/* [RFC-0105] Canonical SiteBackgroundConfig — global viewport background shell block, independent of section-level SectionBackground. Do not introduce app-specific runtime composition or deployment behavior into this reusable package source file. RFC-0133: backfilled MODULE_MAP and CHANGE_SUMMARY markers for compass.validate compliance. RFC-1175: image layer gains explicit fetchpriority — loading no longer implies priority, so an eager decorative background stops competing with the LCP image. RFC-1175: close Lighthouse gaps — directive-allowlist robots (Schemamap retired, ROBOTS-SURFACE-01), capability-gated video (preload=none, data-bg-video, saveData/reduced-motion), single fetchpriority=high per page (IMG-DELIVERY-05), inlined shared texture token, 24px QR touch targets; RFC-1177 security-headers draft */ import { z } from "zod"; const colorLayer = z .object({ kind: z.literal("color"), color: z.string().min(1).optional(), }) .strict(); const imageLayer = z .object({ kind: z.literal("image"), imageName: z.string().min(1), fit: z.enum(["cover", "tile", "stretch-width", "stretch-height"]).optional(), quality: z.enum(["low", "mid", "high", "max"]).optional(), loading: z.enum(["eager", "lazy"]).optional(), /** RFC-1175: explicit fetch priority — decoupled from `loading` so an eager * decorative layer no longer auto-promotes to fetchpriority="high". */ fetchpriority: z.enum(["high", "low", "auto"]).optional(), tint: z .object({ color: z.string().min(1).optional(), opacity: z.number().min(0).max(1).optional(), }) .strict() .optional(), parallax: z .object({ speed: z.number().min(0).max(2).optional(), respectReducedMotion: z.boolean().optional(), }) .strict() .optional(), }) .strict(); const gradientStop = z .object({ at: z.number().min(0).max(1), color: z.string().min(1), opacity: z.number().min(0).max(1).optional(), }) .strict(); const gradientLayer = z .object({ kind: z.literal("gradient"), direction: z.enum(["vertical", "horizontal", "radial"]), stops: z.array(gradientStop).min(2), }) .strict(); export const siteBackgroundLayerSchema = z.discriminatedUnion("kind", [ colorLayer, imageLayer, gradientLayer, ]); export type SiteBackgroundLayer = z.infer; export const siteBackgroundConfigSchema = z .object({ layers: z.array(siteBackgroundLayerSchema).min(1), lang: z.string().optional(), }) .strict(); export type SiteBackgroundConfig = z.infer;