@bison-lab/payload-core 3.10.0 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"admin.mjs","names":["CSS","CSS","CSS","CSS"],"sources":["../src/admin/color-field.tsx","../src/theme/appearance-labels.ts","../src/theme/readability.ts","../src/admin/preview-mode.tsx","../src/admin/readability-list.tsx","../src/admin/color-scale-card.tsx","../src/admin/color-scale-field.tsx","../src/theme/types.ts","../src/theme/library.ts","../src/admin/library-field.tsx","../src/admin/typography-pairing.tsx","../src/admin/font-field.tsx","../src/admin/pairing-field.tsx","../src/admin/appearance-choices.tsx","../src/admin/appearance-field.tsx","../src/admin/grey-scale-field.tsx","../src/admin/contrast-report.tsx","../src/admin/section-heading.tsx","../src/theme/changes.ts","../src/theme/publish.ts","../src/admin/publish-confirm.tsx","../src/admin/theme-tab.ts","../src/admin/publish-child.tsx","../src/admin/save-button.tsx","../src/admin/identity-fallback.tsx"],"sourcesContent":["import { FieldDescription, FieldError, FieldLabel, useField } from \"@payloadcms/ui\";\nimport { isThemeHex } from \"@bison-lab/tokens\";\nimport type { TextFieldClientComponent } from \"payload\";\nimport { useEffect, useId, useState } from \"react\";\n\nconst HEX_ERROR = \"Enter a six-digit hex colour like #1e3a5f\";\n\n/**\n * Swatch, native colour input, and hex text, kept in step. `#rrggbb` on\n * blur; the field's `validate` refuses anything else on save.\n */\nexport const ColorField: TextFieldClientComponent = ({ field, path, readOnly }) => {\n const { value, setValue, showError, errorMessage } = useField<string>({ path });\n const [text, setText] = useState(value ?? \"\");\n const [localError, setLocalError] = useState<string | null>(null);\n const id = useId();\n const hexId = `${id}-hex`;\n const pickerId = `${id}-picker`;\n const required = Boolean(field.required);\n const valid = isThemeHex(value);\n const message = localError ?? errorMessage;\n const show = Boolean(localError) || showError;\n\n useEffect(() => {\n setText(value ?? \"\");\n }, [value]);\n\n function commit(next: string) {\n const trimmed = next.trim();\n if (isThemeHex(trimmed)) {\n setValue(trimmed);\n setLocalError(null);\n return;\n }\n setLocalError(HEX_ERROR);\n }\n\n return (\n <div className=\"field-type bl-color-field\">\n <style href=\"bl-color-field\" precedence=\"default\">\n {CSS}\n </style>\n <FieldLabel htmlFor={hexId} label={field.label} required={required} />\n <div className=\"bl-color-field__control\">\n <span\n className=\"bl-color-field__swatch\"\n aria-hidden=\"true\"\n style={{ background: valid ? value : \"transparent\" }}\n />\n <input\n id={pickerId}\n type=\"color\"\n className=\"bl-color-field__picker\"\n disabled={readOnly}\n value={valid ? value : \"#000000\"}\n aria-label={`${typeof field.label === \"string\" ? field.label : \"Colour\"} picker`}\n onChange={(event) => {\n setValue(event.target.value);\n setText(event.target.value);\n setLocalError(null);\n }}\n />\n <input\n id={hexId}\n type=\"text\"\n className=\"bl-color-field__hex\"\n spellCheck={false}\n autoComplete=\"off\"\n disabled={readOnly}\n value={text}\n onChange={(event) => {\n setText(event.target.value);\n if (isThemeHex(event.target.value.trim())) {\n setValue(event.target.value.trim());\n setLocalError(null);\n }\n }}\n onBlur={() => commit(text)}\n />\n </div>\n <FieldDescription description={field.admin?.description} path={path} />\n <FieldError path={path} showError={show} message={message} />\n </div>\n );\n};\n\nconst CSS = `\n.bl-color-field__control{display:flex;align-items:center;gap:calc(var(--base) * .4)}\n.bl-color-field__swatch{flex:none;width:calc(var(--base) * 1.6);height:calc(var(--base) * 1.6);border:1px solid var(--theme-elevation-150);border-radius:var(--style-radius-s);background:var(--theme-elevation-50)}\n.bl-color-field__picker{flex:none;width:calc(var(--base) * 2);height:calc(var(--base) * 2);padding:0;border:1px solid var(--theme-elevation-150);border-radius:var(--style-radius-s);background:transparent;cursor:pointer}\n.bl-color-field__picker:disabled{cursor:not-allowed;opacity:.6}\n.bl-color-field__hex{flex:1;min-width:0;min-height:calc(var(--base) * 2);padding:calc(var(--base) * .25) calc(var(--base) * .6);border:1px solid var(--theme-elevation-150);border-radius:var(--style-radius-s);background:var(--theme-input-bg);color:var(--theme-elevation-800);font-family:var(--font-mono);font-size:13px}\n.bl-color-field__hex:focus{border-color:var(--theme-elevation-400);outline:none;box-shadow:0 0 0 1px var(--theme-elevation-400)}\n.bl-color-field__hex:disabled{color:var(--theme-elevation-400)}\n`;\n","/**\n * Named choices the Appearance child shows. Values stay the token presets;\n * labels match the mock workflow (Soft → pill, Gentle → minimal, Balanced\n * → default, Follow device → system). No rem, ms, or CSS variable tables.\n */\nexport const APPEARANCE_CHOICES = {\n defaultTheme: {\n light: { label: \"Light\", hint: \"Always opens in light mode\" },\n dark: { label: \"Dark\", hint: \"Always opens in dark mode\" },\n system: { label: \"Follow device\", hint: \"Matches the visitor’s system setting\" },\n },\n radius: {\n sharp: { label: \"Sharp\", hint: \"Crisp and structured\" },\n subtle: { label: \"Subtle\", hint: \"Clean with a little softness\" },\n rounded: { label: \"Rounded\", hint: \"Friendly and contemporary\" },\n pill: { label: \"Soft\", hint: \"Very rounded and expressive\" },\n },\n shadow: {\n flat: { label: \"Flat\", hint: \"Minimal visual depth\" },\n subtle: { label: \"Subtle\", hint: \"Light separation between surfaces\" },\n elevated: { label: \"Elevated\", hint: \"More noticeable layering and depth\" },\n },\n motion: {\n snappy: { label: \"Quick\", hint: \"Fast and responsive\" },\n smooth: { label: \"Smooth\", hint: \"Balanced and natural\" },\n minimal: { label: \"Gentle\", hint: \"Slower and more relaxed\" },\n },\n density: {\n compact: { label: \"Compact\", hint: \"Fits more content on screen\" },\n default: { label: \"Balanced\", hint: \"Comfortable for most sites\" },\n spacious: { label: \"Spacious\", hint: \"More breathing room and larger controls\" },\n },\n} as const;\n\nexport const APPEARANCE_FAMILY_COPY: Record<\n keyof typeof APPEARANCE_CHOICES,\n { title: string; hint: string }\n> = {\n defaultTheme: {\n title: \"Default theme\",\n hint: \"Choose how the public site opens for visitors.\",\n },\n radius: {\n title: \"Corner style\",\n hint: \"Controls the shape of buttons, inputs, cards, and panels across the site.\",\n },\n shadow: {\n title: \"Depth\",\n hint: \"Choose how much cards and floating elements stand out from the page.\",\n },\n motion: {\n title: \"Motion\",\n hint: \"Controls how quickly menus, cards, and interface transitions move.\",\n },\n density: {\n title: \"Spacing\",\n hint: \"Choose how compact or roomy forms, buttons, cards, and page sections feel.\",\n },\n};\n\nexport const FONT_ROLE_COPY = {\n heading: {\n label: \"Heading font\",\n hint: \"Used for page titles, section headings, and cards\",\n },\n body: {\n label: \"Body font\",\n hint: \"Used for paragraphs, navigation, forms, and buttons\",\n },\n} as const;\n\nexport const SYSTEM_COLOR_COPY: Record<\n \"primary\" | \"secondary\" | \"accent\" | \"highlight\" | \"success\" | \"destructive\",\n { label: string; hint: string; group: \"brand\" | \"status\" }\n> = {\n primary: { label: \"Primary\", hint: \"Primary actions and key links\", group: \"brand\" },\n secondary: { label: \"Secondary\", hint: \"Supporting accents and eyebrows\", group: \"brand\" },\n accent: { label: \"Accent\", hint: \"Dark brand surfaces\", group: \"brand\" },\n highlight: { label: \"Highlight\", hint: \"Promotional and emphasis fills\", group: \"brand\" },\n success: {\n label: \"Success\",\n hint: \"Theme chrome for confirmations. Not offered as a page-editor fill.\",\n group: \"status\",\n },\n destructive: {\n label: \"Destructive\",\n hint: \"Theme chrome for errors and dangerous actions. Not offered as a page-editor fill.\",\n group: \"status\",\n },\n};\n","import {\n contrastForeground,\n contrastRatio,\n hexToHSL,\n hslToString,\n isThemeHex,\n type HSL,\n} from \"@bison-lab/tokens\";\n\n/** Same threshold `deriveDarkPalette` uses for brand fills. */\nconst DARK_FILL_LIGHTEN_BELOW = 40;\nconst DARK_FILL_LIGHTEN_BY = 25;\n\nexport const READABILITY_TARGET = 7;\n\nexport interface FillLabelSample {\n ratio: number;\n shortfall: number;\n fill: string;\n label: string;\n}\n\nexport interface FillLabelWarning {\n id: string;\n name: string;\n light: FillLabelSample;\n dark: FillLabelSample;\n /** Both modes at or above the target. */\n meets: boolean;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\nfunction darkFill(color: HSL): HSL {\n if (color.l < DARK_FILL_LIGHTEN_BELOW) {\n return { ...color, l: clamp(color.l + DARK_FILL_LIGHTEN_BY, 0, 100) };\n }\n return color;\n}\n\nfunction sample(fill: HSL, target: number): FillLabelSample {\n const label = contrastForeground(fill);\n const fillCss = hslToString(fill);\n const ratio = contrastRatio(fillCss, label);\n return {\n ratio,\n shortfall: Math.max(0, Math.round((target - ratio) * 100) / 100),\n fill: fillCss,\n label,\n };\n}\n\n/**\n * Editable fill + the automatic label, Light and Dark. Target 7:1.\n * Meets only when both pass. Warnings do not block save.\n */\nexport function fillLabelWarning(\n id: string,\n name: string,\n hex: string,\n target = READABILITY_TARGET,\n): FillLabelWarning | null {\n if (!isThemeHex(hex)) return null;\n const lightFill = hexToHSL(hex);\n const light = sample(lightFill, target);\n const dark = sample(darkFill(lightFill), target);\n return { id, name, light, dark, meets: light.ratio >= target && dark.ratio >= target };\n}\n\n/** Green/teal family. A warning at admin time, not a schema block. */\nexport function successHueWarning(hex: string): string | null {\n if (!isThemeHex(hex)) return null;\n const { h } = hexToHSL(hex);\n if (h >= 80 && h <= 180) return null;\n return \"Keep success colors recognizable — stay in a green or teal family.\";\n}\n\n/** Red family. A warning at admin time, not a schema block. */\nexport function destructiveHueWarning(hex: string): string | null {\n if (!isThemeHex(hex)) return null;\n const { h } = hexToHSL(hex);\n if (h <= 30 || h >= 330) return null;\n return \"Keep destructive colors recognizable — stay in a red family.\";\n}\n\nexport function automaticLabel(hex: string): string | null {\n if (!isThemeHex(hex)) return null;\n return contrastForeground(hexToHSL(hex));\n}\n\nexport function hslCss(value: string): string {\n return `hsl(${value})`;\n}\n\n/** Which appearances fail, in words. Empty when both pass. */\nexport function hardToReadModes(item: FillLabelWarning): string {\n const light = item.light.shortfall > 0;\n const dark = item.dark.shortfall > 0;\n if (light && dark) return \"in Light and Dark\";\n if (light) return \"in Light\";\n if (dark) return \"in Dark\";\n return \"\";\n}\n\nexport function readabilityHeadline(item: FillLabelWarning): string {\n return item.meets ? `Text on ${item.name} looks readable` : `Text on ${item.name} may be hard to read`;\n}\n\nexport function readabilityModesLine(item: FillLabelWarning): string {\n const modes = hardToReadModes(item);\n return modes ? `Hard to read ${modes}.` : \"Looks good in Light and Dark.\";\n}\n\nexport function readabilityGapPercent(sample: FillLabelSample, target = READABILITY_TARGET): number {\n if (sample.shortfall <= 0) return 0;\n return Math.round((sample.shortfall / target) * 100);\n}\n\nexport function readabilityRatioLine(sample: FillLabelSample, target = READABILITY_TARGET): string {\n const percent = readabilityGapPercent(sample, target);\n if (percent <= 0) return \"Meets the contrast we want\";\n if (percent < 10) return \"A little short of the contrast we want\";\n return `About ${percent}% short of the contrast we want`;\n}\n\nexport const READABILITY_FIX =\n \"Darken or lighten the hex, then regenerate the scale. The site picks light or dark type for you.\";\n\nexport const READABILITY_PUBLISH_NOTE =\n \"You can still publish. To improve a color, darken or lighten it and regenerate.\";\n","import { useEffect, useState } from \"react\";\n\nexport type ThemePreviewMode = \"light\" | \"dark\";\n\nconst ATTR = \"data-bl-theme-preview\";\nconst EVENT = \"bl-theme-preview\";\n\nfunction adminIsDark(): boolean {\n if (typeof document === \"undefined\") return false;\n const root = document.documentElement;\n return (\n root.getAttribute(\"data-theme\") === \"dark\" ||\n root.getAttribute(\"data-theme-pref\") === \"dark\" ||\n root.classList.contains(\"dark\")\n );\n}\n\nfunction readMode(): ThemePreviewMode {\n if (typeof document === \"undefined\") return \"light\";\n const set = document.documentElement.getAttribute(ATTR);\n if (set === \"dark\" || set === \"light\") return set;\n return adminIsDark() ? \"dark\" : \"light\";\n}\n\nexport function setThemePreviewMode(mode: ThemePreviewMode) {\n if (typeof document === \"undefined\") return;\n document.documentElement.setAttribute(ATTR, mode);\n window.dispatchEvent(new Event(EVENT));\n}\n\nexport function useThemePreviewMode(): ThemePreviewMode {\n // Always start on light so SSR and the first client paint match.\n // Admin dark is applied after mount — reading `document` here hydrates\n // `data-on` as \"\" on the server and undefined in the browser.\n const [mode, setMode] = useState<ThemePreviewMode>(\"light\");\n useEffect(() => {\n const sync = () => setMode(readMode());\n sync();\n window.addEventListener(EVENT, sync);\n return () => window.removeEventListener(EVENT, sync);\n }, []);\n return mode;\n}\n\nexport function ThemePreviewToggle() {\n const mode = useThemePreviewMode();\n return (\n <div className=\"bl-preview-toggle\" role=\"group\" aria-label=\"Preview fills in\">\n <span className=\"bl-preview-toggle__label\">Preview fills</span>\n <div className=\"bl-preview-toggle__pills\">\n <button type=\"button\" aria-pressed={mode === \"light\"} onClick={() => setThemePreviewMode(\"light\")}>\n Light\n </button>\n <button type=\"button\" aria-pressed={mode === \"dark\"} onClick={() => setThemePreviewMode(\"dark\")}>\n Dark\n </button>\n </div>\n </div>\n );\n}\n\nexport const THEME_PREVIEW_TOGGLE_CSS = `\n.bl-preview-toggle{display:inline-flex;align-items:center;gap:.6rem}\n.bl-preview-toggle__label{font-size:12px;font-weight:600;color:#a1a1aa}\n.bl-preview-toggle__pills{display:inline-flex;padding:3px;border:1px solid #3f3f46;border-radius:10px;background:#18181b}\n.bl-preview-toggle__pills button{min-height:2rem;padding:.25rem .8rem;border:0;border-radius:7px;background:transparent;color:#d4d4d8;font:inherit;font-size:13px;font-weight:600;cursor:pointer}\n.bl-preview-toggle__pills button[aria-pressed=true]{background:#f4f4f5;color:#18181b;box-shadow:0 1px 2px rgba(0,0,0,.25)}\nhtml[data-theme=light] .bl-preview-toggle__label{color:#52525b}\nhtml[data-theme=light] .bl-preview-toggle__pills{border-color:#d4d4d8;background:#e4e4e7}\nhtml[data-theme=light] .bl-preview-toggle__pills button{color:#3f3f46}\nhtml[data-theme=light] .bl-preview-toggle__pills button[aria-pressed=true]{background:#fff;color:#18181b;box-shadow:0 1px 2px rgba(15,23,42,.12)}\n`;\n","import type { FillLabelWarning } from \"../theme/readability\";\nimport {\n hslCss,\n READABILITY_FIX,\n READABILITY_TARGET,\n readabilityHeadline,\n readabilityModesLine,\n readabilityRatioLine,\n} from \"../theme/readability\";\n\nexport function ReadabilityDetail({\n item,\n target = READABILITY_TARGET,\n}: {\n item: FillLabelWarning;\n target?: number;\n}) {\n return (\n <div className=\"bl-readability-detail\">\n <p className=\"bl-readability-detail__lead\">{readabilityModesLine(item)}</p>\n <div className=\"bl-readability-detail__modes\">\n {(\n [\n [\"Light\", item.light],\n [\"Dark\", item.dark],\n ] as const\n ).map(([mode, sample]) => (\n <figure key={mode} data-failing={sample.shortfall > 0 ? \"\" : undefined}>\n <span\n aria-hidden=\"true\"\n className=\"bl-readability__swatch\"\n style={{ background: hslCss(sample.fill), color: hslCss(sample.label) }}\n >\n Aa\n </span>\n <figcaption>\n <strong>{mode}</strong>\n <span>{sample.shortfall > 0 ? \"Hard to read\" : \"Looks good\"}</span>\n <span>{readabilityRatioLine(sample, target)}</span>\n </figcaption>\n </figure>\n ))}\n </div>\n {item.meets ? null : <p className=\"bl-readability-detail__fix\">{READABILITY_FIX}</p>}\n </div>\n );\n}\n\nexport function ReadabilityList({\n warnings,\n target = READABILITY_TARGET,\n}: {\n warnings: FillLabelWarning[];\n target?: number;\n}) {\n const failing = warnings.filter((item) => !item.meets).length;\n return (\n <aside className=\"bl-readability\">\n <div className=\"bl-readability__head\">\n <div>\n <h2>Readability checks</h2>\n <p>Text the site puts on each fill. Warnings do not block save.</p>\n </div>\n <span data-attention={failing ? \"\" : undefined}>\n {failing === 0 ? \"All look readable\" : `${failing} may be hard to read`}\n </span>\n </div>\n <ul>\n {warnings.map((item) => (\n <li key={item.id} data-failing={item.meets ? undefined : \"\"}>\n <strong>{readabilityHeadline(item)}</strong>\n <ReadabilityDetail item={item} target={target} />\n </li>\n ))}\n </ul>\n </aside>\n );\n}\n\nexport const READABILITY_LIST_CSS = `\n.bl-readability{padding:calc(var(--base,16px) * .8);border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:var(--style-radius-m,12px);background:var(--theme-elevation-0,#fff)}\n.bl-readability__head{display:flex;justify-content:space-between;gap:1rem;align-items:flex-start}\n.bl-readability__head h2{margin:0;font-size:1rem}\n.bl-readability__head p{margin:.35rem 0 0;font-size:12px;color:var(--theme-elevation-500,#64748b)}\n.bl-readability__head span{flex:none;font-size:12px;font-weight:600;padding:.2rem .55rem;border-radius:999px;background:var(--theme-elevation-100,#f1f5f9)}\n.bl-readability__head span[data-attention]{background:#fffbeb;color:#92400e}\n.bl-readability ul{margin:.85rem 0 0;padding:0;list-style:none}\n.bl-readability li{padding:.65rem 0;border-top:1px solid var(--theme-elevation-100,#f1f5f9)}\n.bl-readability li:first-child{border-top:0}\n.bl-readability li[data-failing]{background:#fff7ed;margin:0 -.4rem;padding:.65rem .4rem;border-radius:8px}\n.bl-readability__swatch{flex:none;display:inline-flex;align-items:center;justify-content:center;width:2.75rem;height:2rem;border-radius:6px;font-weight:700;font-size:13px}\n.bl-readability strong{display:block;font-size:13px}\n.bl-readability-detail__lead{margin:0 0 .65rem;font-size:13px;color:var(--theme-elevation-600,#475569)}\n.bl-readability-detail__modes{display:grid;grid-template-columns:1fr 1fr;gap:.65rem}\n.bl-readability-detail__modes figure{display:flex;gap:.6rem;align-items:center;margin:0;padding:.55rem .6rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:10px;background:#fff}\n.bl-readability-detail__modes figure[data-failing]{border-color:#fdba74;background:#fff7ed}\n.bl-readability-detail__modes figcaption{display:flex;flex-direction:column;gap:.1rem;min-width:0}\n.bl-readability-detail__modes figcaption strong{font-size:12px}\n.bl-readability-detail__modes figcaption span{font-size:11px;color:var(--theme-elevation-500,#64748b)}\n.bl-readability-detail__fix{margin:.7rem 0 0;font-size:13px;color:var(--theme-elevation-600,#475569)}\n`;\n","import {\n includedShadeSteps,\n regenerateColorScale,\n setColorScaleInclude,\n SHADE_STEPS,\n updateColorScale,\n type ColorScaleState,\n type ShadeStep,\n} from \"@bison-lab/tokens\";\nimport { useId, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport {\n automaticLabel,\n fillLabelWarning,\n hslCss,\n readabilityHeadline,\n successHueWarning,\n destructiveHueWarning,\n} from \"../theme/readability\";\nimport { useThemePreviewMode } from \"./preview-mode\";\nimport { ReadabilityDetail, READABILITY_LIST_CSS } from \"./readability-list\";\n\nexport interface ColorScaleCardProps {\n id?: string;\n name: string;\n hint?: string;\n required?: boolean;\n custom?: boolean;\n state: ColorScaleState;\n onChange: (next: ColorScaleState) => void;\n onDelete?: () => void;\n readOnly?: boolean;\n role?: \"success\" | \"destructive\" | null;\n}\n\nexport function ColorScaleCard({\n id,\n name,\n hint,\n required,\n custom,\n state,\n onChange,\n onDelete,\n readOnly,\n role,\n}: ColorScaleCardProps) {\n const label = automaticLabel(state.hex);\n const warning = fillLabelWarning(id ?? name.toLowerCase(), name, state.hex);\n const previewMode = useThemePreviewMode();\n const preview = warning ? (previewMode === \"dark\" ? warning.dark : warning.light) : null;\n const [open, setOpen] = useState(false);\n const titleId = useId();\n const hueWarning =\n role === \"success\" ? successHueWarning(state.hex) : role === \"destructive\" ? destructiveHueWarning(state.hex) : null;\n const included = new Set(includedShadeSteps(state));\n\n function setHex(hex: string) {\n onChange(updateColorScale(state, { hex }));\n }\n\n function setStep(step: ShadeStep) {\n onChange(updateColorScale(state, { sourceStep: step }));\n }\n\n function toggleStep(step: ShadeStep) {\n if (step === state.sourceStep) return;\n const next = new Set(included);\n if (next.has(step)) next.delete(step);\n else next.add(step);\n onChange(setColorScaleInclude(state, SHADE_STEPS.filter((item) => next.has(item))));\n }\n\n return (\n <article className=\"bl-scale-card\" data-preview={previewMode}>\n <header className=\"bl-scale-card__head\">\n <div>\n <div className=\"bl-scale-card__title-row\">\n <h3 className=\"bl-scale-card__title\">{name}</h3>\n {required ? <span className=\"bl-scale-card__badge\">Required</span> : null}\n {custom ? <span className=\"bl-scale-card__badge\">Optional</span> : null}\n {warning ? (\n warning.meets ? (\n <span className=\"bl-scale-card__status\" data-ok=\"\" title={`Text on ${name} looks readable`}>\n <span aria-hidden=\"true\">✓</span>\n <span className=\"bl-scale-card__sr\">Text on {name} looks readable</span>\n </span>\n ) : (\n <button\n type=\"button\"\n className=\"bl-scale-card__badge bl-scale-card__badge--attention\"\n aria-haspopup=\"dialog\"\n onClick={() => setOpen(true)}\n >\n Needs attention\n </button>\n )\n ) : null}\n </div>\n {hint ? <p className=\"bl-scale-card__hint\">{hint}</p> : null}\n </div>\n <div className=\"bl-scale-card__head-actions\">\n <span className=\"bl-scale-card__mark\" style={{ background: state.hex }} aria-hidden=\"true\" />\n {onDelete ? (\n <button type=\"button\" className=\"bl-scale-card__delete\" disabled={readOnly} onClick={onDelete}>\n Delete\n </button>\n ) : null}\n </div>\n </header>\n\n <div className=\"bl-scale-card__row\">\n <label className=\"bl-scale-card__field\">\n <span>Brand hex</span>\n <span className=\"bl-scale-card__hex-wrap\">\n <input\n type=\"color\"\n aria-label={`${name} picker`}\n disabled={readOnly}\n value={state.hex}\n onChange={(event) => setHex(event.target.value)}\n />\n <input\n type=\"text\"\n spellCheck={false}\n autoComplete=\"off\"\n disabled={readOnly}\n value={state.hex}\n onChange={(event) => {\n const next = event.target.value.trim();\n if (next) setHex(next);\n }}\n />\n </span>\n </label>\n <label className=\"bl-scale-card__field\">\n <span>This color is</span>\n <select\n disabled={readOnly}\n value={String(state.sourceStep)}\n onChange={(event) => setStep(Number(event.target.value) as ShadeStep)}\n >\n {SHADE_STEPS.map((step) => (\n <option key={step} value={step}>\n {step}\n </option>\n ))}\n </select>\n </label>\n </div>\n\n <div className=\"bl-scale-card__label-sample\">\n <span\n className=\"bl-scale-card__swatch\"\n style={{\n background: preview ? hslCss(preview.fill) : state.hex,\n color: preview ? hslCss(preview.label) : label ? hslCss(label) : undefined,\n }}\n >\n Aa\n </span>\n <p>\n {previewMode === \"dark\"\n ? \"Previewing this fill in Dark. A dark-enough hex lightens; otherwise it stays the typed color.\"\n : \"The site chooses light or dark type on this fill. Darken or lighten the hex and regenerate to flip it. There is no ink picker.\"}\n </p>\n </div>\n\n {hueWarning ? <p className=\"bl-scale-card__warn\">{hueWarning}</p> : null}\n\n {state.stale ? (\n <p className=\"bl-scale-card__stale\">This scale is out of date. Regenerate to rebuild 50–950 around the hex.</p>\n ) : null}\n\n <button\n type=\"button\"\n className=\"bl-scale-card__regen\"\n disabled={readOnly || !state.stale}\n onClick={() => onChange(regenerateColorScale(state))}\n >\n Regenerate scale\n </button>\n\n <div className=\"bl-scale-card__scale-head\">\n <span>Generated scale</span>\n <span>\n <button type=\"button\" disabled={readOnly} onClick={() => onChange(setColorScaleInclude(state, \"all\"))}>\n Include all\n </button>\n {\" · \"}\n <button type=\"button\" disabled={readOnly} onClick={() => onChange(setColorScaleInclude(state, \"source\"))}>\n Source only\n </button>\n </span>\n </div>\n <div className=\"bl-scale-card__steps\" role=\"group\" aria-label={`${name} scale steps`}>\n {SHADE_STEPS.map((step) => {\n const source = step === state.sourceStep;\n const on = included.has(step);\n return (\n <button\n key={step}\n type=\"button\"\n className=\"bl-scale-card__step\"\n data-source={source ? \"\" : undefined}\n data-excluded={on ? undefined : \"\"}\n disabled={readOnly || source}\n title={\n source\n ? `Source step ${step} cannot be excluded`\n : on\n ? `Exclude ${step} from page editors`\n : `Include ${step} for page editors`\n }\n onClick={() => toggleStep(step)}\n >\n <span className=\"bl-scale-card__chip\" style={{ background: hslCss(state.scale[step]) }}>\n {source ? null : (\n <span\n className=\"bl-scale-card__intent\"\n data-intent={on ? \"exclude\" : \"include\"}\n aria-hidden=\"true\"\n >\n {on ? (\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\">\n <circle cx=\"12\" cy=\"12\" r=\"8\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.4\" />\n <path d=\"M7.2 16.8 16.8 7.2\" stroke=\"currentColor\" strokeWidth=\"2.4\" />\n </svg>\n ) : (\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\">\n <path d=\"M12 6v12M6 12h12\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.6\" />\n </svg>\n )}\n </span>\n )}\n </span>\n <span className=\"bl-scale-card__step-label\">{step}</span>\n </button>\n );\n })}\n </div>\n {open && warning\n ? createPortal(\n <div\n className=\"bl-scale-card__modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n onClick={(event) => {\n if (event.target === event.currentTarget) setOpen(false);\n }}\n >\n <div className=\"bl-scale-card__panel\">\n <div className=\"bl-scale-card__panel-head\">\n <h4 id={titleId}>{readabilityHeadline(warning)}</h4>\n <button type=\"button\" onClick={() => setOpen(false)} aria-label=\"Close\">\n ×\n </button>\n </div>\n <ReadabilityDetail item={warning} />\n <button type=\"button\" className=\"bl-scale-card__panel-done\" onClick={() => setOpen(false)}>\n Keep editing this color\n </button>\n </div>\n </div>,\n document.body,\n )\n : null}\n </article>\n );\n}\n\nexport const COLOR_SCALE_CARD_CSS = `\n.bl-scale-card{padding:calc(var(--base,16px) * .8);border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:var(--style-radius-m,12px);background:var(--theme-elevation-0,#fff)}\n.bl-scale-card__head{display:flex;justify-content:space-between;gap:1rem;align-items:flex-start}\n.bl-scale-card__title-row{position:relative;display:flex;align-items:center;flex-wrap:wrap;gap:.5rem}\n.bl-scale-card__title{margin:0;font-size:1rem}\n.bl-scale-card__badge{font:inherit;font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:.15rem .45rem;border-radius:999px;border:0;background:var(--theme-elevation-100,#f1f5f9);color:var(--theme-elevation-500,#64748b)}\n.bl-scale-card__badge--attention{background:#fff1f2;color:#be123c;cursor:pointer}\n.bl-scale-card__status{display:inline-grid;place-items:center;width:1.4rem;height:1.4rem;border-radius:999px;border:0;font:inherit;font-weight:700;line-height:1}\n.bl-scale-card__status[data-ok]{background:#ecfdf5;color:#047857}\n.bl-scale-card__sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n.bl-scale-card__hint{margin:.35rem 0 0;color:var(--theme-elevation-500,#64748b);font-size:12px}\n.bl-scale-card__head-actions{display:flex;align-items:center;gap:.5rem}\n.bl-scale-card__mark{display:block;width:2.5rem;height:2.5rem;border-radius:8px;border:1px solid rgba(15,23,42,.12);flex:none}\n.bl-scale-card__delete{border:0;background:none;color:#be123c;font:inherit;font-size:13px;font-weight:600;cursor:pointer}\n.bl-scale-card__row{display:grid;grid-template-columns:1fr 8rem;gap:.75rem;margin-top:1rem}\n.bl-scale-card__field{display:flex;flex-direction:column;gap:.35rem;font-size:12px;font-weight:600;color:var(--theme-elevation-600,#475569)}\n.bl-scale-card__hex-wrap{display:flex;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:8px;overflow:hidden;background:var(--theme-input-bg,#fff)}\n.bl-scale-card__hex-wrap input[type=color]{width:2.75rem;height:2.25rem;padding:0;border:0;border-right:1px solid var(--theme-elevation-150,#e2e8f0);background:transparent;cursor:pointer}\n.bl-scale-card__hex-wrap input[type=text]{flex:1;min-width:0;border:0;padding:.4rem .7rem;font-family:var(--font-mono,ui-monospace,monospace);font-size:13px;background:transparent;color:inherit}\n.bl-scale-card__field select{min-height:2.25rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:8px;padding:.35rem .5rem;background:var(--theme-input-bg,#fff);color:inherit}\n.bl-scale-card__label-sample{display:flex;gap:.75rem;align-items:center;margin-top:1rem}\n.bl-scale-card__swatch{flex:none;display:inline-flex;align-items:center;justify-content:center;width:3rem;height:2.25rem;border-radius:8px;border:1px solid var(--theme-elevation-150,#e2e8f0);font-weight:700}\n.bl-scale-card__label-sample p{margin:0;font-size:12px;color:var(--theme-elevation-500,#64748b)}\n.bl-scale-card__warn,.bl-scale-card__stale{margin:.75rem 0 0;padding:.65rem .75rem;border-radius:8px;font-size:12px}\n.bl-scale-card__warn{border:1px solid #a7f3d0;background:#ecfdf5;color:#065f46}\n.bl-scale-card__stale{border:1px solid #fde68a;background:#fffbeb;color:#92400e}\n.bl-scale-card__regen{width:100%;margin-top:.85rem;min-height:2.25rem;border:0;border-radius:8px;background:#0f172a;color:#fff;font:inherit;font-weight:600;cursor:pointer}\n.bl-scale-card__regen:disabled{background:#1e293b;color:#f8fafc;opacity:1;cursor:not-allowed}\n.bl-scale-card__scale-head{display:flex;justify-content:space-between;margin:1rem 0 .4rem;font-size:12px;color:var(--theme-elevation-500,#64748b)}\n.bl-scale-card__scale-head button{border:0;background:none;padding:0;font:inherit;color:inherit;text-decoration:underline;cursor:pointer}\n.bl-scale-card__steps{display:grid;grid-template-columns:repeat(11,minmax(0,1fr));gap:.45rem 3px}\n.bl-scale-card__step{display:flex;flex-direction:column;align-items:center;gap:.3rem;border:0;padding:0;background:transparent;cursor:pointer}\n.bl-scale-card__chip{position:relative;display:block;width:100%;height:2.15rem;border-radius:6px;overflow:hidden}\n.bl-scale-card__intent{position:absolute;top:3px;right:3px;width:1.15rem;height:1.15rem;border-radius:999px;display:grid;place-items:center;opacity:0;color:#be123c;background:#fff;box-shadow:0 1px 3px rgba(15,23,42,.28);transition:opacity .15s ease,transform .15s ease;pointer-events:none}\n.bl-scale-card__intent[data-intent=include]{color:#047857}\n.bl-scale-card__step:hover:not(:disabled) .bl-scale-card__chip{transform:translateY(-1px)}\n.bl-scale-card__step:hover:not(:disabled) .bl-scale-card__intent{opacity:1}\n.bl-scale-card__step-label{font-size:10px;line-height:1;color:var(--theme-elevation-600,#475569)}\n.bl-scale-card__step[data-source] .bl-scale-card__chip{box-shadow:0 0 0 2px var(--theme-elevation-800,#0f172a)}\n.bl-scale-card__step[data-excluded]{opacity:.55}\n.bl-scale-card__step:disabled{cursor:default}\n.bl-scale-card__modal{position:fixed;inset:0;z-index:100000;display:grid;place-items:center;padding:1rem;background:rgba(15,23,42,.45)}\n.bl-scale-card__panel{width:min(32rem,100%);padding:1.15rem 1.2rem;border-radius:16px;background:#fff;color:#0f172a}\n.bl-scale-card__panel-head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem}\n.bl-scale-card__panel-head h4{margin:0;font-size:1rem}\n.bl-scale-card__panel-head button{border:0;background:none;font:inherit;font-size:1.25rem;line-height:1;color:#64748b;cursor:pointer}\n.bl-scale-card__panel-done{margin-top:1rem;min-height:2.1rem;padding:.35rem .85rem;border:0;border-radius:8px;background:#0f172a;color:#fff;font:inherit;font-weight:600;cursor:pointer}\n` + READABILITY_LIST_CSS;\n","import { useField } from \"@payloadcms/ui\";\nimport { isThemeHex, SHADE_STEPS, type ColorScaleState, type ShadeStep } from \"@bison-lab/tokens\";\nimport type { GroupFieldClientComponent } from \"payload\";\n\nimport { SYSTEM_COLOR_COPY } from \"../theme/appearance-labels\";\nimport { colorDocFromState, stateFromColorDoc } from \"../theme/map\";\nimport { ColorScaleCard, COLOR_SCALE_CARD_CSS } from \"./color-scale-card\";\n\nconst SYSTEM_ROLES = new Set(Object.keys(SYSTEM_COLOR_COPY));\n\n/**\n * One system (or library row) color: hex, source step, regenerate, stale,\n * include/exclude, automatic label. Writes the group's stored fields.\n */\nexport const ColorScaleField: GroupFieldClientComponent = ({ field, path, readOnly }) => {\n const hex = useField<string>({ path: `${path}.hex` });\n const sourceStep = useField<string | number>({ path: `${path}.sourceStep` });\n const scale = useField<ColorScaleState[\"scale\"]>({ path: `${path}.scale` });\n const stale = useField<boolean>({ path: `${path}.stale` });\n const include = useField<string>({ path: `${path}.include` });\n const includedSteps = useField<ShadeStep[]>({ path: `${path}.includedSteps` });\n const key = path.split(\".\").pop() ?? \"\";\n const copy = SYSTEM_ROLES.has(key) ? SYSTEM_COLOR_COPY[key as keyof typeof SYSTEM_COLOR_COPY] : undefined;\n const state = stateFromColorDoc({\n hex: hex.value,\n sourceStep: sourceStep.value as ShadeStep | undefined,\n scale: scale.value,\n stale: stale.value,\n include: include.value === \"source\" || include.value === \"custom\" || include.value === \"all\" ? include.value : \"all\",\n includedSteps: includedSteps.value,\n });\n\n function write(next: ColorScaleState) {\n const doc = colorDocFromState(next);\n hex.setValue(doc.hex);\n sourceStep.setValue(String(doc.sourceStep));\n scale.setValue(doc.scale);\n stale.setValue(doc.stale);\n include.setValue(doc.include);\n includedSteps.setValue(doc.includedSteps ?? (doc.include === \"source\" ? [doc.sourceStep] : [...SHADE_STEPS]));\n }\n\n const label = copy?.label ?? (typeof field.label === \"string\" ? field.label : key);\n\n return (\n <div className=\"field-type bl-scale-field\">\n <style href=\"bl-scale-card\" precedence=\"default\">\n {COLOR_SCALE_CARD_CSS}\n </style>\n <ColorScaleCard\n id={key}\n name={label}\n hint={copy?.hint}\n required={Boolean(copy) || Boolean(\"required\" in field && field.required)}\n state={isThemeHex(state.hex) ? state : { ...state, hex: \"#000000\" }}\n onChange={write}\n readOnly={readOnly}\n role={key === \"success\" || key === \"destructive\" ? key : null}\n />\n </div>\n );\n};\n","import type { Access } from \"payload\";\nimport type { FontEntry } from \"@bison-lab/fonts\";\nimport type { ColorScale, ColorScaleInclude, ShadeStep, ThemeConfig } from \"@bison-lab/tokens\";\n\nimport type { ResolvedThemeIdentity, ThemeIdentityFallback } from \"./identity\";\n\n/**\n * The Theme document a site's generated types will describe. Optional and\n * nullable, no index signature: a generated Global is assignable to this,\n * never the reverse.\n *\n * Legacy flat `brand.*` hexes, `fonts`, and preset fields at the root stay\n * readable so `getPublishedTheme` still maps a pre-BIS-87 row.\n */\nexport interface ThemeColorDoc {\n hex?: string | null;\n sourceStep?: ShadeStep | string | null;\n scale?: ColorScale | null;\n stale?: boolean | null;\n include?: ColorScaleInclude | \"custom\" | null;\n includedSteps?: ShadeStep[] | string[] | null;\n}\n\nexport interface ThemeLibraryColorDoc extends ThemeColorDoc {\n key?: string | null;\n label?: string | null;\n}\n\nexport interface ThemeDoc {\n colors?: {\n brand?: {\n primary?: ThemeColorDoc | string | null;\n secondary?: ThemeColorDoc | string | null;\n accent?: ThemeColorDoc | string | null;\n highlight?: ThemeColorDoc | string | null;\n success?: ThemeColorDoc | string | null;\n destructive?: ThemeColorDoc | string | null;\n } | null;\n library?: ThemeLibraryColorDoc[] | null;\n greyScale?: ThemeConfig[\"greyScale\"] | null;\n } | null;\n typography?: {\n body?: string | null;\n heading?: string | null;\n } | null;\n appearance?: {\n defaultTheme?: ThemeConfig[\"defaultTheme\"] | null;\n radius?: ThemeConfig[\"radius\"] | null;\n shadow?: ThemeConfig[\"shadow\"] | null;\n motion?: ThemeConfig[\"motion\"] | null;\n density?: ThemeConfig[\"density\"] | null;\n } | null;\n /** @deprecated Pre-BIS-87 flat brand hexes. */\n brand?: {\n primary?: ThemeColorDoc | string | null;\n secondary?: ThemeColorDoc | string | null;\n accent?: ThemeColorDoc | string | null;\n highlight?: ThemeColorDoc | string | null;\n success?: ThemeColorDoc | string | null;\n destructive?: ThemeColorDoc | string | null;\n } | null;\n /** @deprecated Pre-BIS-87; now `colors.greyScale`. */\n greyScale?: ThemeConfig[\"greyScale\"] | null;\n /** @deprecated Pre-BIS-87; now `appearance.*`. */\n radius?: ThemeConfig[\"radius\"] | null;\n shadow?: ThemeConfig[\"shadow\"] | null;\n motion?: ThemeConfig[\"motion\"] | null;\n density?: ThemeConfig[\"density\"] | null;\n defaultTheme?: ThemeConfig[\"defaultTheme\"] | null;\n /** @deprecated Pre-BIS-87; now `typography`. */\n fonts?: {\n body?: string | null;\n heading?: string | null;\n } | null;\n logo?: number | string | ThemeUploadDoc | null;\n favicon?: number | string | ThemeUploadDoc | null;\n logoMark?: number | string | ThemeUploadDoc | null;\n}\n\nexport interface ThemeUploadDoc {\n id?: number | string | null;\n url?: string | null;\n alt?: string | null;\n}\n\n/**\n * What an editor can change. `darkSelector` and `fontWeights` stay on the\n * seed — they mean nothing in the admin — and `themeConfigFromDoc` puts\n * them back.\n */\nexport type EditableTheme = Omit<ThemeConfig, \"darkSelector\" | \"fontWeights\">;\n\nexport interface CreateThemeOptions {\n /**\n * Required, no default. Predicates live in each site's `src/platform`\n * until BIS-43; pass `canManageBrand` as `update` (and typically\n * `isAuthenticated` as `read`).\n */\n access: { read: Access; update: Access };\n /** The site's `bison.config.json`. Every field's `defaultValue`, and the fallback `getPublishedTheme` returns. */\n seed: ThemeConfig;\n /**\n * Destructive seed hex. Required unless `seed.brandDestructive` is set.\n * Not a package default — the site names it.\n */\n destructive?: string;\n /** Default: the whole catalogue. */\n fonts?: readonly FontEntry[];\n /** Where the site's `serveFont` route answers, for the picker's specimens. Default `\"/fonts\"`. */\n fontsBaseUrl?: string;\n /** Fill + automatic label target. Default `7`. Warnings never block save. */\n contrastTarget?: number;\n /**\n * @deprecated Theme has no preview pane (SPI-56 canceled). Kept so a\n * site that still passes it does not fail to boot.\n */\n previewPath?: string;\n /**\n * Adds logo, favicon, and mobile-menu mark upload relations when\n * given. Pass `BRAND_ASSETS_SLUG` (or the slug you gave\n * `createBrandAssets`). Identity is a Theme child with its own Publish.\n */\n logo?: { collection: string };\n /**\n * Fallback art when logo, favicon, or mobile-menu mark is empty. The\n * site passes today's files; `--color-primary-mark` is not a Theme field.\n */\n identity?: { fallback?: ThemeIdentityFallback };\n /** Fires from `afterChange` on every save — Theme has no draft mode. */\n onPublish?: (theme: ThemeConfig, doc: ThemeDoc) => void | Promise<void>;\n}\n\nexport interface ThemeHeadOptions {\n fontsBaseUrl?: string;\n attribute?: \"class\" | \"data-theme\";\n identity?: ResolvedThemeIdentity;\n}\n\nexport interface ThemeHead {\n css: string;\n preloads: { href: string; type: \"font/woff2\" }[];\n identity?: ResolvedThemeIdentity;\n}\n\nexport const THEME_SLUG = \"theme\";\n\nexport const SYSTEM_COLOR_KEYS = [\n \"primary\",\n \"secondary\",\n \"accent\",\n \"highlight\",\n \"success\",\n \"destructive\",\n] as const;\n\nexport type SystemColorKey = (typeof SYSTEM_COLOR_KEYS)[number];\n","import { SHADE_STEPS, type ShadeStep } from \"@bison-lab/tokens\";\n\nimport { SYSTEM_COLOR_KEYS, type ThemeDoc } from \"./types\";\n\nconst STEP_SET = new Set<number>(SHADE_STEPS);\n\n/**\n * Page editors pick `coral-400`, never a raw hex. Rewrite every use of\n * `fromKey` onto `toKey` at the same step: `coral-400` → `highlight-400`.\n * A bare key (`coral`) becomes `toKey`. Anything else is left alone.\n */\nexport function rewriteColorToken(token: string, fromKey: string, toKey: string): string {\n if (token === fromKey) return toKey;\n const dash = token.lastIndexOf(\"-\");\n if (dash <= 0) return token;\n const key = token.slice(0, dash);\n const step = Number(token.slice(dash + 1));\n if (key !== fromKey || !STEP_SET.has(step)) return token;\n return `${toKey}-${step as ShadeStep}`;\n}\n\nexport function themeColorKeys(doc: ThemeDoc | null | undefined): string[] {\n const custom = (Array.isArray(doc?.colors?.library) ? doc.colors.library : [])\n .map((row) => row.key?.trim())\n .filter((key): key is string => Boolean(key));\n return [...SYSTEM_COLOR_KEYS, ...custom];\n}\n\n/**\n * Remove a custom color. Unused: omit `replacement` and the row is gone.\n * In use: pass another system or custom key; the caller rewrites page\n * tokens with `rewriteColorToken`. After this, no library row still\n * has `key`.\n */\nexport function deleteLibraryColor(doc: ThemeDoc, key: string, replacement?: string): ThemeDoc {\n const library = [...(Array.isArray(doc.colors?.library) ? doc.colors.library : [])];\n const index = library.findIndex((row) => row.key === key);\n if (index === -1) {\n throw new Error(`No custom color named ${JSON.stringify(key)}`);\n }\n library.splice(index, 1);\n const next: ThemeDoc = {\n ...doc,\n colors: { ...doc.colors, library },\n };\n if (replacement !== undefined) {\n if (replacement === key) {\n throw new Error(\"Replacement must be a different color\");\n }\n if (!themeColorKeys(next).includes(replacement)) {\n throw new Error(`Replacement ${JSON.stringify(replacement)} is not a system or remaining custom color`);\n }\n }\n return next;\n}\n","import { useField } from \"@payloadcms/ui\";\nimport { createColorScale } from \"@bison-lab/tokens\";\nimport type { ArrayFieldClientComponent } from \"payload\";\nimport { useState } from \"react\";\n\nimport { deleteLibraryColor } from \"../theme/library\";\nimport { colorDocFromState, stateFromColorDoc } from \"../theme/map\";\nimport { SYSTEM_COLOR_KEYS, type ThemeDoc, type ThemeLibraryColorDoc } from \"../theme/types\";\nimport { ColorScaleCard, COLOR_SCALE_CARD_CSS } from \"./color-scale-card\";\n\nfunction slugify(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\n/**\n * Custom colors: the same scale controls as system colors, plus add and\n * in-use delete (one replacement scale; unused rows delete immediately).\n */\nexport const LibraryField: ArrayFieldClientComponent = ({ path, readOnly }) => {\n const { value, setValue } = useField<ThemeLibraryColorDoc[]>({ path });\n const rows = Array.isArray(value) ? value : [];\n const [adding, setAdding] = useState(false);\n const [name, setName] = useState(\"\");\n const [hex, setHex] = useState(\"#E07A5F\");\n const [pendingDelete, setPendingDelete] = useState<ThemeLibraryColorDoc | null>(null);\n const [replacement, setReplacement] = useState(\"\");\n\n function write(next: ThemeLibraryColorDoc[]) {\n setValue(next);\n }\n\n function add() {\n const key = slugify(name);\n if (!key || rows.some((row) => row.key === key)) return;\n write([...rows, { key, label: name.trim(), ...colorDocFromState(createColorScale(hex, 500)) }]);\n setName(\"\");\n setAdding(false);\n }\n\n function remove(row: ThemeLibraryColorDoc, replaceWith?: string) {\n const doc: ThemeDoc = { colors: { library: rows } };\n write(deleteLibraryColor(doc, row.key ?? \"\", replaceWith).colors?.library ?? []);\n setPendingDelete(null);\n setReplacement(\"\");\n }\n\n const replacements = [\n ...SYSTEM_COLOR_KEYS.map((key) => ({ value: key, label: key[0].toUpperCase() + key.slice(1) })),\n ...rows\n .filter((row) => row.key && row.key !== pendingDelete?.key)\n .map((row) => ({ value: row.key ?? \"\", label: row.label ?? row.key ?? \"\" })),\n ];\n\n return (\n <div className=\"field-type bl-library\">\n <style href=\"bl-scale-card\" precedence=\"default\">\n {COLOR_SCALE_CARD_CSS}\n </style>\n <style href=\"bl-library\" precedence=\"default\">\n {CSS}\n </style>\n <div className=\"bl-library__head\">\n <div>\n <h2>Custom colors</h2>\n <p>Named scales that sit with the house colors. Page editors pick them as keys (`coral-400`).</p>\n </div>\n <button type=\"button\" disabled={readOnly} onClick={() => setAdding(true)}>\n Add color\n </button>\n </div>\n {adding ? (\n <div className=\"bl-library__add\">\n <label>\n Name\n <input value={name} onChange={(event) => setName(event.target.value)} />\n </label>\n <label>\n Hex\n <input value={hex} onChange={(event) => setHex(event.target.value)} />\n </label>\n <button type=\"button\" onClick={() => setAdding(false)}>\n Cancel\n </button>\n <button type=\"button\" disabled={!slugify(name)} onClick={add}>\n Create color scale\n </button>\n </div>\n ) : null}\n <div className=\"bl-library__list\">\n {rows.map((row, index) => (\n <ColorScaleCard\n key={row.key ?? index}\n id={row.key ?? `custom-${index}`}\n name={row.label ?? row.key ?? \"Color\"}\n hint={row.key ? `Key: ${row.key}` : undefined}\n custom\n state={stateFromColorDoc(row)}\n onChange={(next) => {\n const copy = [...rows];\n copy[index] = { ...row, ...colorDocFromState(next) };\n write(copy);\n }}\n onDelete={readOnly ? undefined : () => setPendingDelete(row)}\n readOnly={readOnly}\n />\n ))}\n </div>\n {pendingDelete ? (\n <div className=\"bl-library__modal\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"bl-library-delete-title\">\n <div className=\"bl-library__panel\">\n <h2 id=\"bl-library-delete-title\">Delete {pendingDelete.label ?? pendingDelete.key}</h2>\n <p>\n Unused custom colors delete immediately. If this scale is in use, pick one replacement — every{\" \"}\n <code>{pendingDelete.key}-400</code> becomes <code>{replacement || \"…\"}-400</code>.\n </p>\n <label>\n Replacement scale\n <select value={replacement} onChange={(event) => setReplacement(event.target.value)}>\n <option value=\"\">Choose a scale…</option>\n {replacements.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </label>\n <div className=\"bl-library__actions\">\n <button type=\"button\" onClick={() => setPendingDelete(null)}>\n Cancel\n </button>\n <button type=\"button\" onClick={() => remove(pendingDelete)}>\n Delete immediately\n </button>\n <button type=\"button\" disabled={!replacement} onClick={() => remove(pendingDelete, replacement)}>\n Replace & delete\n </button>\n </div>\n </div>\n </div>\n ) : null}\n </div>\n );\n};\n\nconst CSS = `\n.bl-library__head{display:flex;justify-content:space-between;gap:1rem;align-items:flex-start;margin-bottom:.85rem}\n.bl-library__head h2{margin:0;font-size:1.1rem}\n.bl-library__head p{margin:.35rem 0 0;font-size:13px;color:var(--theme-elevation-500,#64748b)}\n.bl-library__head button,.bl-library__add button,.bl-library__actions button{min-height:2.1rem;padding:.35rem .75rem;border-radius:8px;border:1px solid var(--theme-elevation-150,#e2e8f0);background:var(--theme-elevation-0,#fff);font:inherit;cursor:pointer}\n.bl-library__list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.85rem}\n@media (max-width:860px){.bl-library__list{grid-template-columns:1fr}}\n.bl-library__add{display:flex;flex-wrap:wrap;gap:.6rem;align-items:end;margin-bottom:.85rem;padding:.85rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:12px}\n.bl-library__add label{display:flex;flex-direction:column;gap:.3rem;font-size:12px;font-weight:600}\n.bl-library__add input{min-height:2.1rem;padding:.3rem .55rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:8px}\n.bl-library__modal{position:fixed;inset:0;z-index:80;display:grid;place-items:center;padding:1rem;background:rgba(15,23,42,.45)}\n.bl-library__panel{width:min(28rem,100%);padding:1.2rem;border-radius:16px;background:#fff;color:#0f172a}\n.bl-library__panel h2{margin:0}\n.bl-library__panel p{margin:.5rem 0 0;color:#475569;font-size:14px}\n.bl-library__panel label{display:flex;flex-direction:column;gap:.4rem;margin-top:1rem;font-size:13px;font-weight:600}\n.bl-library__panel select{min-height:2.25rem;border:1px solid #cbd5e1;border-radius:8px;padding:.35rem .5rem}\n.bl-library__actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.5rem;margin-top:1rem}\n`;\n","import type { ReactNode } from \"react\";\n\nexport function FontRoleCard({\n title,\n hint,\n required,\n family,\n preview,\n children,\n}: {\n title: string;\n hint: string;\n required?: boolean;\n family: string;\n preview: \"heading\" | \"body\";\n children?: ReactNode;\n}) {\n return (\n <article className=\"bl-font-role\">\n <header className=\"bl-font-role__head\">\n <div>\n <h3>{title}</h3>\n <p>{hint}</p>\n </div>\n {required ? <span className=\"bl-font-role__badge\">Required</span> : null}\n </header>\n {children}\n <div className=\"bl-font-role__preview\">\n <span>Preview</span>\n {preview === \"heading\" ? (\n <p className=\"bl-font-role__heading\" style={{ fontFamily: `\"${family}\"` }}>\n Advancing the work with clarity.\n </p>\n ) : (\n <p className=\"bl-font-role__body\" style={{ fontFamily: `\"${family}\"` }}>\n Clear, comfortable text for longer reading across the site.\n </p>\n )}\n </div>\n </article>\n );\n}\n\nexport function TypographyPairing({\n headingFamily,\n bodyFamily,\n}: {\n headingFamily: string;\n bodyFamily: string;\n}) {\n return (\n <section className=\"bl-pairing\" aria-label=\"Font pairing sample\">\n <header>\n <h2>Pairing sample</h2>\n <p>Heading and body from the approved catalogue. Type scale stays with the library.</p>\n </header>\n <div className=\"bl-pairing__page\">\n <p className=\"bl-pairing__eyebrow\" style={{ fontFamily: `\"${bodyFamily}\"` }}>\n For visitors\n </p>\n <p className=\"bl-pairing__title\" style={{ fontFamily: `\"${headingFamily}\"` }}>\n Stay in motion.\n </p>\n <p className=\"bl-pairing__copy\" style={{ fontFamily: `\"${bodyFamily}\"` }}>\n Heading and body come from the catalogue. This is the pairing, not a full site preview.\n </p>\n <div className=\"bl-pairing__actions\">\n <span className=\"bl-pairing__btn\" style={{ fontFamily: `\"${bodyFamily}\"` }}>\n Primary action\n </span>\n <span className=\"bl-pairing__btn bl-pairing__btn--ghost\" style={{ fontFamily: `\"${bodyFamily}\"` }}>\n Learn more\n </span>\n </div>\n </div>\n </section>\n );\n}\n\nexport const TYPOGRAPHY_PAIRING_CSS = `\n.bl-font-role{padding:1.1rem 1.15rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:12px;background:var(--theme-elevation-0,#fff)}\n.bl-font-role__head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem}\n.bl-font-role__head h3{margin:0;font-size:1rem}\n.bl-font-role__head p{margin:.3rem 0 0;font-size:12px;color:var(--theme-elevation-500,#64748b)}\n.bl-font-role__badge{font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:.15rem .45rem;border-radius:999px;background:var(--theme-elevation-100,#f1f5f9);color:var(--theme-elevation-500,#64748b)}\n.bl-font-role__preview{margin-top:1rem;padding:.85rem .9rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:12px;background:var(--theme-elevation-50,#f8fafc)}\n.bl-font-role__preview > span{display:block;margin-bottom:.4rem;font-size:11px;color:var(--theme-elevation-500,#64748b)}\n.bl-font-role__heading{margin:0;font-size:1.5rem;line-height:1.2;font-weight:600}\n.bl-font-role__body{margin:0;font-size:1rem;line-height:1.6;color:var(--theme-elevation-600,#475569)}\n.bl-pairing{padding:0;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:12px;background:var(--theme-elevation-0,#fff);overflow:hidden}\n.bl-pairing > header{padding:1rem 1.15rem;border-bottom:1px solid var(--theme-elevation-150,#e2e8f0)}\n.bl-pairing > header h2{margin:0;font-size:1rem}\n.bl-pairing > header p{margin:.3rem 0 0;font-size:12px;color:var(--theme-elevation-500,#64748b)}\n.bl-pairing__page{padding:1.35rem 1.4rem 1.5rem}\n.bl-pairing__eyebrow{margin:0;font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:#7c1fa2}\n.bl-pairing__title{margin:.5rem 0 0;font-size:2rem;line-height:1.1;font-weight:600}\n.bl-pairing__copy{margin:.75rem 0 0;max-width:36rem;font-size:1rem;line-height:1.6;color:var(--theme-elevation-600,#475569)}\n.bl-pairing__actions{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:1.1rem}\n.bl-pairing__btn{display:inline-flex;align-items:center;min-height:2.15rem;padding:.4rem .85rem;border-radius:8px;background:#db0082;color:#fff;font-size:14px;font-weight:600}\n.bl-pairing__btn--ghost{background:#fff;color:#0f172a;border:1px solid #cbd5e1}\n`;\n","import { FieldDescription, FieldError, FieldLabel, useField } from \"@payloadcms/ui\";\nimport { findFont, fontFaceCss, isFontId, type FontId } from \"@bison-lab/fonts\";\nimport type { SelectFieldClientComponent } from \"payload\";\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\n\nimport { FONT_ROLE_COPY } from \"../theme/appearance-labels\";\nimport { SAME_AS_BODY } from \"../theme/fields\";\nimport { FontRoleCard, TYPOGRAPHY_PAIRING_CSS } from \"./typography-pairing\";\n\ntype Option = { value: string; family: string; hint: string; specimen: boolean };\n\n/**\n * Listbox over the catalogue ids in `admin.custom.ids`. Each option is the\n * family name in that face, with the catalogue hint beneath. Faces load\n * from the site's font route for the selected family, and for every\n * catalogue id once the picker opens.\n */\nexport const FontField: SelectFieldClientComponent = ({ field, path, readOnly }) => {\n const { value, setValue, showError, errorMessage } = useField<string>({ path });\n const custom = (field.admin?.custom ?? {}) as {\n fontsBaseUrl?: string;\n ids?: string[];\n sameAsBody?: boolean;\n };\n const ids = custom.ids ?? [];\n const fontsBaseUrl = custom.fontsBaseUrl ?? \"/fonts\";\n const sameAsBody = Boolean(custom.sameAsBody);\n\n const options = useMemo<Option[]>(() => {\n const fromCatalogue: Option[] = ids.flatMap((id) => {\n const font = findFont(id);\n if (!font) return [];\n return [{ value: font.id, family: font.family, hint: font.hint, specimen: true }];\n });\n if (!sameAsBody) return fromCatalogue;\n return [{ value: SAME_AS_BODY, family: \"Same as body\", hint: \"Use the body family for headings\", specimen: false }, ...fromCatalogue];\n }, [ids, sameAsBody]);\n\n const [open, setOpen] = useState(false);\n const [faces, setFaces] = useState(false);\n const [active, setActive] = useState(-1);\n const [query, setQuery] = useState(\"\");\n const [category, setCategory] = useState<\"all\" | \"sans\" | \"serif\" | \"display\" | \"mono\">(\"all\");\n const typed = useRef(\"\");\n const typedAt = useRef(0);\n const id = useId();\n const buttonId = `${id}-button`;\n const listId = `${id}-list`;\n const required = Boolean(field.required);\n\n useEffect(() => {\n if (open) setFaces(true);\n }, [open]);\n\n const selected = options.find((option) => option.value === (value ?? SAME_AS_BODY)) ?? options[0];\n const visible = options.filter((option) => {\n if (query && !option.family.toLowerCase().includes(query.trim().toLowerCase())) return false;\n if (category === \"all\" || !option.specimen) return true;\n const font = findFont(option.value);\n return font?.category === category;\n });\n const role = sameAsBody ? FONT_ROLE_COPY.heading : FONT_ROLE_COPY.body;\n\n function choose(option: Option) {\n setValue(option.value);\n setOpen(false);\n setActive(-1);\n setQuery(\"\");\n setCategory(\"all\");\n }\n\n function onKeyDown(event: React.KeyboardEvent<HTMLButtonElement>) {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n if (!open) {\n setOpen(true);\n setActive(0);\n return;\n }\n setActive((i) => (options.length ? (i + 1) % options.length : -1));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n if (!open) {\n setOpen(true);\n setActive(options.length - 1);\n return;\n }\n setActive((i) => (options.length ? (i <= 0 ? options.length - 1 : i - 1) : -1));\n } else if (event.key === \"Enter\") {\n if (!open) return;\n event.preventDefault();\n const pick = options[active] ?? options[0];\n if (pick) choose(pick);\n } else if (event.key === \"Escape\") {\n if (!open) return;\n event.preventDefault();\n event.stopPropagation();\n setOpen(false);\n setActive(-1);\n } else if (event.key.length === 1 && !event.metaKey && !event.ctrlKey && !event.altKey) {\n const now = Date.now();\n typed.current = now - typedAt.current > 600 ? event.key : typed.current + event.key;\n typedAt.current = now;\n const needle = typed.current.toLowerCase();\n const index = options.findIndex((option) => option.family.toLowerCase().startsWith(needle));\n if (index >= 0) {\n if (!open) setOpen(true);\n setActive(index);\n }\n }\n }\n\n const activeId = active >= 0 && open ? `${id}-option-${active}` : undefined;\n const faceIds = (faces ? ids : isFontId(value) ? [value] : []) as FontId[];\n\n return (\n <div className=\"field-type bl-font-field\">\n <style href=\"bl-pairing\" precedence=\"default\">\n {TYPOGRAPHY_PAIRING_CSS}\n </style>\n <style href=\"bl-font-field\" precedence=\"default\">\n {CSS}\n </style>\n {faceIds.length > 0 ? <style data-bl-font-faces=\"\">{fontFaceCss(faceIds, fontsBaseUrl)}</style> : null}\n <FontRoleCard\n title={typeof field.label === \"string\" ? field.label : role.label}\n hint={role.hint}\n required={required}\n family={selected?.family ?? \"Inter\"}\n preview={sameAsBody ? \"heading\" : \"body\"}\n >\n <FieldLabel htmlFor={buttonId} label={field.label} required={required} />\n <button\n id={buttonId}\n type=\"button\"\n className=\"bl-font-field__trigger\"\n disabled={readOnly}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-controls={listId}\n aria-activedescendant={activeId}\n onClick={() => setOpen((was) => !was)}\n onKeyDown={onKeyDown}\n >\n <span>\n <span className=\"bl-font-field__selected-label\">Selected</span>\n <span\n className=\"bl-font-field__selected-name\"\n style={selected?.specimen ? { fontFamily: `\"${selected.family}\"` } : undefined}\n >\n {selected?.family ?? \"Choose a font\"}\n </span>\n </span>\n <span aria-hidden=\"true\">⌄</span>\n </button>\n </FontRoleCard>\n {open ? (\n <div\n className=\"bl-font-field__modal\"\n onClick={(event) => {\n if (event.target === event.currentTarget) setOpen(false);\n }}\n >\n <div className=\"bl-font-field__panel\">\n <div className=\"bl-font-field__panel-head\">\n <div>\n <p>Choose a font</p>\n <h2>{role.label}</h2>\n </div>\n <button type=\"button\" onClick={() => setOpen(false)} aria-label=\"Close\">\n ×\n </button>\n </div>\n <input\n type=\"search\"\n className=\"bl-font-field__search\"\n placeholder=\"Search fonts…\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n />\n <div className=\"bl-font-field__filters\">\n {([\"all\", \"sans\", \"serif\", \"display\", \"mono\"] as const).map((item) => (\n <button\n key={item}\n type=\"button\"\n data-on={category === item ? \"\" : undefined}\n onClick={() => setCategory(item)}\n >\n {item === \"all\" ? \"All\" : item === \"sans\" ? \"Sans serif\" : item === \"serif\" ? \"Serif\" : item === \"display\" ? \"Display\" : \"Mono\"}\n </button>\n ))}\n </div>\n <ul id={listId} role=\"listbox\" className=\"bl-font-field__menu\">\n {visible.map((option, i) => (\n <li\n key={option.value || \"same\"}\n id={`${id}-option-${i}`}\n role=\"option\"\n aria-selected={option.value === (value ?? SAME_AS_BODY)}\n className=\"bl-font-field__option\"\n onMouseDown={(event) => {\n event.preventDefault();\n choose(option);\n }}\n onMouseEnter={() => setActive(i)}\n >\n <span\n className=\"bl-font-field__family\"\n style={option.specimen ? { fontFamily: `\"${option.family}\"` } : undefined}\n >\n {option.family}\n </span>\n <span className=\"bl-font-field__hint\">{option.hint}</span>\n <span\n className=\"bl-font-field__specimen\"\n style={option.specimen ? { fontFamily: `\"${option.family}\"` } : undefined}\n >\n The quick brown fox jumps over the lazy dog.\n </span>\n </li>\n ))}\n </ul>\n </div>\n </div>\n ) : null}\n <FieldDescription description={field.admin?.description} path={path} />\n <FieldError path={path} showError={showError} message={errorMessage} />\n </div>\n );\n};\n\nconst CSS = `\n.bl-font-field{margin-bottom:1rem}\n.bl-font-field .field-label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n.bl-font-field__trigger{display:flex;align-items:center;justify-content:space-between;width:100%;margin-top:1rem;min-height:3.25rem;padding:.7rem 1rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:12px;background:var(--theme-input-bg,#fff);color:inherit;font:inherit;text-align:left;cursor:pointer}\n.bl-font-field__trigger:focus{border-color:var(--theme-elevation-400,#94a3b8);outline:none;box-shadow:0 0 0 1px var(--theme-elevation-400,#94a3b8)}\n.bl-font-field__trigger:disabled{color:var(--theme-elevation-400,#94a3b8);cursor:not-allowed}\n.bl-font-field__selected-label{display:block;font-size:11px;color:var(--theme-elevation-500,#64748b)}\n.bl-font-field__selected-name{display:block;margin-top:.15rem;font-weight:600}\n.bl-font-field__modal{position:fixed;inset:0;z-index:80;display:grid;place-items:center;padding:1rem;background:rgba(15,23,42,.45)}\n.bl-font-field__panel{width:min(36rem,100%);max-height:min(36rem,90vh);display:flex;flex-direction:column;padding:1.15rem 1.2rem;border-radius:16px;background:#fff;color:#0f172a}\n.bl-font-field__panel-head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem}\n.bl-font-field__panel-head p{margin:0;font-size:12px;color:#64748b}\n.bl-font-field__panel-head h2{margin:.2rem 0 0;font-size:1.15rem}\n.bl-font-field__panel-head button{border:0;background:none;font:inherit;font-size:1.25rem;color:#64748b;cursor:pointer}\n.bl-font-field__search{margin-top:.9rem;min-height:2.5rem;padding:.5rem .75rem;border:1px solid #cbd5e1;border-radius:10px;font:inherit}\n.bl-font-field__filters{display:flex;flex-wrap:wrap;gap:.4rem;margin-top:.75rem}\n.bl-font-field__filters button{min-height:1.8rem;padding:.2rem .7rem;border:0;border-radius:999px;background:#f1f5f9;color:#475569;font:inherit;font-size:12px;cursor:pointer}\n.bl-font-field__filters button[data-on]{background:#0f172a;color:#fff}\n.bl-font-field__menu{margin:.75rem 0 0;padding:0;list-style:none;overflow:auto;max-height:18rem}\n.bl-font-field__option{display:flex;flex-direction:column;gap:2px;margin-bottom:.5rem;padding:.75rem .85rem;border:1px solid #e2e8f0;border-radius:12px;cursor:pointer}\n.bl-font-field__option[aria-selected=\"true\"]{border-color:#7c1fa2;background:#f5f3ff}\n.bl-font-field__family{font-weight:600}\n.bl-font-field__hint{color:#64748b;font-size:12px}\n.bl-font-field__specimen{margin-top:.45rem;font-size:1.25rem;line-height:1.3}\n`;\n","import { useFormFields } from \"@payloadcms/ui\";\nimport { findFont, fontFaceCss, type FontId } from \"@bison-lab/fonts\";\nimport type { UIFieldClientComponent } from \"payload\";\n\nimport { SAME_AS_BODY } from \"../theme/fields\";\nimport { TypographyPairing, TYPOGRAPHY_PAIRING_CSS } from \"./typography-pairing\";\n\n/**\n * Pairing sample only — no weight, letter-spacing, line-height, or health\n * scores. Faces load from the site's font route.\n */\nexport const PairingField: UIFieldClientComponent = ({ field }) => {\n const custom = (field.admin?.custom ?? {}) as { fontsBaseUrl?: string };\n const fontsBaseUrl = custom.fontsBaseUrl ?? \"/fonts\";\n const { body, heading } = useFormFields(([fields]) => {\n const record = fields as Record<string, { value?: unknown } | undefined>;\n return {\n body: String(record[\"typography.body\"]?.value ?? \"\"),\n heading: String(record[\"typography.heading\"]?.value ?? SAME_AS_BODY),\n };\n });\n const headingId = heading || body;\n const bodyFont = findFont(body);\n const headingFont = findFont(headingId);\n const ids = [body, headingId].filter(Boolean) as FontId[];\n\n return (\n <div className=\"field-type bl-pairing-field\">\n <style href=\"bl-pairing\" precedence=\"default\">\n {TYPOGRAPHY_PAIRING_CSS}\n </style>\n {ids.length > 0 ? <style data-bl-font-faces=\"\">{fontFaceCss(ids, fontsBaseUrl)}</style> : null}\n <TypographyPairing\n headingFamily={headingFont?.family ?? \"Georgia\"}\n bodyFamily={bodyFont?.family ?? \"system-ui\"}\n />\n </div>\n );\n};\n","import { APPEARANCE_CHOICES, APPEARANCE_FAMILY_COPY } from \"../theme/appearance-labels\";\n\ntype Family = keyof typeof APPEARANCE_CHOICES;\n\nfunction ChoicePreview({ family, value }: { family: Family; value: string }) {\n return (\n <div className=\"bl-appearance__preview\" data-family={family} data-value={value} aria-hidden=\"true\">\n {family === \"defaultTheme\" && value === \"system\" ? (\n <>\n <div className=\"bl-appearance__pane bl-appearance__pane--light\">\n <i />\n <b />\n </div>\n <div className=\"bl-appearance__pane bl-appearance__pane--dark\">\n <i />\n <b />\n </div>\n </>\n ) : family === \"motion\" ? (\n <span className=\"bl-appearance__dot\" />\n ) : family === \"shadow\" ? (\n <div className=\"bl-appearance__lift\" />\n ) : family === \"radius\" ? (\n <>\n <b>Button</b>\n <i className=\"bl-appearance__input\" />\n <i className=\"bl-appearance__card\" />\n </>\n ) : family === \"density\" ? (\n <>\n <b />\n <i className=\"bl-appearance__input\" />\n <i className=\"bl-appearance__card\" />\n </>\n ) : (\n <>\n <i />\n <i />\n <b />\n </>\n )}\n </div>\n );\n}\n\nexport function AppearanceChoices({\n values,\n onChange,\n readOnly,\n}: {\n values: Record<Family, string>;\n onChange: (name: Family, value: string) => void;\n readOnly?: boolean;\n}) {\n return (\n <div className=\"bl-appearance\">\n <header className=\"bl-appearance__intro\">\n <h2>Set the overall feel of your site</h2>\n <p>\n Choose how rounded, elevated, animated, and spacious the interface feels. You don’t manage the\n technical values — the system handles those.\n </p>\n </header>\n {(Object.keys(APPEARANCE_CHOICES) as Family[]).map((family) => {\n const choices = APPEARANCE_CHOICES[family];\n const copy = APPEARANCE_FAMILY_COPY[family];\n return (\n <fieldset key={family} className=\"bl-appearance__family\">\n <legend>\n <strong>{copy.title}</strong>\n <span>{copy.hint}</span>\n </legend>\n <div className=\"bl-appearance__choices\" data-family={family}>\n {Object.entries(choices).map(([value, item]) => {\n const selected = values[family] === value;\n return (\n <label\n key={value}\n className=\"bl-appearance__choice\"\n data-selected={selected ? \"\" : undefined}\n >\n <input\n type=\"radio\"\n name={family}\n value={value}\n checked={selected}\n disabled={readOnly}\n onChange={() => onChange(family, value)}\n />\n <ChoicePreview family={family} value={value} />\n <span className=\"bl-appearance__copy\">\n <strong>\n {item.label}\n {selected ? <em aria-hidden=\"true\">✓</em> : null}\n </strong>\n <span>{item.hint}</span>\n </span>\n </label>\n );\n })}\n </div>\n {family === \"motion\" ? (\n <p className=\"bl-appearance__note\">\n Visitors who prefer reduced motion will still see fewer animations automatically.\n </p>\n ) : null}\n </fieldset>\n );\n })}\n </div>\n );\n}\n\nexport const APPEARANCE_CHOICES_CSS = `\n.bl-appearance{display:flex;flex-direction:column;gap:1.25rem}\n.bl-appearance__intro h2{margin:0;font-size:1.1rem}\n.bl-appearance__intro p{margin:.35rem 0 0;font-size:13px;color:var(--theme-elevation-500,#64748b);max-width:40rem}\n.bl-appearance__family{margin:0;padding:1rem 1.1rem 1.15rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:12px;background:var(--theme-elevation-0,#fff)}\n.bl-appearance__family legend{padding:0;margin-bottom:.85rem}\n.bl-appearance__family legend strong{display:block;font-size:14px}\n.bl-appearance__family legend span{display:block;margin-top:.25rem;font-size:12px;color:var(--theme-elevation-500,#64748b);font-weight:400}\n.bl-appearance__choices{display:grid;gap:.6rem}\n.bl-appearance__choices[data-family=defaultTheme],.bl-appearance__choices[data-family=shadow],.bl-appearance__choices[data-family=motion],.bl-appearance__choices[data-family=density]{grid-template-columns:repeat(3,minmax(0,1fr))}\n.bl-appearance__choices[data-family=radius]{grid-template-columns:repeat(4,minmax(0,1fr))}\n.bl-appearance__choice{display:flex;flex-direction:column;gap:.65rem;padding:.75rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:12px;background:var(--theme-elevation-0,#fff);cursor:pointer}\n.bl-appearance__choice[data-selected]{box-shadow:inset 0 0 0 2px #0f172a;border-color:#0f172a}\n.bl-appearance__choice input{position:absolute;opacity:0;pointer-events:none}\n.bl-appearance__copy{display:flex;flex-direction:column;gap:.2rem}\n.bl-appearance__copy strong{display:flex;justify-content:space-between;align-items:center;gap:.4rem;font-size:14px}\n.bl-appearance__copy em{font-style:normal}\n.bl-appearance__copy span{font-size:12px;color:var(--theme-elevation-500,#64748b)}\n.bl-appearance__note{margin:.75rem 0 0;font-size:12px;color:var(--theme-elevation-500,#64748b)}\n.bl-appearance__preview{--bl-preview-brand:#db0082;--bl-preview-radius:8px;border-radius:10px;background:#f8fafc;overflow:hidden}\n.bl-appearance__preview[data-family=defaultTheme]{display:grid;min-height:5.5rem;padding:.65rem}\n.bl-appearance__preview[data-family=defaultTheme][data-value=system]{grid-template-columns:1fr 1fr;padding:0}\n.bl-appearance__preview[data-family=defaultTheme][data-value=dark]{background:#020617}\n.bl-appearance__pane{display:flex;flex-direction:column;gap:.45rem;padding:.65rem}\n.bl-appearance__pane--dark{background:#020617}\n.bl-appearance__pane i,.bl-appearance__preview[data-family=defaultTheme] > i{display:block;height:.4rem;width:42%;border-radius:99px;background:#0f172a}\n.bl-appearance__pane i + i,.bl-appearance__preview[data-family=defaultTheme] > i + i{width:64%;background:#cbd5e1}\n.bl-appearance__pane--dark i{background:#fff}\n.bl-appearance__pane--dark i + i{background:#334155}\n.bl-appearance__preview[data-family=defaultTheme][data-value=dark] > i{background:#fff}\n.bl-appearance__preview[data-family=defaultTheme][data-value=dark] > i + i{background:#334155}\n.bl-appearance__pane b,.bl-appearance__preview[data-family=defaultTheme] > b{display:block;height:1.6rem;margin-top:auto;border-radius:6px;background:var(--bl-preview-brand)}\n.bl-appearance__pane--dark b{background:var(--bl-preview-brand)}\n.bl-appearance__preview[data-family=radius]{display:flex;flex-direction:column;gap:.45rem;padding:.65rem;background:#fff}\n.bl-appearance__preview[data-family=radius] b{display:grid;place-items:center;height:1.85rem;background:var(--bl-preview-brand);color:#fff;font-size:10px;font-weight:600;border-radius:var(--bl-preview-radius)}\n.bl-appearance__input{display:block;height:1.85rem;border:1px solid #cbd5e1;background:#f8fafc;border-radius:var(--bl-preview-radius)}\n.bl-appearance__card{display:block;height:2.4rem;border:1px solid #e2e8f0;background:#fff;border-radius:var(--bl-preview-radius)}\n.bl-appearance__preview[data-value=sharp]{--bl-preview-radius:0}\n.bl-appearance__preview[data-value=subtle]{--bl-preview-radius:6px}\n.bl-appearance__preview[data-value=rounded]{--bl-preview-radius:12px}\n.bl-appearance__preview[data-value=pill]{--bl-preview-radius:999px}\n.bl-appearance__preview[data-value=pill] .bl-appearance__card{--bl-preview-radius:1.25rem}\n.bl-appearance__preview[data-family=shadow]{display:grid;place-items:center;min-height:6.5rem;padding:.85rem}\n.bl-appearance__lift{width:100%;height:3.5rem;border-radius:10px;background:#fff}\n.bl-appearance__preview[data-value=flat] .bl-appearance__lift{border:1px solid #e2e8f0}\n.bl-appearance__preview[data-value=subtle] .bl-appearance__lift{box-shadow:0 1px 2px rgba(15,23,42,.06),0 4px 12px rgba(15,23,42,.06)}\n.bl-appearance__preview[data-value=elevated] .bl-appearance__lift{box-shadow:0 10px 30px rgba(15,23,42,.12)}\n.bl-appearance__preview[data-family=motion]{display:flex;align-items:center;min-height:4.5rem;padding:0 .85rem}\n.bl-appearance__dot{width:1.15rem;height:1.15rem;border-radius:999px;background:var(--bl-preview-brand);animation:bl-appear-dot 1.8s ease-in-out infinite}\n.bl-appearance__preview[data-value=snappy] .bl-appearance__dot{animation-duration:1s}\n.bl-appearance__preview[data-value=minimal] .bl-appearance__dot{animation-duration:2.5s}\n@keyframes bl-appear-dot{0%,100%{transform:translateX(0)}50%{transform:translateX(4.5rem)}}\n.bl-appearance__preview[data-family=density]{display:flex;flex-direction:column;background:#f8fafc}\n.bl-appearance__preview[data-value=compact]{gap:.4rem;padding:.55rem}\n.bl-appearance__preview[data-value=default]{gap:.65rem;padding:.8rem}\n.bl-appearance__preview[data-value=spacious]{gap:.9rem;padding:1.05rem}\n.bl-appearance__preview[data-family=density] b{display:block;height:1.7rem;background:var(--bl-preview-brand);border-radius:6px}\n.bl-appearance__preview[data-value=compact] b,.bl-appearance__preview[data-value=compact] .bl-appearance__input{height:1.45rem}\n.bl-appearance__preview[data-value=spacious] b,.bl-appearance__preview[data-value=spacious] .bl-appearance__input{height:2.1rem}\n@media (max-width:720px){\n .bl-appearance__choices[data-family=defaultTheme],.bl-appearance__choices[data-family=shadow],.bl-appearance__choices[data-family=motion],.bl-appearance__choices[data-family=density],.bl-appearance__choices[data-family=radius]{grid-template-columns:1fr}\n}\n@media (prefers-reduced-motion:reduce){\n .bl-appearance__dot{animation:none}\n}\n`;\n","import { useField } from \"@payloadcms/ui\";\nimport type { GroupFieldClientComponent } from \"payload\";\n\nimport { APPEARANCE_CHOICES } from \"../theme/appearance-labels\";\nimport { AppearanceChoices, APPEARANCE_CHOICES_CSS } from \"./appearance-choices\";\n\ntype Family = keyof typeof APPEARANCE_CHOICES;\n\n/**\n * Named appearance choices. Soft → pill, Gentle → minimal, Balanced →\n * default, Follow device → system. No rem or ms.\n */\nexport const AppearanceField: GroupFieldClientComponent = ({ path, readOnly }) => {\n const defaultTheme = useField<string>({ path: `${path}.defaultTheme` });\n const radius = useField<string>({ path: `${path}.radius` });\n const shadow = useField<string>({ path: `${path}.shadow` });\n const motion = useField<string>({ path: `${path}.motion` });\n const density = useField<string>({ path: `${path}.density` });\n const fields = { defaultTheme, radius, shadow, motion, density };\n\n function onChange(name: Family, value: string) {\n fields[name].setValue(value);\n }\n\n return (\n <div className=\"field-type bl-appearance-field\">\n <style href=\"bl-appearance\" precedence=\"default\">\n {APPEARANCE_CHOICES_CSS}\n </style>\n <AppearanceChoices\n values={{\n defaultTheme: defaultTheme.value ?? \"system\",\n radius: radius.value ?? \"rounded\",\n shadow: shadow.value ?? \"subtle\",\n motion: motion.value ?? \"smooth\",\n density: density.value ?? \"default\",\n }}\n onChange={onChange}\n readOnly={readOnly}\n />\n </div>\n );\n};\n","import { GREY_SCALES, presetHints, type GreyScale } from \"@bison-lab/tokens\";\nimport { useField } from \"@payloadcms/ui\";\nimport type { SelectFieldClientComponent } from \"payload\";\n\nconst FAMILIES = Object.keys(presetHints.greyScale) as GreyScale[];\nconst SWATCHES = [\"50\", \"200\", \"400\", \"700\", \"950\"] as const;\n\nexport function GreyScaleChoices({\n value,\n onChange,\n readOnly,\n}: {\n value: GreyScale;\n onChange: (next: GreyScale) => void;\n readOnly?: boolean;\n}) {\n return (\n <section className=\"bl-grey\">\n <header className=\"bl-grey__head\">\n <div>\n <h2>Gray family</h2>\n <p>Choose the neutral family used for page backgrounds, cards, borders, inputs, and muted text.</p>\n </div>\n <span className=\"bl-grey__badge\">Required</span>\n </header>\n <div className=\"bl-grey__choices\">\n {FAMILIES.map((id) => {\n const copy = presetHints.greyScale[id];\n const selected = value === id;\n return (\n <label key={id} className=\"bl-grey__choice\" data-selected={selected ? \"\" : undefined}>\n <input\n type=\"radio\"\n name=\"greyScale\"\n value={id}\n checked={selected}\n disabled={readOnly}\n onChange={() => onChange(id)}\n />\n <span className=\"bl-grey__ramp\" aria-hidden=\"true\">\n {SWATCHES.map((step) => (\n <i key={step} style={{ background: `hsl(${GREY_SCALES[id][step]})` }} />\n ))}\n </span>\n <strong>\n {copy.label}\n {selected ? <em aria-hidden=\"true\">✓</em> : null}\n </strong>\n <span>{copy.hint}</span>\n </label>\n );\n })}\n </div>\n </section>\n );\n}\n\n/**\n * Visual picker over the five grey-scale presets. Replaces the stock select\n * on Colors; the stored value is still `colors.greyScale`.\n */\nexport const GreyScaleField: SelectFieldClientComponent = ({ path, readOnly }) => {\n const { value, setValue } = useField<GreyScale>({ path });\n\n return (\n <div className=\"field-type bl-grey-field\">\n <style href=\"bl-grey\" precedence=\"default\">\n {GREY_SCALE_FIELD_CSS}\n </style>\n <GreyScaleChoices value={value ?? \"slate\"} onChange={setValue} readOnly={readOnly} />\n </div>\n );\n};\n\nexport const GREY_SCALE_FIELD_CSS = `\n.bl-grey{margin:0 0 1.75rem}\n.bl-grey__head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem;margin-bottom:.85rem}\n.bl-grey__head h2{margin:0;font-size:1.1rem}\n.bl-grey__head p{margin:.35rem 0 0;max-width:40rem;font-size:13px;color:var(--theme-elevation-500,#64748b)}\n.bl-grey__badge{font:inherit;font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:.15rem .45rem;border-radius:999px;background:var(--theme-elevation-100,#f1f5f9);color:var(--theme-elevation-500,#64748b)}\n.bl-grey__choices{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:.6rem}\n.bl-grey__choice{display:flex;flex-direction:column;gap:.45rem;padding:.75rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:12px;background:var(--theme-elevation-0,#fff);cursor:pointer}\n.bl-grey__choice[data-selected]{box-shadow:inset 0 0 0 2px #0f172a;border-color:#0f172a}\n.bl-grey__choice input{position:absolute;opacity:0;pointer-events:none}\n.bl-grey__ramp{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:3px}\n.bl-grey__ramp i{display:block;height:2rem;border-radius:6px}\n.bl-grey__choice strong{display:flex;justify-content:space-between;align-items:center;gap:.4rem;font-size:14px}\n.bl-grey__choice em{font-style:normal}\n.bl-grey__choice > span{font-size:12px;color:var(--theme-elevation-500,#64748b)}\n[data-bl-theme-preview=dark] .bl-grey__head p,[data-bl-theme-preview=dark] .bl-grey__choice > span{color:#94a3b8}\n[data-bl-theme-preview=dark] .bl-grey__choice{background:#0f172a;border-color:#334155;color:#f8fafc}\n[data-bl-theme-preview=dark] .bl-grey__choice[data-selected]{box-shadow:inset 0 0 0 2px #f8fafc;border-color:#f8fafc}\n[data-bl-theme-preview=dark] .bl-grey__badge{background:#1e293b;color:#94a3b8}\n@media (max-width:720px){.bl-grey__choices{grid-template-columns:1fr}}\n`;\n","import type { UIFieldClientComponent } from \"payload\";\n\n/**\n * Contrast used to be a Colors-tab list. Readability now lives on each\n * color card: Needs attention opens a popup. This field stays in the\n * schema so `contrastTarget` is still a Theme option; it paints nothing.\n */\nexport const ContrastReport: UIFieldClientComponent = () => null;\n","import type { UIFieldClientComponent } from \"payload\";\n\n/**\n * Unnamed UI heading between Theme fields. No document path.\n */\nexport const SectionHeading: UIFieldClientComponent = ({ field }) => {\n const custom = (field.admin?.custom ?? {}) as { title?: string; hint?: string };\n if (!custom.title) return null;\n return (\n <header className=\"bl-section-heading\">\n <style href=\"bl-section-heading\" precedence=\"default\">\n {CSS}\n </style>\n <h2>{custom.title}</h2>\n {custom.hint ? <p>{custom.hint}</p> : null}\n </header>\n );\n};\n\nconst CSS = `\n.bl-section-heading{margin:1.25rem 0 .65rem}\n.bl-section-heading:first-child{margin-top:0}\n.bl-section-heading h2{margin:0;font-size:1.1rem}\n.bl-section-heading p{margin:.35rem 0 0;font-size:13px;color:var(--theme-elevation-500,#64748b);max-width:40rem}\n`;\n","import { SYSTEM_COLOR_KEYS, type ThemeDoc, type ThemeLibraryColorDoc } from \"./types\";\nimport type { ThemeChild } from \"./publish\";\n\n/** Payload may hand an empty array field as `{}`. `.map` on that crashes the Theme form. */\nexport function libraryRows(value: unknown): ThemeLibraryColorDoc[] {\n return Array.isArray(value) ? value : [];\n}\n\nfunction colorLine(name: string, before: unknown, after: unknown): string | null {\n const a = before && typeof before === \"object\" ? before : { hex: before };\n const b = after && typeof after === \"object\" ? after : { hex: after };\n const left = a as { hex?: unknown; sourceStep?: unknown };\n const right = b as { hex?: unknown; sourceStep?: unknown };\n if (left.hex === right.hex && String(left.sourceStep) === String(right.sourceStep)) return null;\n return `${name}: ${String(left.hex ?? \"—\")} → ${String(right.hex ?? \"—\")}`;\n}\n\n/**\n * Human lines for the Publish confirmation. Only this child's\n * differences; other responsibilities are not listed.\n */\nexport function themeChildChanges(child: ThemeChild, published: ThemeDoc, incoming: ThemeDoc): string[] {\n if (child === \"colors\") {\n const lines: string[] = [];\n for (const key of SYSTEM_COLOR_KEYS) {\n const line = colorLine(\n key[0].toUpperCase() + key.slice(1),\n published.colors?.brand?.[key],\n incoming.colors?.brand?.[key],\n );\n if (line) lines.push(line);\n }\n const beforeKeys = libraryRows(published.colors?.library)\n .map((row) => row.key)\n .join(\", \");\n const afterKeys = libraryRows(incoming.colors?.library)\n .map((row) => row.key)\n .join(\", \");\n if (beforeKeys !== afterKeys) lines.push(`Custom colors: ${beforeKeys || \"none\"} → ${afterKeys || \"none\"}`);\n if ((published.colors?.greyScale ?? \"\") !== (incoming.colors?.greyScale ?? \"\")) {\n lines.push(`Gray family: ${published.colors?.greyScale ?? \"—\"} → ${incoming.colors?.greyScale ?? \"—\"}`);\n }\n return lines;\n }\n if (child === \"typography\") {\n const lines: string[] = [];\n if ((published.typography?.heading ?? \"\") !== (incoming.typography?.heading ?? \"\")) {\n lines.push(`Heading: ${published.typography?.heading || \"same as body\"} → ${incoming.typography?.heading || \"same as body\"}`);\n }\n if ((published.typography?.body ?? \"\") !== (incoming.typography?.body ?? \"\")) {\n lines.push(`Body: ${published.typography?.body ?? \"—\"} → ${incoming.typography?.body ?? \"—\"}`);\n }\n return lines;\n }\n if (child === \"appearance\") {\n const keys = [\"defaultTheme\", \"radius\", \"shadow\", \"motion\", \"density\"] as const;\n return keys.flatMap((key) => {\n const left = published.appearance?.[key] ?? \"\";\n const right = incoming.appearance?.[key] ?? \"\";\n return left === right ? [] : [`${key}: ${left || \"—\"} → ${right || \"—\"}`];\n });\n }\n const lines: string[] = [];\n if (uploadId(published.logo) !== uploadId(incoming.logo)) lines.push(\"Logo updated\");\n if (uploadId(published.favicon) !== uploadId(incoming.favicon)) lines.push(\"Favicon updated\");\n if (uploadId(published.logoMark) !== uploadId(incoming.logoMark)) lines.push(\"Mobile menu logo updated\");\n return lines;\n}\n\nfunction uploadId(value: ThemeDoc[\"logo\"]): string {\n if (value && typeof value === \"object\" && value.id != null) return String(value.id);\n if (typeof value === \"string\" || typeof value === \"number\") return String(value);\n return \"\";\n}\n","import type { ThemeDoc } from \"./types\";\n\nexport const THEME_CHILDREN = [\"colors\", \"typography\", \"appearance\", \"identity\"] as const;\n\nexport type ThemeChild = (typeof THEME_CHILDREN)[number];\n\n/**\n * Publishing a child writes that slice only. Other responsibilities stay\n * as they already are on the stored document. Unsaved form state on a\n * different child never goes live. A first save (no stored row) still\n * writes only the named child; `getPublishedTheme` fills the rest from\n * the seed.\n */\nexport function publishThemeChild(stored: ThemeDoc, incoming: ThemeDoc, child: ThemeChild): ThemeDoc {\n if (child === \"colors\") return { ...stored, colors: incoming.colors };\n if (child === \"typography\") return { ...stored, typography: incoming.typography };\n if (child === \"appearance\") return { ...stored, appearance: incoming.appearance };\n return { ...stored, logo: incoming.logo, favicon: incoming.favicon, logoMark: incoming.logoMark };\n}\n\nexport function isThemeChild(value: unknown): value is ThemeChild {\n return typeof value === \"string\" && (THEME_CHILDREN as readonly string[]).includes(value);\n}\n","import type { FillLabelWarning } from \"../theme/readability\";\nimport {\n hardToReadModes,\n hslCss,\n READABILITY_PUBLISH_NOTE,\n readabilityHeadline,\n} from \"../theme/readability\";\n\nexport interface PublishConfirmProps {\n childLabel: string;\n changes: string[];\n shorts?: FillLabelWarning[];\n onKeepEditing: () => void;\n onPublish: () => void;\n busy?: boolean;\n}\n\nconst OTHER_CHILDREN: Record<string, string> = {\n Colors: \"Typography, Appearance, and Identity stay as they are.\",\n Typography: \"Colors, Appearance, and Identity stay as they are.\",\n Appearance: \"Colors, Typography, and Identity stay as they are.\",\n Identity: \"Colors, Typography, and Appearance stay as they are.\",\n};\n\nexport function PublishConfirm({\n childLabel,\n changes,\n shorts,\n onKeepEditing,\n onPublish,\n busy,\n}: PublishConfirmProps) {\n const remaining = shorts?.filter((item) => !item.meets) ?? [];\n return (\n <div className=\"bl-publish\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"bl-publish-title\">\n <div className=\"bl-publish__panel\">\n <h2 id=\"bl-publish-title\">Publish {childLabel}</h2>\n <p>\n These {childLabel.toLowerCase()} changes go live now.{\" \"}\n {OTHER_CHILDREN[childLabel] ?? \"The other Theme sections stay as they are.\"}\n </p>\n {changes.length === 0 ? (\n <p className=\"bl-publish__empty\">No changes to publish.</p>\n ) : (\n <ul>\n {changes.map((change) => (\n <li key={change}>{change}</li>\n ))}\n </ul>\n )}\n {remaining.length > 0 ? (\n <div className=\"bl-publish__shorts\">\n <strong>Some colors may be hard to read</strong>\n <ul>\n {remaining.map((item) => (\n <li key={item.id}>\n <span\n aria-hidden=\"true\"\n className=\"bl-publish__swatch\"\n style={{ background: hslCss(item.light.fill), color: hslCss(item.light.label) }}\n >\n Aa\n </span>\n <span>\n {readabilityHeadline(item).replace(/^Text on /, \"\")} {hardToReadModes(item)}.\n </span>\n </li>\n ))}\n </ul>\n <p>{READABILITY_PUBLISH_NOTE}</p>\n </div>\n ) : null}\n <div className=\"bl-publish__actions\">\n <button type=\"button\" onClick={onKeepEditing}>\n Keep editing\n </button>\n <button type=\"button\" disabled={busy || changes.length === 0} onClick={onPublish}>\n {remaining.length > 0 ? \"Publish anyway\" : \"Publish\"}\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nexport const PUBLISH_CONFIRM_CSS = `\n.bl-publish{position:fixed;inset:0;z-index:80;display:grid;place-items:center;padding:1rem;background:rgba(15,23,42,.45)}\n.bl-publish__panel{width:min(36rem,100%);padding:1.25rem 1.35rem;border-radius:16px;background:#fff;color:#0f172a;box-shadow:0 24px 60px rgba(15,23,42,.2)}\n.bl-publish__panel h2{margin:0}\n.bl-publish__panel p{margin:.5rem 0 0;color:#475569}\n.bl-publish__empty{font-style:italic}\n.bl-publish__panel > ul{margin:.75rem 0 0;padding-left:1.1rem}\n.bl-publish__shorts{margin-top:1rem;padding:.85rem .9rem;border-radius:10px;background:#fffbeb}\n.bl-publish__shorts strong{display:block}\n.bl-publish__shorts ul{margin:.65rem 0 0;padding:0;list-style:none}\n.bl-publish__shorts li{display:flex;gap:.65rem;align-items:center;margin-top:.45rem;font-size:13px}\n.bl-publish__swatch{flex:none;display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:1.6rem;border-radius:6px;font-weight:700;font-size:12px}\n.bl-publish__shorts p{margin:.65rem 0 0;font-size:13px}\n.bl-publish__actions{display:flex;justify-content:flex-end;gap:.6rem;margin-top:1.1rem}\n.bl-publish__actions button{min-height:2.25rem;padding:.4rem .9rem;border-radius:8px;border:1px solid #cbd5e1;background:#fff;font:inherit;cursor:pointer}\n.bl-publish__actions button:last-child{border:0;background:#0f172a;color:#fff;font-weight:600}\n.bl-publish__actions button:disabled{opacity:.45;cursor:not-allowed}\n`;\n","import { THEME_CHILDREN, type ThemeChild } from \"../theme/publish\";\n\nexport const THEME_TAB_LABELS = {\n colors: \"Colors\",\n typography: \"Typography\",\n appearance: \"Appearance\",\n identity: \"Identity\",\n} as const satisfies Record<ThemeChild, string>;\n\n/**\n * The selected Payload field tab on Theme. Defaults to Colors when the\n * tabs have not painted yet (SSR, first paint).\n */\nexport function readActiveThemeTab(root: ParentNode | null | undefined = typeof document === \"undefined\" ? null : document): ThemeChild {\n if (!root) return \"colors\";\n const selected =\n root.querySelector('.tabs-field__tab-button[aria-selected=\"true\"]') ??\n root.querySelector(\".tabs-field__tab-button--active\") ??\n root.querySelector('[role=\"tab\"][aria-selected=\"true\"]');\n const text = selected?.textContent?.replace(/\\s+/g, \" \").trim();\n return THEME_CHILDREN.find((id) => THEME_TAB_LABELS[id] === text) ?? \"colors\";\n}\n","import { useField, useForm, useFormFields } from \"@payloadcms/ui\";\nimport type { UIFieldClientComponent } from \"payload\";\nimport { useMemo, useState } from \"react\";\n\nimport { SYSTEM_COLOR_COPY } from \"../theme/appearance-labels\";\nimport { libraryRows, themeChildChanges } from \"../theme/changes\";\nimport { isThemeChild, type ThemeChild } from \"../theme/publish\";\nimport { fillLabelWarning, type FillLabelWarning } from \"../theme/readability\";\nimport { SYSTEM_COLOR_KEYS, type ThemeColorDoc, type ThemeDoc, type ThemeLibraryColorDoc } from \"../theme/types\";\nimport { ThemePreviewToggle, THEME_PREVIEW_TOGGLE_CSS } from \"./preview-mode\";\nimport { PublishConfirm, PUBLISH_CONFIRM_CSS } from \"./publish-confirm\";\nimport { THEME_TAB_LABELS } from \"./theme-tab\";\n\nfunction asColor(value: unknown): ThemeColorDoc | undefined {\n if (value && typeof value === \"object\") return value as ThemeColorDoc;\n if (typeof value === \"string\") return { hex: value };\n return undefined;\n}\n\nfunction formDoc(fields: Record<string, { value?: unknown } | undefined>): ThemeDoc {\n const brand = Object.fromEntries(\n SYSTEM_COLOR_KEYS.map((key) => [\n key,\n {\n hex: fields[`colors.brand.${key}.hex`]?.value as string | undefined,\n sourceStep: fields[`colors.brand.${key}.sourceStep`]?.value as ThemeColorDoc[\"sourceStep\"],\n },\n ]),\n ) as NonNullable<NonNullable<ThemeDoc[\"colors\"]>[\"brand\"]>;\n return {\n colors: {\n brand,\n library: libraryRows(fields[\"colors.library\"]?.value),\n greyScale: fields[\"colors.greyScale\"]?.value as NonNullable<ThemeDoc[\"colors\"]>[\"greyScale\"],\n },\n typography: {\n body: fields[\"typography.body\"]?.value as string | undefined,\n heading: fields[\"typography.heading\"]?.value as string | undefined,\n },\n appearance: {\n defaultTheme: fields[\"appearance.defaultTheme\"]?.value as NonNullable<ThemeDoc[\"appearance\"]>[\"defaultTheme\"],\n radius: fields[\"appearance.radius\"]?.value as NonNullable<ThemeDoc[\"appearance\"]>[\"radius\"],\n shadow: fields[\"appearance.shadow\"]?.value as NonNullable<ThemeDoc[\"appearance\"]>[\"shadow\"],\n motion: fields[\"appearance.motion\"]?.value as NonNullable<ThemeDoc[\"appearance\"]>[\"motion\"],\n density: fields[\"appearance.density\"]?.value as NonNullable<ThemeDoc[\"appearance\"]>[\"density\"],\n },\n logo: fields.logo?.value as ThemeDoc[\"logo\"],\n favicon: fields.favicon?.value as ThemeDoc[\"favicon\"],\n logoMark: fields.logoMark?.value as ThemeDoc[\"logoMark\"],\n };\n}\n\nfunction publishedDoc(fields: Record<string, { initialValue?: unknown; value?: unknown } | undefined>): ThemeDoc {\n return formDoc(\n Object.fromEntries(Object.entries(fields).map(([path, field]) => [path, { value: field?.initialValue }])),\n );\n}\n\nfunction shortsFrom(doc: ThemeDoc): FillLabelWarning[] {\n const brand = doc.colors?.brand ?? {};\n const custom = libraryRows(doc.colors?.library);\n return [\n ...SYSTEM_COLOR_KEYS.flatMap((key) => {\n const hex = asColor(brand[key])?.hex;\n const warning = typeof hex === \"string\" ? fillLabelWarning(key, SYSTEM_COLOR_COPY[key].label, hex) : null;\n return warning ? [warning] : [];\n }),\n ...custom.flatMap((row, index) => {\n const warning = row.hex ? fillLabelWarning(`library-${index}`, row.label ?? row.key ?? \"Custom\", row.hex) : null;\n return warning ? [warning] : [];\n }),\n ];\n}\n\n/**\n * Publish for the open Theme tab. Lives in Payload's document Save\n * slot (`ThemeSaveButton`) so the header matches a Pages document.\n * Sets `publishChild` then submits; `beforeChange` writes only that slice.\n */\nexport function ThemePublishControls({ child }: { child: ThemeChild }) {\n const label = THEME_TAB_LABELS[child];\n const { submit } = useForm();\n const publishChild = useField<string>({ path: \"publishChild\" });\n const snapshot = useFormFields(([fields]) => {\n const record = fields as Record<string, { initialValue?: unknown; value?: unknown } | undefined>;\n return { incoming: formDoc(record), published: publishedDoc(record) };\n });\n const [open, setOpen] = useState(false);\n const [busy, setBusy] = useState(false);\n\n const changes = useMemo(\n () => themeChildChanges(child, snapshot.published, snapshot.incoming),\n [child, snapshot],\n );\n const shorts = child === \"colors\" ? shortsFrom(snapshot.incoming) : undefined;\n\n async function publish() {\n setBusy(true);\n publishChild.setValue(child);\n try {\n await submit();\n setOpen(false);\n } finally {\n setBusy(false);\n }\n }\n\n return (\n <div className=\"bl-publish-child\">\n <style href=\"bl-publish\" precedence=\"default\">\n {PUBLISH_CONFIRM_CSS}\n </style>\n <style href=\"bl-publish-child\" precedence=\"default\">\n {`${THEME_PREVIEW_TOGGLE_CSS}.bl-publish-child{display:flex;align-items:center;gap:.75rem}.bl-publish-child__button{min-height:2.25rem;padding:.4rem 1rem;border:0;border-radius:8px;background:#a80063;color:#fff;font:inherit;font-weight:600;cursor:pointer}`}\n </style>\n {child === \"colors\" ? <ThemePreviewToggle /> : null}\n <button type=\"button\" className=\"bl-publish-child__button\" onClick={() => setOpen(true)}>\n Publish {label}\n </button>\n {open ? (\n <PublishConfirm\n childLabel={label}\n changes={changes}\n shorts={shorts}\n busy={busy}\n onKeepEditing={() => setOpen(false)}\n onPublish={() => {\n void publish();\n }}\n />\n ) : null}\n </div>\n );\n}\n\n/** @deprecated Theme publish is the document Save button */\nexport const PublishChild: UIFieldClientComponent = ({ field }) => {\n const child = (field.admin?.custom as { child?: string } | undefined)?.child;\n return <ThemePublishControls child={isThemeChild(child) ? child : \"colors\"} />;\n};\n","import { useEffect, useState } from \"react\";\n\nimport type { ThemeChild } from \"../theme/publish\";\nimport { ThemePublishControls } from \"./publish-child\";\nimport { readActiveThemeTab } from \"./theme-tab\";\n\n/**\n * Payload's document Save slot — the same control row as Pages'\n * \"Publish changes\". Theme has no drafts; this publishes only the\n * open field tab. The tab is read after mount so SSR matches.\n */\nexport function ThemeSaveButton() {\n const [child, setChild] = useState<ThemeChild>(\"colors\");\n\n useEffect(() => {\n const sync = () => setChild(readActiveThemeTab());\n sync();\n const tabs = document.querySelector(\".tabs-field\");\n const target = tabs ?? document.body;\n const observer = new MutationObserver(sync);\n observer.observe(target, {\n subtree: true,\n attributes: true,\n attributeFilter: [\"aria-selected\", \"class\"],\n childList: true,\n });\n target.addEventListener(\"click\", sync);\n return () => {\n observer.disconnect();\n target.removeEventListener(\"click\", sync);\n };\n }, []);\n\n return <ThemePublishControls child={child} />;\n}\n\n/** Import-map alias — Theme still points `SaveButton` at this name. */\nexport const HiddenSaveButton = ThemeSaveButton;\n","import type { UIFieldClientComponent } from \"payload\";\n\nimport type { ThemeIdentityFallback } from \"../theme/identity\";\n\n/**\n * Identity child when the site has not registered a cupboard yet.\n * Shows the fallback lockup and mark; uploads wait on `logo.collection`.\n */\nexport const IdentityFallback: UIFieldClientComponent = ({ field }) => {\n const fallback = (field.admin?.custom as { fallback?: ThemeIdentityFallback } | undefined)?.fallback;\n return (\n <section className=\"bl-identity-fallback\">\n <style href=\"bl-identity-fallback\" precedence=\"default\">\n {CSS}\n </style>\n <header>\n <h2>Site identity</h2>\n <p>Today&apos;s lockup and mark until a brand editor uploads replacements.</p>\n </header>\n <div className=\"bl-identity-fallback__grid\">\n {fallback?.lockup ? (\n <figure>\n <img src={fallback.lockup.url} alt={fallback.lockup.alt} />\n <figcaption>Lockup</figcaption>\n </figure>\n ) : null}\n {fallback?.mark ? (\n <figure>\n <img src={fallback.mark.url} alt={fallback.mark.alt} />\n <figcaption>Mark</figcaption>\n </figure>\n ) : null}\n </div>\n </section>\n );\n};\n\nconst CSS = `\n.bl-identity-fallback header h2{margin:0;font-size:1.1rem}\n.bl-identity-fallback header p{margin:.35rem 0 1rem;color:var(--theme-elevation-600,#475569)}\n.bl-identity-fallback__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));gap:1rem}\n.bl-identity-fallback figure{margin:0;padding:1rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:10px;background:var(--theme-elevation-50,#f8fafc)}\n.bl-identity-fallback img{display:block;max-width:100%;height:4rem;object-fit:contain}\n.bl-identity-fallback figcaption{margin-top:.5rem;font-size:.8rem;color:var(--theme-elevation-600,#475569)}\n`;\n"],"mappings":"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"}
1
+ {"version":3,"file":"admin.mjs","names":["CSS","CSS","CSS","CSS"],"sources":["../src/admin/color-field.tsx","../src/theme/appearance-labels.ts","../src/theme/readability.ts","../src/admin/colors-layout.ts","../src/admin/portal.tsx","../src/admin/preview-mode.tsx","../src/admin/readability-list.tsx","../src/admin/color-scale-card.tsx","../src/admin/color-scale-field.tsx","../src/theme/library.ts","../src/admin/library-field.tsx","../src/admin/typography-pairing.tsx","../src/admin/font-field.tsx","../src/admin/pairing-field.tsx","../src/admin/appearance-choices.tsx","../src/admin/appearance-field.tsx","../src/admin/grey-scale-field.tsx","../src/admin/contrast-report.tsx","../src/admin/section-heading.tsx","../src/theme/changes.ts","../src/theme/publish.ts","../src/admin/publish-confirm.tsx","../src/admin/publish-child.tsx","../src/admin/theme-tab.ts","../src/admin/save-button.tsx","../src/admin/identity-fallback.tsx","../src/admin/look-field.tsx","../src/roles/types.ts","../src/roles/matrix.ts","../src/admin/roles-matrix-field.tsx","../src/admin/roles-field.tsx"],"sourcesContent":["import { FieldDescription, FieldError, FieldLabel, useField } from \"@payloadcms/ui\";\nimport { isThemeHex } from \"@bison-lab/tokens\";\nimport type { TextFieldClientComponent } from \"payload\";\nimport { useEffect, useId, useState } from \"react\";\n\nconst HEX_ERROR = \"Enter a six-digit hex colour like #1e3a5f\";\n\n/**\n * Swatch, native colour input, and hex text, kept in step. `#rrggbb` on\n * blur; the field's `validate` refuses anything else on save.\n */\nexport const ColorField: TextFieldClientComponent = ({ field, path, readOnly }) => {\n const { value, setValue, showError, errorMessage } = useField<string>({ path });\n const [text, setText] = useState(value ?? \"\");\n const [localError, setLocalError] = useState<string | null>(null);\n const id = useId();\n const hexId = `${id}-hex`;\n const pickerId = `${id}-picker`;\n const required = Boolean(field.required);\n const valid = isThemeHex(value);\n const message = localError ?? errorMessage;\n const show = Boolean(localError) || showError;\n\n useEffect(() => {\n setText(value ?? \"\");\n }, [value]);\n\n function commit(next: string) {\n const trimmed = next.trim();\n if (isThemeHex(trimmed)) {\n setValue(trimmed);\n setLocalError(null);\n return;\n }\n setLocalError(HEX_ERROR);\n }\n\n return (\n <div className=\"field-type bl-color-field\">\n <style href=\"bl-color-field\" precedence=\"default\">\n {CSS}\n </style>\n <FieldLabel htmlFor={hexId} label={field.label} required={required} />\n <div className=\"bl-color-field__control\">\n <span\n className=\"bl-color-field__swatch\"\n aria-hidden=\"true\"\n style={{ background: valid ? value : \"transparent\" }}\n />\n <input\n id={pickerId}\n type=\"color\"\n className=\"bl-color-field__picker\"\n disabled={readOnly}\n value={valid ? value : \"#000000\"}\n aria-label={`${typeof field.label === \"string\" ? field.label : \"Colour\"} picker`}\n onChange={(event) => {\n setValue(event.target.value);\n setText(event.target.value);\n setLocalError(null);\n }}\n />\n <input\n id={hexId}\n type=\"text\"\n className=\"bl-color-field__hex\"\n spellCheck={false}\n autoComplete=\"off\"\n disabled={readOnly}\n value={text}\n onChange={(event) => {\n setText(event.target.value);\n if (isThemeHex(event.target.value.trim())) {\n setValue(event.target.value.trim());\n setLocalError(null);\n }\n }}\n onBlur={() => commit(text)}\n />\n </div>\n <FieldDescription description={field.admin?.description} path={path} />\n <FieldError path={path} showError={show} message={message} />\n </div>\n );\n};\n\nconst CSS = `\n.bl-color-field__control{display:flex;align-items:center;gap:calc(var(--base) * .4)}\n.bl-color-field__swatch{flex:none;width:calc(var(--base) * 1.6);height:calc(var(--base) * 1.6);border:1px solid var(--theme-elevation-150);border-radius:var(--style-radius-s);background:var(--theme-elevation-50)}\n.bl-color-field__picker{flex:none;width:calc(var(--base) * 2);height:calc(var(--base) * 2);padding:0;border:1px solid var(--theme-elevation-150);border-radius:var(--style-radius-s);background:transparent;cursor:pointer}\n.bl-color-field__picker:disabled{cursor:not-allowed;opacity:.6}\n.bl-color-field__hex{flex:1;min-width:0;min-height:calc(var(--base) * 2);padding:calc(var(--base) * .25) calc(var(--base) * .6);border:1px solid var(--theme-elevation-150);border-radius:var(--style-radius-s);background:var(--theme-input-bg);color:var(--theme-elevation-800);font-family:var(--font-mono);font-size:13px}\n.bl-color-field__hex:focus{border-color:var(--theme-elevation-400);outline:none;box-shadow:0 0 0 1px var(--theme-elevation-400)}\n.bl-color-field__hex:disabled{color:var(--theme-elevation-400)}\n`;\n","/**\n * Named choices the Appearance child shows. Values stay the token presets;\n * labels match the mock workflow (Soft → pill, Gentle → minimal, Balanced\n * → default, Follow device → system). No rem, ms, or CSS variable tables.\n */\nexport const APPEARANCE_CHOICES = {\n defaultTheme: {\n light: { label: \"Light\", hint: \"Always opens in light mode\" },\n dark: { label: \"Dark\", hint: \"Always opens in dark mode\" },\n system: { label: \"Follow device\", hint: \"Matches the visitor’s system setting\" },\n },\n radius: {\n sharp: { label: \"Sharp\", hint: \"Crisp and structured\" },\n subtle: { label: \"Subtle\", hint: \"Clean with a little softness\" },\n rounded: { label: \"Rounded\", hint: \"Friendly and contemporary\" },\n pill: { label: \"Soft\", hint: \"Very rounded and expressive\" },\n },\n shadow: {\n flat: { label: \"Flat\", hint: \"Minimal visual depth\" },\n subtle: { label: \"Subtle\", hint: \"Light separation between surfaces\" },\n elevated: { label: \"Elevated\", hint: \"More noticeable layering and depth\" },\n },\n motion: {\n snappy: { label: \"Quick\", hint: \"Fast and responsive\" },\n smooth: { label: \"Smooth\", hint: \"Balanced and natural\" },\n minimal: { label: \"Gentle\", hint: \"Slower and more relaxed\" },\n },\n density: {\n compact: { label: \"Compact\", hint: \"Fits more content on screen\" },\n default: { label: \"Balanced\", hint: \"Comfortable for most sites\" },\n spacious: { label: \"Spacious\", hint: \"More breathing room and larger controls\" },\n },\n} as const;\n\nexport const APPEARANCE_FAMILY_COPY: Record<\n keyof typeof APPEARANCE_CHOICES,\n { title: string; hint: string }\n> = {\n defaultTheme: {\n title: \"Default theme\",\n hint: \"Choose how the public site opens for visitors.\",\n },\n radius: {\n title: \"Corner style\",\n hint: \"Controls the shape of buttons, inputs, cards, and panels across the site.\",\n },\n shadow: {\n title: \"Depth\",\n hint: \"Choose how much cards and floating elements stand out from the page.\",\n },\n motion: {\n title: \"Motion\",\n hint: \"Controls how quickly menus, cards, and interface transitions move.\",\n },\n density: {\n title: \"Spacing\",\n hint: \"Choose how compact or roomy forms, buttons, cards, and page sections feel.\",\n },\n};\n\nexport const FONT_ROLE_COPY = {\n heading: {\n label: \"Heading font\",\n hint: \"Used for page titles, section headings, and cards\",\n },\n body: {\n label: \"Body font\",\n hint: \"Used for paragraphs, navigation, forms, and buttons\",\n },\n} as const;\n\nexport const SYSTEM_COLOR_COPY: Record<\n \"primary\" | \"secondary\" | \"accent\" | \"highlight\" | \"success\" | \"destructive\",\n { label: string; hint: string; group: \"brand\" | \"status\" }\n> = {\n primary: { label: \"Primary\", hint: \"Primary actions and key links\", group: \"brand\" },\n secondary: { label: \"Secondary\", hint: \"Supporting accents and eyebrows\", group: \"brand\" },\n accent: { label: \"Accent\", hint: \"Dark brand surfaces\", group: \"brand\" },\n highlight: { label: \"Highlight\", hint: \"Promotional and emphasis fills\", group: \"brand\" },\n success: {\n label: \"Success\",\n hint: \"Success messages and confirmations\",\n group: \"status\",\n },\n destructive: {\n label: \"Destructive\",\n hint: \"Errors, dangerous actions, and destructive confirmations\",\n group: \"status\",\n },\n};\n","import {\n contrastForeground,\n contrastRatio,\n hexToHSL,\n hslToString,\n isThemeHex,\n type HSL,\n} from \"@bison-lab/tokens\";\n\n/** Same threshold `deriveDarkPalette` uses for brand fills. */\nconst DARK_FILL_LIGHTEN_BELOW = 40;\nconst DARK_FILL_LIGHTEN_BY = 25;\n\nexport const READABILITY_TARGET = 7;\n\nexport interface FillLabelSample {\n ratio: number;\n shortfall: number;\n fill: string;\n label: string;\n}\n\nexport interface FillLabelWarning {\n id: string;\n name: string;\n light: FillLabelSample;\n dark: FillLabelSample;\n /** Both modes at or above the target. */\n meets: boolean;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\nfunction darkFill(color: HSL): HSL {\n if (color.l < DARK_FILL_LIGHTEN_BELOW) {\n return { ...color, l: clamp(color.l + DARK_FILL_LIGHTEN_BY, 0, 100) };\n }\n return color;\n}\n\nfunction sample(fill: HSL, target: number): FillLabelSample {\n const label = contrastForeground(fill);\n const fillCss = hslToString(fill);\n const ratio = contrastRatio(fillCss, label);\n return {\n ratio,\n shortfall: Math.max(0, Math.round((target - ratio) * 100) / 100),\n fill: fillCss,\n label,\n };\n}\n\n/**\n * Editable fill + the automatic label, Light and Dark. Target 7:1.\n * Meets only when both pass. Warnings do not block save.\n */\nexport function fillLabelWarning(\n id: string,\n name: string,\n hex: string,\n target = READABILITY_TARGET,\n): FillLabelWarning | null {\n if (!isThemeHex(hex)) return null;\n const lightFill = hexToHSL(hex);\n const light = sample(lightFill, target);\n const dark = sample(darkFill(lightFill), target);\n return { id, name, light, dark, meets: light.ratio >= target && dark.ratio >= target };\n}\n\n/** Green/teal family. A warning at admin time, not a schema block. */\nexport function successHueWarning(hex: string): string | null {\n if (!isThemeHex(hex)) return null;\n const { h } = hexToHSL(hex);\n if (h >= 80 && h <= 180) return null;\n return \"Keep success colors recognizable — stay in a green or teal family.\";\n}\n\n/** Red family. A warning at admin time, not a schema block. */\nexport function destructiveHueWarning(hex: string): string | null {\n if (!isThemeHex(hex)) return null;\n const { h } = hexToHSL(hex);\n if (h <= 30 || h >= 330) return null;\n return \"Keep destructive colors recognizable — stay in a red family.\";\n}\n\nexport function automaticLabel(hex: string): string | null {\n if (!isThemeHex(hex)) return null;\n return contrastForeground(hexToHSL(hex));\n}\n\nexport function hslCss(value: string): string {\n return `hsl(${value})`;\n}\n\n/** Which appearances fail, in words. Empty when both pass. */\nexport function hardToReadModes(item: FillLabelWarning): string {\n const light = item.light.shortfall > 0;\n const dark = item.dark.shortfall > 0;\n if (light && dark) return \"in Light and Dark\";\n if (light) return \"in Light\";\n if (dark) return \"in Dark\";\n return \"\";\n}\n\nexport function readabilityHeadline(item: FillLabelWarning): string {\n return item.meets ? `Text on ${item.name} looks readable` : `Text on ${item.name} may be hard to read`;\n}\n\nexport function readabilityModesLine(item: FillLabelWarning): string {\n const modes = hardToReadModes(item);\n return modes ? `Hard to read ${modes}.` : \"Looks good in Light and Dark.\";\n}\n\nexport function readabilityGapPercent(sample: FillLabelSample, target = READABILITY_TARGET): number {\n if (sample.shortfall <= 0) return 0;\n return Math.round((sample.shortfall / target) * 100);\n}\n\nexport function readabilityRatioLine(sample: FillLabelSample, target = READABILITY_TARGET): string {\n const percent = readabilityGapPercent(sample, target);\n if (percent <= 0) return \"Meets the contrast we want\";\n if (percent < 10) return \"A little short of the contrast we want\";\n return `About ${percent}% short of the contrast we want`;\n}\n\nexport const READABILITY_FIX =\n \"Darken or lighten the hex, then regenerate the scale. The site picks light or dark type for you.\";\n\nexport const READABILITY_PUBLISH_NOTE =\n \"You can still publish. To improve a color, darken or lighten it and regenerate.\";\n","/**\n * Theme Colors tab chrome. Payload group-in-group draws a left gutter;\n * the mockup does not. Brand cards sit two-up. Light / Dark lives on the\n * cards only — the field list stays Payload chrome.\n */\nexport const THEME_COLORS_LAYOUT_CSS = `\n.group-field--gutter:has(.bl-scale-field),\n.group-field--gutter:has(.bl-section-heading),\n.group-field--gutter:has(.bl-grey),\n.group-field--gutter:has(.bl-library){\n border-left:none;\n padding-left:0;\n}\n.render-fields:has(> .bl-scale-field),\n.render-fields:has(> .field-type.bl-scale-field){\n display:grid;\n grid-template-columns:minmax(0,1fr) minmax(0,1fr);\n gap:1rem;\n align-items:start;\n}\n.render-fields:has(> .bl-scale-field) > .bl-section-heading,\n.render-fields:has(> .field-type.bl-scale-field) > .bl-section-heading,\n.render-fields:has(> .bl-scale-field) > :has(.bl-section-heading),\n.render-fields:has(> .field-type.bl-scale-field) > :has(.bl-section-heading),\n.render-fields:has(> .bl-scale-field) > .bl-library,\n.render-fields:has(> .field-type.bl-scale-field) > .field-type.bl-library,\n.render-fields:has(> .bl-scale-field) > :has(.bl-library),\n.render-fields:has(> .field-type.bl-scale-field) > :has(.bl-library),\n.render-fields:has(> .bl-scale-field) > :has(.bl-grey),\n.render-fields:has(> .field-type.bl-scale-field) > :has(.bl-grey){\n grid-column:1/-1;\n}\n@media (max-width:860px){\n .render-fields:has(> .bl-scale-field),\n .render-fields:has(> .field-type.bl-scale-field){\n grid-template-columns:1fr;\n }\n}\n`;\n","import type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\n\n/** Theme overlays must leave Payload's transformed/clipped admin tree. */\nexport function ThemePortal({ children }: { children: ReactNode }) {\n if (typeof document === \"undefined\") return null;\n return createPortal(children, document.body);\n}\n","import { useFormFields } from \"@payloadcms/ui\";\nimport {\n deriveDarkPalette,\n deriveLightPalette,\n type GreyScale,\n} from \"@bison-lab/tokens\";\nimport { useEffect, useState, type CSSProperties } from \"react\";\n\nexport type ThemePreviewMode = \"light\" | \"dark\";\n\nconst ATTR = \"data-bl-theme-preview\";\nconst EVENT = \"bl-theme-preview\";\nconst PREVIEW_VARS = [\n \"--bl-preview-bg\",\n \"--bl-preview-card\",\n \"--bl-preview-border\",\n \"--bl-preview-text\",\n \"--bl-preview-muted\",\n \"--bl-preview-input\",\n] as const;\n\n/** Brand hexes do not affect grey-driven surfaces; derive still requires them. */\nconst PREVIEW_BRAND = { primary: \"#111111\", secondary: \"#111111\", success: \"#111111\" } as const;\n\nlet currentMode: ThemePreviewMode = \"light\";\n\nfunction readMode(): ThemePreviewMode {\n return currentMode;\n}\n\n/** Drop leftovers from the old html-wide preview so Payload chrome stays Payload. */\nfunction clearDocumentPreview() {\n if (typeof document === \"undefined\") return;\n document.documentElement.removeAttribute(ATTR);\n for (const name of PREVIEW_VARS) document.documentElement.style.removeProperty(name);\n}\n\nexport function setThemePreviewMode(mode: ThemePreviewMode) {\n currentMode = mode;\n clearDocumentPreview();\n if (typeof window !== \"undefined\") window.dispatchEvent(new Event(EVENT));\n}\n\nexport function useThemePreviewMode(): ThemePreviewMode {\n const [mode, setMode] = useState<ThemePreviewMode>(readMode);\n useEffect(() => {\n clearDocumentPreview();\n const sync = () => setMode(readMode());\n sync();\n window.addEventListener(EVENT, sync);\n return () => window.removeEventListener(EVENT, sync);\n }, []);\n return mode;\n}\n\nexport function previewVarsFor(grey: GreyScale, mode: ThemePreviewMode) {\n const palette =\n mode === \"dark\"\n ? deriveDarkPalette({ ...PREVIEW_BRAND, grey })\n : deriveLightPalette({ ...PREVIEW_BRAND, grey });\n return {\n \"--bl-preview-bg\": `hsl(${palette.background})`,\n \"--bl-preview-card\": `hsl(${palette.card})`,\n \"--bl-preview-border\": `hsl(${palette.border})`,\n \"--bl-preview-text\": `hsl(${palette.foreground})`,\n \"--bl-preview-muted\": `hsl(${palette[\"muted-foreground\"]})`,\n \"--bl-preview-input\": `hsl(${palette.input})`,\n } satisfies Record<(typeof PREVIEW_VARS)[number], string>;\n}\n\nfunction useGreyScale(): GreyScale {\n return useFormFields(([fields]) => {\n const value = fields[\"colors.greyScale\"]?.value;\n return value === \"gray\" ||\n value === \"zinc\" ||\n value === \"neutral\" ||\n value === \"stone\" ||\n value === \"slate\"\n ? value\n : \"slate\";\n });\n}\n\n/**\n * Light / Dark + the live grey family, applied on each Theme field canvas.\n * Never writes to `documentElement` — nav, tabs, and Publish stay Payload.\n */\nexport function usePreviewCanvas() {\n const mode = useThemePreviewMode();\n const greyScale = useGreyScale();\n return {\n mode,\n className: \"bl-preview-canvas\",\n style: previewVarsFor(greyScale, mode) as CSSProperties,\n };\n}\n\nexport function ThemePreviewToggle() {\n const mode = useThemePreviewMode();\n return (\n <div className=\"bl-preview-toggle\" role=\"group\" aria-label=\"Preview theme in\">\n <button type=\"button\" data-on={mode === \"light\" ? \"\" : undefined} onClick={() => setThemePreviewMode(\"light\")}>\n Light\n </button>\n <button type=\"button\" data-on={mode === \"dark\" ? \"\" : undefined} onClick={() => setThemePreviewMode(\"dark\")}>\n Dark\n </button>\n </div>\n );\n}\n\nexport const THEME_PREVIEW_TOGGLE_CSS = `\n.bl-preview-toggle{display:inline-flex;padding:3px;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:10px;background:var(--theme-elevation-0,#fff)}\n.bl-preview-toggle button{min-height:2rem;padding:.25rem .75rem;border:0;border-radius:7px;background:transparent;color:var(--theme-elevation-600,#475569);font:inherit;font-size:13px;font-weight:600;cursor:pointer}\n.bl-preview-toggle button[data-on]{background:var(--theme-text,#0f172a);color:var(--theme-bg,#fff)}\n`;\n","import type { FillLabelWarning } from \"../theme/readability\";\nimport {\n hslCss,\n READABILITY_FIX,\n READABILITY_TARGET,\n readabilityHeadline,\n readabilityModesLine,\n readabilityRatioLine,\n} from \"../theme/readability\";\n\nexport function ReadabilityDetail({\n item,\n target = READABILITY_TARGET,\n}: {\n item: FillLabelWarning;\n target?: number;\n}) {\n return (\n <div className=\"bl-readability-detail\">\n <p className=\"bl-readability-detail__lead\">{readabilityModesLine(item)}</p>\n <div className=\"bl-readability-detail__modes\">\n {(\n [\n [\"Light\", item.light],\n [\"Dark\", item.dark],\n ] as const\n ).map(([mode, sample]) => (\n <figure key={mode} data-failing={sample.shortfall > 0 ? \"\" : undefined}>\n <span\n aria-hidden=\"true\"\n className=\"bl-readability__swatch\"\n style={{ background: hslCss(sample.fill), color: hslCss(sample.label) }}\n >\n Aa\n </span>\n <figcaption>\n <strong>{mode}</strong>\n <span>{sample.shortfall > 0 ? \"Hard to read\" : \"Looks good\"}</span>\n <span>{readabilityRatioLine(sample, target)}</span>\n </figcaption>\n </figure>\n ))}\n </div>\n {item.meets ? null : <p className=\"bl-readability-detail__fix\">{READABILITY_FIX}</p>}\n </div>\n );\n}\n\nexport function ReadabilityList({\n warnings,\n target = READABILITY_TARGET,\n}: {\n warnings: FillLabelWarning[];\n target?: number;\n}) {\n const failing = warnings.filter((item) => !item.meets).length;\n return (\n <section className=\"bl-readability\">\n <div className=\"bl-readability__head\">\n <div>\n <h2>Readability checks</h2>\n <p>Text the site puts on each fill. Warnings do not block save.</p>\n </div>\n <span data-attention={failing ? \"\" : undefined}>\n {failing === 0 ? \"All look readable\" : `${failing} may be hard to read`}\n </span>\n </div>\n <ul>\n {warnings.map((item) => (\n <li key={item.id} data-failing={item.meets ? undefined : \"\"}>\n <strong>{readabilityHeadline(item)}</strong>\n <ReadabilityDetail item={item} target={target} />\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nexport const READABILITY_LIST_CSS = `\n.bl-readability{padding:calc(var(--base,16px) * .8);border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:var(--style-radius-m,12px);background:var(--theme-elevation-0,#fff)}\n.bl-readability__head{display:flex;justify-content:space-between;gap:1rem;align-items:flex-start}\n.bl-readability__head h2{margin:0;font-size:1rem}\n.bl-readability__head p{margin:.35rem 0 0;font-size:12px;color:var(--theme-elevation-500,#64748b)}\n.bl-readability__head span{flex:none;font-size:12px;font-weight:600;padding:.2rem .55rem;border-radius:999px;background:var(--theme-elevation-100,#f1f5f9)}\n.bl-readability__head span[data-attention]{background:#fffbeb;color:#92400e}\n.bl-readability ul{margin:.85rem 0 0;padding:0;list-style:none}\n.bl-readability li{padding:.65rem 0;border-top:1px solid var(--theme-elevation-100,#f1f5f9)}\n.bl-readability li:first-child{border-top:0}\n.bl-readability li[data-failing]{background:#fff7ed;margin:0 -.4rem;padding:.65rem .4rem;border-radius:8px}\n.bl-readability__swatch{flex:none;display:inline-flex;align-items:center;justify-content:center;width:2.75rem;height:2rem;border-radius:6px;font-weight:700;font-size:13px}\n.bl-readability strong{display:block;font-size:13px}\n.bl-readability-detail__lead{margin:0 0 .65rem;font-size:13px;color:var(--theme-elevation-600,#475569)}\n.bl-readability-detail__modes{display:grid;grid-template-columns:1fr 1fr;gap:.65rem}\n.bl-readability-detail__modes figure{display:flex;gap:.6rem;align-items:center;margin:0;padding:.55rem .6rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:10px;background:#fff}\n.bl-readability-detail__modes figure[data-failing]{border-color:#fdba74;background:#fff7ed}\n.bl-readability-detail__modes figcaption{display:flex;flex-direction:column;gap:.1rem;min-width:0}\n.bl-readability-detail__modes figcaption strong{font-size:12px}\n.bl-readability-detail__modes figcaption span{font-size:11px;color:var(--theme-elevation-500,#64748b)}\n.bl-readability-detail__fix{margin:.7rem 0 0;font-size:13px;color:var(--theme-elevation-600,#475569)}\n`;\n","import {\n createColorScale,\n includedShadeSteps,\n isThemeHex,\n setColorScaleInclude,\n SHADE_STEPS,\n type ColorScaleState,\n type ShadeStep,\n} from \"@bison-lab/tokens\";\nimport { useEffect, useId, useState } from \"react\";\n\nimport {\n fillLabelWarning,\n hslCss,\n readabilityHeadline,\n successHueWarning,\n destructiveHueWarning,\n} from \"../theme/readability\";\nimport { THEME_COLORS_LAYOUT_CSS } from \"./colors-layout\";\nimport { ThemePortal } from \"./portal\";\nimport { usePreviewCanvas } from \"./preview-mode\";\nimport { ReadabilityDetail, READABILITY_LIST_CSS } from \"./readability-list\";\n\nexport interface ColorScaleCardProps {\n id?: string;\n name: string;\n hint?: string;\n required?: boolean;\n custom?: boolean;\n state: ColorScaleState;\n onChange: (next: ColorScaleState) => void;\n onDelete?: () => void;\n readOnly?: boolean;\n role?: \"success\" | \"destructive\" | null;\n}\n\nconst STATUS_COPY = {\n success: {\n title: \"Keep success colors recognizable\",\n body: \"Success states should stay in a green or teal family so users can quickly recognize positive outcomes and confirmations.\",\n drift: \"This color may no longer read as a success state.\",\n },\n destructive: {\n title: \"Keep destructive colors recognizable\",\n body: \"Destructive actions should stay in a red or crimson family so users can quickly recognize errors and dangerous actions.\",\n drift: \"This color may no longer read as a destructive or error state.\",\n },\n} as const;\n\nfunction IncludeMark({ on }: { on: boolean }) {\n return (\n <span className=\"bl-scale-card__status\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\">\n {on ? (\n <path\n d=\"M3.5 8.5 6.5 11.5 12.5 4.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n ) : (\n <path\n d=\"M4.5 4.5 11.5 11.5M11.5 4.5 4.5 11.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.4\"\n strokeLinecap=\"round\"\n />\n )}\n </svg>\n </span>\n );\n}\n\nexport function ColorScaleCard({\n id,\n name,\n hint,\n required,\n custom,\n state,\n onChange,\n onDelete,\n readOnly,\n role,\n}: ColorScaleCardProps) {\n const warning = fillLabelWarning(id ?? name.toLowerCase(), name, state.hex);\n const canvas = usePreviewCanvas();\n const [attentionOpen, setAttentionOpen] = useState(false);\n const [shakeStep, setShakeStep] = useState<ShadeStep | null>(null);\n const [hexDraft, setHexDraft] = useState(state.hex);\n const titleId = useId();\n const included = new Set(includedShadeSteps(state));\n const hueDrift =\n role === \"success\"\n ? Boolean(successHueWarning(state.hex))\n : role === \"destructive\"\n ? Boolean(destructiveHueWarning(state.hex))\n : false;\n\n useEffect(() => {\n setHexDraft(state.hex);\n }, [state.hex]);\n\n function commitHex(hex: string) {\n onChange(createColorScale(hex, state.sourceStep, state.include));\n }\n\n function commitStep(step: ShadeStep) {\n onChange(createColorScale(state.hex, step, state.include));\n }\n\n function toggleStep(step: ShadeStep) {\n if (step === state.sourceStep) {\n setShakeStep(step);\n window.setTimeout(() => setShakeStep((was) => (was === step ? null : was)), 180);\n return;\n }\n const next = new Set(included);\n if (next.has(step)) next.delete(step);\n else next.add(step);\n onChange(setColorScaleInclude(state, SHADE_STEPS.filter((item) => next.has(item))));\n }\n\n return (\n <article className={`bl-scale-card ${canvas.className}`} data-preview={canvas.mode} style={canvas.style}>\n <header className=\"bl-scale-card__head\">\n <div>\n <div className=\"bl-scale-card__title-row\">\n <h3 className=\"bl-scale-card__title\">{name}</h3>\n {required ? <span className=\"bl-scale-card__badge\">Required</span> : null}\n {custom ? <span className=\"bl-scale-card__badge\">Optional</span> : null}\n {warning && !warning.meets ? (\n <button\n type=\"button\"\n className=\"bl-scale-card__badge bl-scale-card__badge--attention\"\n aria-haspopup=\"dialog\"\n onClick={() => setAttentionOpen(true)}\n >\n Needs attention\n </button>\n ) : null}\n </div>\n {hint ? <p className=\"bl-scale-card__hint\">{hint}</p> : null}\n </div>\n {onDelete ? (\n <button type=\"button\" className=\"bl-scale-card__delete\" disabled={readOnly} onClick={onDelete}>\n Delete\n </button>\n ) : null}\n </header>\n\n <div className=\"bl-scale-card__row\">\n <div className=\"bl-scale-card__field\">\n <span>Brand hex</span>\n <span className=\"bl-scale-card__hex-wrap\">\n <input\n type=\"color\"\n aria-label={`${name} picker`}\n disabled={readOnly}\n value={isThemeHex(state.hex) ? state.hex : \"#000000\"}\n onPointerDown={(event) => {\n const input = event.currentTarget;\n if (typeof input.showPicker !== \"function\") return;\n event.preventDefault();\n try {\n input.showPicker();\n } catch {\n input.click();\n }\n }}\n onChange={(event) => commitHex(event.target.value)}\n />\n <input\n type=\"text\"\n spellCheck={false}\n autoComplete=\"off\"\n disabled={readOnly}\n aria-label={`${name} hex`}\n value={hexDraft}\n onChange={(event) => {\n const next = event.target.value.trim();\n setHexDraft(next);\n if (isThemeHex(next)) commitHex(next);\n }}\n onBlur={() => {\n if (!isThemeHex(hexDraft)) setHexDraft(state.hex);\n }}\n />\n </span>\n </div>\n <label className=\"bl-scale-card__field\">\n <span>This color is</span>\n <select\n disabled={readOnly}\n value={String(state.sourceStep)}\n onChange={(event) => commitStep(Number(event.target.value) as ShadeStep)}\n >\n {SHADE_STEPS.map((step) => (\n <option key={step} value={step}>\n {step}\n </option>\n ))}\n </select>\n </label>\n </div>\n\n {role ? (\n <div className=\"bl-scale-card__family\" data-role={role} data-drift={hueDrift ? \"\" : undefined}>\n <div className=\"bl-scale-card__family-mark\" aria-hidden=\"true\">\n !\n </div>\n <div>\n <div className=\"bl-scale-card__family-title\">{STATUS_COPY[role].title}</div>\n <p>{STATUS_COPY[role].body}</p>\n {hueDrift ? <p className=\"bl-scale-card__family-drift\">{STATUS_COPY[role].drift}</p> : null}\n </div>\n </div>\n ) : null}\n\n <div className=\"bl-scale-card__scale-head\">\n <span>Generated scale</span>\n <span>{SHADE_STEPS.length} shades</span>\n </div>\n <div className=\"bl-scale-card__steps\" role=\"group\" aria-label={`${name} scale steps`}>\n {SHADE_STEPS.map((step) => {\n const source = step === state.sourceStep;\n const on = included.has(step);\n return (\n <button\n key={step}\n type=\"button\"\n className=\"bl-scale-card__step\"\n data-source={source ? \"\" : undefined}\n data-excluded={on ? undefined : \"\"}\n data-shake={shakeStep === step ? \"\" : undefined}\n disabled={readOnly}\n aria-pressed={on}\n aria-label={\n source\n ? `Source step ${step} cannot be excluded`\n : on\n ? `Shade ${step}, available — click to exclude from the palette`\n : `Shade ${step}, excluded — click to include in the palette`\n }\n title={\n source\n ? `Source step ${step} cannot be excluded`\n : on\n ? \"Available to page editors — click to exclude\"\n : \"Excluded from page editors — click to include\"\n }\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n toggleStep(step);\n }}\n >\n <span className=\"bl-scale-card__chip-wrap\">\n <span className=\"bl-scale-card__chip\" style={{ backgroundColor: hslCss(state.scale[step]) }} />\n <IncludeMark on={on} />\n </span>\n <span className=\"bl-scale-card__step-label\">{step}</span>\n </button>\n );\n })}\n </div>\n <div className=\"bl-scale-card__editors\">\n <div>\n <div>Available to page editors</div>\n <p>\n {included.size} of {SHADE_STEPS.length} shades available · Choose which shades editors can select when\n building pages.\n </p>\n </div>\n <span>\n <button type=\"button\" disabled={readOnly} onClick={() => onChange(setColorScaleInclude(state, \"all\"))}>\n Include all\n </button>\n <button type=\"button\" disabled={readOnly} onClick={() => onChange(setColorScaleInclude(state, \"source\"))}>\n Source only\n </button>\n </span>\n </div>\n {attentionOpen && warning ? (\n <ThemePortal>\n <div\n className=\"bl-scale-card__modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n onClick={(event) => {\n if (event.target === event.currentTarget) setAttentionOpen(false);\n }}\n >\n <div className=\"bl-scale-card__panel\">\n <div className=\"bl-scale-card__panel-head\">\n <h4 id={titleId}>{readabilityHeadline(warning)}</h4>\n <button type=\"button\" onClick={() => setAttentionOpen(false)} aria-label=\"Close\">\n ×\n </button>\n </div>\n <ReadabilityDetail item={warning} />\n <button type=\"button\" className=\"bl-scale-card__panel-done\" onClick={() => setAttentionOpen(false)}>\n Keep editing this color\n </button>\n </div>\n </div>\n </ThemePortal>\n ) : null}\n </article>\n );\n}\n\nexport const COLOR_SCALE_CARD_CSS = `\n.bl-scale-card{padding:calc(var(--base,16px) * .8);border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:var(--style-radius-m,12px);background:var(--bl-preview-card,var(--theme-elevation-0,#fff));color:var(--bl-preview-text,inherit)}\n.bl-scale-card__head{display:flex;justify-content:space-between;gap:1rem;align-items:flex-start}\n.bl-scale-card__title-row{position:relative;display:flex;align-items:center;flex-wrap:wrap;gap:.5rem}\n.bl-scale-card__title{margin:0;font-size:1rem}\n.bl-scale-card__badge{font:inherit;font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:.15rem .45rem;border-radius:999px;border:0;background:#e2e8f0;color:#0f172a}\n.bl-scale-card__badge--attention{background:#fff1f2;color:#be123c;cursor:pointer}\n.bl-scale-card__hint{margin:.35rem 0 0;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b));font-size:12px}\n.bl-scale-card__delete{border:0;background:none;color:#be123c;font:inherit;font-size:13px;font-weight:600;cursor:pointer}\n.bl-scale-card__row{display:grid;grid-template-columns:1fr 8rem;gap:.75rem;margin-top:1rem}\n.bl-scale-card__field{display:flex;flex-direction:column;gap:.35rem;font-size:12px;font-weight:600;color:var(--bl-preview-muted,var(--theme-elevation-600,#475569))}\n.bl-scale-card__hex-wrap{display:flex;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:8px;background:var(--bl-preview-card,var(--theme-input-bg,#fff))}\n.bl-scale-card__hex-wrap input[type=color]{width:2.75rem;height:2.25rem;padding:0;border:0;border-right:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:8px 0 0 8px;background:transparent;cursor:pointer;color-scheme:light;appearance:none;-webkit-appearance:none}\n.bl-scale-card__hex-wrap input[type=color]::-webkit-color-swatch-wrapper{padding:0}\n.bl-scale-card__hex-wrap input[type=color]::-webkit-color-swatch{border:0;border-radius:0;width:100%;height:100%}\n.bl-scale-card__hex-wrap input[type=text]{flex:1;min-width:0;border:0;padding:.4rem .7rem;font-family:var(--font-mono,ui-monospace,monospace);font-size:13px;background:transparent;color:inherit;border-radius:0 8px 8px 0}\n.bl-scale-card__field select{min-height:2.25rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:8px;padding:.35rem .5rem;background:var(--bl-preview-card,var(--theme-input-bg,#fff));color:inherit}\n.bl-scale-card__family{display:flex;gap:.75rem;align-items:flex-start;margin-top:1rem;padding:.75rem .85rem;border-radius:8px}\n.bl-scale-card__family[data-role=success]{border:1px solid #a7f3d0;background:#ecfdf5;color:#065f46}\n.bl-scale-card__family[data-role=destructive]{border:1px solid #fecdd3;background:#fff1f2;color:#9f1239}\n.bl-scale-card__family[data-drift]{box-shadow:0 0 0 2px #fbbf24}\n.bl-scale-card__family-mark{flex:none;width:1.25rem;height:1.25rem;border-radius:999px;display:grid;place-items:center;font-size:11px;font-weight:700}\n.bl-scale-card__family[data-role=success] .bl-scale-card__family-mark{background:#d1fae5;color:#047857}\n.bl-scale-card__family[data-role=destructive] .bl-scale-card__family-mark{background:#ffe4e6;color:#be123c}\n.bl-scale-card__family-title{font-size:12px;font-weight:600}\n.bl-scale-card__family p{margin:.25rem 0 0;font-size:11px;line-height:1.45;opacity:.85}\n.bl-scale-card__family-drift{font-weight:600;opacity:1}\n.bl-scale-card__scale-head{display:flex;justify-content:space-between;margin:1rem 0 .4rem;font-size:12px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b))}\n.bl-scale-card__steps{display:grid;grid-template-columns:repeat(11,minmax(0,1fr));gap:.45rem 3px}\n.bl-scale-card__step{display:flex;flex-direction:column;align-items:center;gap:.3rem;border:0;padding:0;background:transparent;cursor:pointer}\n.bl-scale-card__chip-wrap{position:relative;display:block;width:100%}\n.bl-scale-card__chip{display:block;width:100%;height:2.15rem;border-radius:6px;overflow:hidden}\n.bl-scale-card__status{position:absolute;top:3px;right:3px;width:16px;height:16px;border-radius:999px;display:grid;place-items:center;pointer-events:none;background:rgba(255,255,255,.94);color:#0f172a;box-shadow:0 1px 3px rgba(15,23,42,.18)}\n.bl-scale-card__status svg{display:block;width:10px;height:10px}\n.bl-scale-card__step-label{font-size:10px;line-height:1;color:var(--theme-elevation-600,#475569)}\n.bl-scale-card__step[data-source] .bl-scale-card__chip{box-shadow:0 0 0 2px #0f172a}\n.bl-scale-card__step[data-excluded] .bl-scale-card__chip{opacity:.28;background-image:linear-gradient(45deg,transparent 44%,rgba(15,23,42,.8) 45%,rgba(15,23,42,.8) 55%,transparent 56%)}\n.bl-scale-card__step[data-excluded] .bl-scale-card__status{color:#991b1b;background:rgba(255,255,255,.96)}\n.bl-scale-card__step[data-excluded] .bl-scale-card__step-label{opacity:.35}\n@keyframes bl-scale-shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-3px)}75%{transform:translateX(3px)}}\n.bl-scale-card__step[data-shake]{animation:bl-scale-shake .18s}\n.bl-scale-card__step:disabled{cursor:default}\n.bl-scale-card__editors{display:flex;flex-wrap:wrap;justify-content:space-between;gap:.75rem;align-items:flex-end;margin-top:.75rem;padding:.65rem .75rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:8px;background:var(--bl-preview-bg,var(--theme-elevation-50,#f8fafc))}\n.bl-scale-card__editors > div > div{font-size:12px;font-weight:600;color:var(--bl-preview-text,var(--theme-elevation-700,#334155))}\n.bl-scale-card__editors p{margin:.2rem 0 0;font-size:11px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b))}\n.bl-scale-card__editors button{border:0;background:none;padding:0;margin-left:.75rem;font:inherit;font-size:12px;font-weight:600;color:var(--theme-success-500,#1587ba);text-decoration:underline;cursor:pointer}\n.bl-scale-card__editors span{display:flex;gap:0}\n.bl-scale-card__modal{position:fixed;inset:0;z-index:10000;display:grid;place-items:center;padding:1rem;background:rgba(15,23,42,.45)}\n.bl-scale-card__panel{width:min(32rem,100%);padding:1.15rem 1.2rem;border-radius:16px;background:#fff;color:#0f172a;color-scheme:light}\n.bl-scale-card__panel-head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem}\n.bl-scale-card__panel-head h4{margin:0;font-size:1rem}\n.bl-scale-card__panel-head button{border:0;background:none;font:inherit;font-size:1.25rem;line-height:1;color:#64748b;cursor:pointer}\n.bl-scale-card__panel-done{margin-top:1rem;min-height:2.1rem;padding:.35rem .85rem;border:0;border-radius:8px;background:#0f172a;color:#fff;font:inherit;font-weight:600;cursor:pointer}\n.bl-scale-card[data-preview=dark] .bl-scale-card__step[data-source] .bl-scale-card__chip{box-shadow:0 0 0 2px var(--bl-preview-text,#fafafa)}\n` + READABILITY_LIST_CSS + THEME_COLORS_LAYOUT_CSS;\n","import { useField, useForm } from \"@payloadcms/ui\";\nimport { isThemeHex, SHADE_STEPS, type ColorScaleState, type ShadeStep } from \"@bison-lab/tokens\";\nimport type { GroupFieldClientComponent } from \"payload\";\n\nimport { SYSTEM_COLOR_COPY } from \"../theme/appearance-labels\";\nimport { colorDocFromState, stateFromColorDoc } from \"../theme/map\";\nimport { ColorScaleCard, COLOR_SCALE_CARD_CSS } from \"./color-scale-card\";\n\nconst SYSTEM_ROLES = new Set(Object.keys(SYSTEM_COLOR_COPY));\n\n/**\n * Payload's hasMany select often stores a count on the field path and the\n * chosen values at `path.0`, `path.1`, … — same shape as an array field.\n */\nfunction includedStepsFromForm(\n path: string,\n value: ShadeStep[] | string[] | number | undefined,\n getDataByPath?: (fieldPath: string) => unknown,\n): ShadeStep[] | string[] | undefined {\n if (Array.isArray(value)) return value;\n const stored = getDataByPath?.(path);\n if (Array.isArray(stored)) return stored as ShadeStep[] | string[];\n const count = typeof value === \"number\" ? value : typeof stored === \"number\" ? stored : 0;\n if (count <= 0) return undefined;\n const steps = Array.from({ length: count }, (_, index) => getDataByPath?.(`${path}.${index}`));\n if (steps.every((step) => step == null)) return undefined;\n return steps.filter((step): step is ShadeStep | string => step != null).map(String);\n}\n\n/**\n * One system (or library row) color: hex, source step, include/exclude.\n * Writes the group's stored fields. A committed hex or step rebuilds the scale.\n */\nexport const ColorScaleField: GroupFieldClientComponent = ({ field, path, readOnly }) => {\n const hex = useField<string>({ path: `${path}.hex` });\n const sourceStep = useField<string | number>({ path: `${path}.sourceStep` });\n const scale = useField<ColorScaleState[\"scale\"]>({ path: `${path}.scale` });\n const stale = useField<boolean>({ path: `${path}.stale` });\n const include = useField<string>({ path: `${path}.include` });\n const includedSteps = useField<ShadeStep[] | string[] | number>({ path: `${path}.includedSteps` });\n const { getDataByPath } = useForm();\n const key = path.split(\".\").pop() ?? \"\";\n const copy = SYSTEM_ROLES.has(key) ? SYSTEM_COLOR_COPY[key as keyof typeof SYSTEM_COLOR_COPY] : undefined;\n const stepList = includedStepsFromForm(`${path}.includedSteps`, includedSteps.value, getDataByPath);\n const state = stateFromColorDoc({\n hex: hex.value,\n sourceStep: sourceStep.value as ShadeStep | undefined,\n scale: scale.value,\n stale: stale.value,\n include: include.value === \"source\" || include.value === \"custom\" || include.value === \"all\" ? include.value : \"all\",\n includedSteps: stepList,\n });\n\n function write(next: ColorScaleState) {\n const doc = colorDocFromState(next);\n hex.setValue(doc.hex);\n sourceStep.setValue(String(doc.sourceStep));\n scale.setValue(doc.scale);\n stale.setValue(doc.stale);\n include.setValue(doc.include);\n includedSteps.setValue(\n (doc.includedSteps ?? (doc.include === \"source\" ? [doc.sourceStep] : [...SHADE_STEPS])).map(String),\n );\n }\n\n const label = copy?.label ?? (typeof field.label === \"string\" ? field.label : key);\n\n return (\n <div className=\"field-type bl-scale-field\">\n <style href=\"bl-scale-card\" precedence=\"default\">\n {COLOR_SCALE_CARD_CSS}\n </style>\n <ColorScaleCard\n id={key}\n name={label}\n hint={copy?.hint}\n required={Boolean(copy) || Boolean(\"required\" in field && field.required)}\n state={isThemeHex(state.hex) ? state : { ...state, hex: \"#000000\" }}\n onChange={write}\n readOnly={readOnly}\n role={key === \"success\" || key === \"destructive\" ? key : null}\n />\n </div>\n );\n};\n","import { SHADE_STEPS, type ShadeStep } from \"@bison-lab/tokens\";\n\nimport { SYSTEM_COLOR_KEYS, type ThemeDoc, type ThemeLibraryColorDoc } from \"./types\";\n\n/**\n * Payload's array form state stores the row count (`0`, `2`, …), not the\n * rows. A custom Field that treats that number as the list will throw\n * `rows.filter is not a function` on an empty Theme library.\n */\nexport function asLibraryRows(value: unknown): ThemeLibraryColorDoc[] {\n return Array.isArray(value) ? value : [];\n}\n\nconst STEP_SET = new Set<number>(SHADE_STEPS);\n\n/**\n * Page editors pick `coral-400`, never a raw hex. Rewrite every use of\n * `fromKey` onto `toKey` at the same step: `coral-400` → `highlight-400`.\n * A bare key (`coral`) becomes `toKey`. Anything else is left alone.\n */\nexport function rewriteColorToken(token: string, fromKey: string, toKey: string): string {\n if (token === fromKey) return toKey;\n const dash = token.lastIndexOf(\"-\");\n if (dash <= 0) return token;\n const key = token.slice(0, dash);\n const step = Number(token.slice(dash + 1));\n if (key !== fromKey || !STEP_SET.has(step)) return token;\n return `${toKey}-${step as ShadeStep}`;\n}\n\nexport function themeColorKeys(doc: ThemeDoc | null | undefined): string[] {\n const custom = asLibraryRows(doc?.colors?.library)\n .map((row) => row.key?.trim())\n .filter((key): key is string => Boolean(key));\n return [...SYSTEM_COLOR_KEYS, ...custom];\n}\n\n/**\n * Remove a custom color. Unused: omit `replacement` and the row is gone.\n * In use: pass another system or custom key; the caller rewrites page\n * tokens with `rewriteColorToken`. After this, no library row still\n * has `key`.\n */\nexport function deleteLibraryColor(doc: ThemeDoc, key: string, replacement?: string): ThemeDoc {\n const library = [...asLibraryRows(doc.colors?.library)];\n const index = library.findIndex((row) => row.key === key);\n if (index === -1) {\n throw new Error(`No custom color named ${JSON.stringify(key)}`);\n }\n library.splice(index, 1);\n const next: ThemeDoc = {\n ...doc,\n colors: { ...doc.colors, library },\n };\n if (replacement !== undefined) {\n if (replacement === key) {\n throw new Error(\"Replacement must be a different color\");\n }\n if (!themeColorKeys(next).includes(replacement)) {\n throw new Error(`Replacement ${JSON.stringify(replacement)} is not a system or remaining custom color`);\n }\n }\n return next;\n}\n","import { useField, useForm } from \"@payloadcms/ui\";\nimport { createColorScale, isThemeHex, SHADE_STEPS, type ShadeStep } from \"@bison-lab/tokens\";\nimport type { ArrayFieldClientComponent } from \"payload\";\nimport { useState } from \"react\";\n\nimport { asLibraryRows, deleteLibraryColor } from \"../theme/library\";\nimport { colorDocFromState, stateFromColorDoc } from \"../theme/map\";\nimport { type ThemeDoc, type ThemeLibraryColorDoc } from \"../theme/types\";\nimport { ColorScaleCard, COLOR_SCALE_CARD_CSS } from \"./color-scale-card\";\nimport { ThemePortal } from \"./portal\";\n\nfunction slugify(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\n/**\n * Custom colors: the same scale controls as system colors. A row that is\n * not referenced on a page deletes immediately. Rewriting in-use tokens\n * (`rewriteColorToken`) waits on a site usage lookup — Theme cannot see\n * page assignments by itself.\n */\nexport const LibraryField: ArrayFieldClientComponent = ({ field, path, readOnly }) => {\n const dataPath =\n typeof field.admin?.custom?.dataPath === \"string\" ? field.admin.custom.dataPath : path;\n const { value, setValue } = useField<ThemeLibraryColorDoc[] | number>({ path: dataPath, hasRows: true });\n const { getDataByPath } = useForm();\n const rows = asLibraryRows(value).length > 0 ? asLibraryRows(value) : asLibraryRows(getDataByPath?.(dataPath));\n const [adding, setAdding] = useState(false);\n const [name, setName] = useState(\"\");\n const [hex, setHex] = useState(\"\");\n const [sourceStep, setSourceStep] = useState<ShadeStep>(500);\n\n function write(next: ThemeLibraryColorDoc[]) {\n setValue(next);\n }\n\n function add() {\n const key = slugify(name);\n if (!key || !isThemeHex(hex) || rows.some((row) => row.key === key)) return;\n write([...rows, { key, label: name.trim(), ...colorDocFromState(createColorScale(hex, sourceStep)) }]);\n setName(\"\");\n setHex(\"\");\n setSourceStep(500);\n setAdding(false);\n }\n\n function remove(row: ThemeLibraryColorDoc) {\n const doc: ThemeDoc = { colors: { library: rows } };\n write(deleteLibraryColor(doc, row.key ?? \"\").colors?.library ?? []);\n }\n\n return (\n <div className=\"field-type bl-library\">\n <style href=\"bl-scale-card\" precedence=\"default\">\n {COLOR_SCALE_CARD_CSS}\n </style>\n <style href=\"bl-library\" precedence=\"default\">\n {CSS}\n </style>\n <div className=\"bl-library__head\">\n <div>\n <h2>Additional colors</h2>\n <p>Add optional named colors for special sections, campaigns, or components.</p>\n </div>\n <button\n type=\"button\"\n disabled={readOnly}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n setAdding(true);\n }}\n >\n Add color\n </button>\n </div>\n {adding ? (\n <ThemePortal>\n <div\n className=\"bl-library__modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"bl-library-add-title\"\n onClick={(event) => {\n if (event.target === event.currentTarget) setAdding(false);\n }}\n >\n <div className=\"bl-library__panel\">\n <div className=\"bl-library__panel-head\">\n <div>\n <h2 id=\"bl-library-add-title\">New color</h2>\n <p>Give it a useful name, enter your brand hex, then say which scale step that hex is.</p>\n </div>\n <button type=\"button\" onClick={() => setAdding(false)} aria-label=\"Close\">\n ×\n </button>\n </div>\n <label>\n Name\n <input\n value={name}\n placeholder=\"e.g. Coral\"\n onChange={(event) => setName(event.target.value)}\n />\n </label>\n <label>\n Brand hex\n <input\n value={hex}\n placeholder=\"#DB0082\"\n spellCheck={false}\n autoComplete=\"off\"\n onChange={(event) => setHex(event.target.value.trim())}\n />\n </label>\n <label>\n This color is\n <select\n value={String(sourceStep)}\n onChange={(event) => setSourceStep(Number(event.target.value) as ShadeStep)}\n >\n {SHADE_STEPS.map((step) => (\n <option key={step} value={step}>\n {step}\n </option>\n ))}\n </select>\n </label>\n <div className=\"bl-library__actions\">\n <button type=\"button\" onClick={() => setAdding(false)}>\n Cancel\n </button>\n <button type=\"button\" disabled={!slugify(name) || !isThemeHex(hex)} onClick={add}>\n Create color scale\n </button>\n </div>\n </div>\n </div>\n </ThemePortal>\n ) : null}\n <div className=\"bl-library__list\">\n {rows.map((row, index) => (\n <ColorScaleCard\n key={row.key ?? index}\n id={row.key ?? `custom-${index}`}\n name={row.label ?? row.key ?? \"Color\"}\n hint={row.key ? `Key: ${row.key}` : undefined}\n custom\n state={stateFromColorDoc(row)}\n onChange={(next) => {\n const copy = [...rows];\n copy[index] = { ...row, ...colorDocFromState(next) };\n write(copy);\n }}\n onDelete={readOnly ? undefined : () => remove(row)}\n readOnly={readOnly}\n />\n ))}\n </div>\n </div>\n );\n};\n\nconst CSS = `\n.bl-library__head{display:flex;justify-content:space-between;gap:1rem;align-items:flex-start;margin-bottom:.85rem}\n.bl-library__head h2{margin:0;font-size:1.1rem}\n.bl-library__head p{margin:.35rem 0 0;font-size:13px;color:color-mix(in srgb,var(--theme-text,#f8fafc) 92%,transparent)}\n.bl-library__head button,.bl-library__actions button{min-height:2.1rem;padding:.35rem .75rem;border-radius:8px;border:1px solid var(--theme-elevation-150,#e2e8f0);background:var(--theme-elevation-0,#fff);color:var(--theme-text,#0f172a);font:inherit;cursor:pointer}\n.bl-library__list{display:grid;gap:.85rem}\n.bl-library__modal{position:fixed;inset:0;z-index:10000;display:grid;place-items:center;padding:1rem;background:rgba(15,23,42,.45)}\n.bl-library__panel{width:min(28rem,100%);padding:1.2rem;border-radius:16px;background:#fff;color:#0f172a;color-scheme:light;box-shadow:0 24px 48px rgba(15,23,42,.22)}\n.bl-library__panel-head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem}\n.bl-library__panel-head button{border:0;background:none;font:inherit;font-size:1.25rem;line-height:1;color:#94a3b8;cursor:pointer}\n.bl-library__panel h2{margin:0}\n.bl-library__panel p{margin:.5rem 0 0;color:#475569;font-size:14px}\n.bl-library__panel label{display:flex;flex-direction:column;gap:.4rem;margin-top:1rem;font-size:13px;font-weight:600}\n.bl-library__panel input,.bl-library__panel select{min-height:2.25rem;border:1px solid #cbd5e1;border-radius:8px;padding:.35rem .5rem;background:#fff;color:#0f172a}\n.bl-library__actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.5rem;margin-top:1rem}\n.bl-library__actions button:last-child{border:0;background:#0f172a;color:#fff;font-weight:600}\n.bl-library__actions button:last-child:disabled{opacity:.4;cursor:not-allowed}\n`;\n","import type { ReactNode } from \"react\";\n\nexport function FontRoleCard({\n title,\n hint,\n required,\n family,\n preview,\n children,\n}: {\n title: string;\n hint: string;\n required?: boolean;\n family: string;\n preview: \"heading\" | \"body\";\n children?: ReactNode;\n}) {\n return (\n <article className=\"bl-font-role\">\n <header className=\"bl-font-role__head\">\n <div>\n <h3>{title}</h3>\n <p>{hint}</p>\n </div>\n {required ? <span className=\"bl-font-role__badge\">Required</span> : null}\n </header>\n {children}\n <div className=\"bl-font-role__preview\">\n <span>Preview</span>\n {preview === \"heading\" ? (\n <p className=\"bl-font-role__heading\" style={{ fontFamily: `\"${family}\"` }}>\n Advancing the work with clarity.\n </p>\n ) : (\n <p className=\"bl-font-role__body\" style={{ fontFamily: `\"${family}\"` }}>\n Clear, comfortable text for longer reading across the site.\n </p>\n )}\n </div>\n </article>\n );\n}\n\nexport function TypographyPairing({\n headingFamily,\n bodyFamily,\n}: {\n headingFamily: string;\n bodyFamily: string;\n}) {\n return (\n <section className=\"bl-pairing\" aria-label=\"Font pairing sample\">\n <header>\n <h2>Pairing sample</h2>\n <p>Heading and body from the approved catalogue. Type scale stays with the library.</p>\n </header>\n <div className=\"bl-pairing__page\">\n <p className=\"bl-pairing__eyebrow\" style={{ fontFamily: `\"${bodyFamily}\"` }}>\n For visitors\n </p>\n <p className=\"bl-pairing__title\" style={{ fontFamily: `\"${headingFamily}\"` }}>\n Stay in motion.\n </p>\n <p className=\"bl-pairing__copy\" style={{ fontFamily: `\"${bodyFamily}\"` }}>\n Heading and body come from the catalogue. This is the pairing, not a full site preview.\n </p>\n <div className=\"bl-pairing__actions\">\n <span className=\"bl-pairing__btn\" style={{ fontFamily: `\"${bodyFamily}\"` }}>\n Primary action\n </span>\n <span className=\"bl-pairing__btn bl-pairing__btn--ghost\" style={{ fontFamily: `\"${bodyFamily}\"` }}>\n Learn more\n </span>\n </div>\n </div>\n </section>\n );\n}\n\nexport const TYPOGRAPHY_PAIRING_CSS = `\n.bl-font-role{padding:1.1rem 1.15rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:12px;background:var(--bl-preview-card,var(--theme-elevation-0,#fff));color:var(--bl-preview-text,inherit)}\n.bl-font-role__head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem}\n.bl-font-role__head h3{margin:0;font-size:1rem}\n.bl-font-role__head p{margin:.3rem 0 0;font-size:12px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b))}\n.bl-font-role__badge{font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:.15rem .45rem;border-radius:999px;background:#e2e8f0;color:#0f172a}\n.bl-font-role__preview{margin-top:1rem;padding:.85rem .9rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:12px;background:var(--bl-preview-bg,var(--theme-elevation-50,#f8fafc))}\n.bl-font-role__preview > span{display:block;margin-bottom:.4rem;font-size:11px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b))}\n.bl-font-role__heading{margin:0;font-size:1.5rem;line-height:1.2;font-weight:600}\n.bl-font-role__body{margin:0;font-size:1rem;line-height:1.6;color:var(--bl-preview-muted,var(--theme-elevation-600,#475569))}\n.bl-pairing{padding:0;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:12px;background:var(--bl-preview-card,var(--theme-elevation-0,#fff));color:var(--bl-preview-text,inherit);overflow:hidden}\n.bl-pairing > header{padding:1rem 1.15rem;border-bottom:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0))}\n.bl-pairing > header h2{margin:0;font-size:1rem}\n.bl-pairing > header p{margin:.3rem 0 0;font-size:12px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b))}\n.bl-pairing__page{padding:1.35rem 1.4rem 1.5rem;background:var(--bl-preview-bg,transparent)}\n.bl-pairing__eyebrow{margin:0;font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:#7c1fa2}\n.bl-pairing__title{margin:.5rem 0 0;font-size:2rem;line-height:1.1;font-weight:600}\n.bl-pairing__copy{margin:.75rem 0 0;max-width:36rem;font-size:1rem;line-height:1.6;color:var(--bl-preview-muted,var(--theme-elevation-600,#475569))}\n.bl-pairing__actions{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:1.1rem}\n.bl-pairing__btn{display:inline-flex;align-items:center;min-height:2.15rem;padding:.4rem .85rem;border-radius:8px;background:#db0082;color:#fff;font-size:14px;font-weight:600}\n.bl-pairing__btn--ghost{background:#fff;color:#0f172a;border:1px solid #cbd5e1}\n`;\n","import { FieldDescription, FieldError, FieldLabel, useField } from \"@payloadcms/ui\";\nimport { findFont, fontFaceCss, isFontId, type FontId } from \"@bison-lab/fonts\";\nimport type { SelectFieldClientComponent } from \"payload\";\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\n\nimport { FONT_ROLE_COPY } from \"../theme/appearance-labels\";\nimport { SAME_AS_BODY } from \"../theme/fields\";\nimport { usePreviewCanvas } from \"./preview-mode\";\nimport { FontRoleCard, TYPOGRAPHY_PAIRING_CSS } from \"./typography-pairing\";\n\ntype Option = { value: string; family: string; hint: string; specimen: boolean };\n\n/**\n * Listbox over the catalogue ids in `admin.custom.ids`. Each option is the\n * family name in that face, with the catalogue hint beneath. Faces load\n * from the site's font route for the selected family, and for every\n * catalogue id once the picker opens.\n */\nexport const FontField: SelectFieldClientComponent = ({ field, path, readOnly }) => {\n const { value, setValue, showError, errorMessage } = useField<string>({ path });\n const custom = (field.admin?.custom ?? {}) as {\n fontsBaseUrl?: string;\n ids?: string[];\n sameAsBody?: boolean;\n };\n const ids = custom.ids ?? [];\n const fontsBaseUrl = custom.fontsBaseUrl ?? \"/fonts\";\n const sameAsBody = Boolean(custom.sameAsBody);\n\n const options = useMemo<Option[]>(() => {\n const fromCatalogue: Option[] = ids.flatMap((id) => {\n const font = findFont(id);\n if (!font) return [];\n return [{ value: font.id, family: font.family, hint: font.hint, specimen: true }];\n });\n if (!sameAsBody) return fromCatalogue;\n return [{ value: SAME_AS_BODY, family: \"Same as body\", hint: \"Use the body family for headings\", specimen: false }, ...fromCatalogue];\n }, [ids, sameAsBody]);\n\n const [open, setOpen] = useState(false);\n const [faces, setFaces] = useState(false);\n const [active, setActive] = useState(-1);\n const [query, setQuery] = useState(\"\");\n const [category, setCategory] = useState<\"all\" | \"sans\" | \"serif\" | \"display\" | \"mono\">(\"all\");\n const typed = useRef(\"\");\n const typedAt = useRef(0);\n const id = useId();\n const buttonId = `${id}-button`;\n const listId = `${id}-list`;\n const required = Boolean(field.required);\n\n useEffect(() => {\n if (open) setFaces(true);\n }, [open]);\n\n const selected = options.find((option) => option.value === (value ?? SAME_AS_BODY)) ?? options[0];\n const visible = options.filter((option) => {\n if (query && !option.family.toLowerCase().includes(query.trim().toLowerCase())) return false;\n if (category === \"all\" || !option.specimen) return true;\n const font = findFont(option.value);\n return font?.category === category;\n });\n const role = sameAsBody ? FONT_ROLE_COPY.heading : FONT_ROLE_COPY.body;\n\n function choose(option: Option) {\n setValue(option.value);\n setOpen(false);\n setActive(-1);\n setQuery(\"\");\n setCategory(\"all\");\n }\n\n function onKeyDown(event: React.KeyboardEvent<HTMLButtonElement>) {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n if (!open) {\n setOpen(true);\n setActive(0);\n return;\n }\n setActive((i) => (options.length ? (i + 1) % options.length : -1));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n if (!open) {\n setOpen(true);\n setActive(options.length - 1);\n return;\n }\n setActive((i) => (options.length ? (i <= 0 ? options.length - 1 : i - 1) : -1));\n } else if (event.key === \"Enter\") {\n if (!open) return;\n event.preventDefault();\n const pick = options[active] ?? options[0];\n if (pick) choose(pick);\n } else if (event.key === \"Escape\") {\n if (!open) return;\n event.preventDefault();\n event.stopPropagation();\n setOpen(false);\n setActive(-1);\n } else if (event.key.length === 1 && !event.metaKey && !event.ctrlKey && !event.altKey) {\n const now = Date.now();\n typed.current = now - typedAt.current > 600 ? event.key : typed.current + event.key;\n typedAt.current = now;\n const needle = typed.current.toLowerCase();\n const index = options.findIndex((option) => option.family.toLowerCase().startsWith(needle));\n if (index >= 0) {\n if (!open) setOpen(true);\n setActive(index);\n }\n }\n }\n\n const activeId = active >= 0 && open ? `${id}-option-${active}` : undefined;\n const faceIds = (faces ? ids : isFontId(value) ? [value] : []) as FontId[];\n const canvas = usePreviewCanvas();\n\n return (\n <div className={`field-type bl-font-field ${canvas.className}`} data-preview={canvas.mode} style={canvas.style}>\n <style href=\"bl-pairing\" precedence=\"default\">\n {TYPOGRAPHY_PAIRING_CSS}\n </style>\n <style href=\"bl-font-field\" precedence=\"default\">\n {CSS}\n </style>\n {faceIds.length > 0 ? <style data-bl-font-faces=\"\">{fontFaceCss(faceIds, fontsBaseUrl)}</style> : null}\n <FontRoleCard\n title={typeof field.label === \"string\" ? field.label : role.label}\n hint={role.hint}\n required={required}\n family={selected?.family ?? \"Inter\"}\n preview={sameAsBody ? \"heading\" : \"body\"}\n >\n <FieldLabel htmlFor={buttonId} label={field.label} required={required} />\n <button\n id={buttonId}\n type=\"button\"\n className=\"bl-font-field__trigger\"\n disabled={readOnly}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-controls={listId}\n aria-activedescendant={activeId}\n onClick={() => setOpen((was) => !was)}\n onKeyDown={onKeyDown}\n >\n <span>\n <span className=\"bl-font-field__selected-label\">Selected</span>\n <span\n className=\"bl-font-field__selected-name\"\n style={selected?.specimen ? { fontFamily: `\"${selected.family}\"` } : undefined}\n >\n {selected?.family ?? \"Choose a font\"}\n </span>\n </span>\n <span aria-hidden=\"true\">⌄</span>\n </button>\n </FontRoleCard>\n {open ? (\n <div\n className=\"bl-font-field__modal\"\n onClick={(event) => {\n if (event.target === event.currentTarget) setOpen(false);\n }}\n >\n <div className=\"bl-font-field__panel\">\n <div className=\"bl-font-field__panel-head\">\n <div>\n <p>Choose a font</p>\n <h2>{role.label}</h2>\n </div>\n <button type=\"button\" onClick={() => setOpen(false)} aria-label=\"Close\">\n ×\n </button>\n </div>\n <input\n type=\"search\"\n className=\"bl-font-field__search\"\n placeholder=\"Search fonts…\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n />\n <div className=\"bl-font-field__filters\">\n {([\"all\", \"sans\", \"serif\", \"display\", \"mono\"] as const).map((item) => (\n <button\n key={item}\n type=\"button\"\n data-on={category === item ? \"\" : undefined}\n onClick={() => setCategory(item)}\n >\n {item === \"all\" ? \"All\" : item === \"sans\" ? \"Sans serif\" : item === \"serif\" ? \"Serif\" : item === \"display\" ? \"Display\" : \"Mono\"}\n </button>\n ))}\n </div>\n <ul id={listId} role=\"listbox\" className=\"bl-font-field__menu\">\n {visible.map((option, i) => (\n <li\n key={option.value || \"same\"}\n id={`${id}-option-${i}`}\n role=\"option\"\n aria-selected={option.value === (value ?? SAME_AS_BODY)}\n className=\"bl-font-field__option\"\n onMouseDown={(event) => {\n event.preventDefault();\n choose(option);\n }}\n onMouseEnter={() => setActive(i)}\n >\n <span\n className=\"bl-font-field__family\"\n style={option.specimen ? { fontFamily: `\"${option.family}\"` } : undefined}\n >\n {option.family}\n </span>\n <span className=\"bl-font-field__hint\">{option.hint}</span>\n <span\n className=\"bl-font-field__specimen\"\n style={option.specimen ? { fontFamily: `\"${option.family}\"` } : undefined}\n >\n The quick brown fox jumps over the lazy dog.\n </span>\n </li>\n ))}\n </ul>\n </div>\n </div>\n ) : null}\n <FieldDescription description={field.admin?.description} path={path} />\n <FieldError path={path} showError={showError} message={errorMessage} />\n </div>\n );\n};\n\nconst CSS = `\n.bl-font-field{margin-bottom:1rem}\n.bl-font-field .field-label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n.bl-font-field__trigger{display:flex;align-items:center;justify-content:space-between;width:100%;margin-top:1rem;min-height:3.25rem;padding:.7rem 1rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:12px;background:var(--theme-input-bg,#fff);color:inherit;font:inherit;text-align:left;cursor:pointer}\n.bl-font-field__trigger:focus{border-color:var(--theme-elevation-400,#94a3b8);outline:none;box-shadow:0 0 0 1px var(--theme-elevation-400,#94a3b8)}\n.bl-font-field__trigger:disabled{color:var(--theme-elevation-400,#94a3b8);cursor:not-allowed}\n.bl-font-field__selected-label{display:block;font-size:11px;color:var(--theme-elevation-500,#64748b)}\n.bl-font-field__selected-name{display:block;margin-top:.15rem;font-weight:600}\n.bl-font-field__modal{position:fixed;inset:0;z-index:10000;display:grid;place-items:center;padding:1rem;background:rgba(15,23,42,.45)}\n.bl-font-field__panel{width:min(36rem,100%);max-height:min(36rem,90vh);display:flex;flex-direction:column;padding:1.15rem 1.2rem;border-radius:16px;background:#fff;color:#0f172a}\n.bl-font-field__panel-head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem}\n.bl-font-field__panel-head p{margin:0;font-size:12px;color:#64748b}\n.bl-font-field__panel-head h2{margin:.2rem 0 0;font-size:1.15rem}\n.bl-font-field__panel-head button{border:0;background:none;font:inherit;font-size:1.25rem;color:#64748b;cursor:pointer}\n.bl-font-field__search{margin-top:.9rem;min-height:2.5rem;padding:.5rem .75rem;border:1px solid #cbd5e1;border-radius:10px;font:inherit}\n.bl-font-field__filters{display:flex;flex-wrap:wrap;gap:.4rem;margin-top:.75rem}\n.bl-font-field__filters button{min-height:1.8rem;padding:.2rem .7rem;border:0;border-radius:999px;background:#f1f5f9;color:#475569;font:inherit;font-size:12px;cursor:pointer}\n.bl-font-field__filters button[data-on]{background:#0f172a;color:#fff}\n.bl-font-field__menu{margin:.75rem 0 0;padding:0;list-style:none;overflow:auto;max-height:18rem}\n.bl-font-field__option{display:flex;flex-direction:column;gap:2px;margin-bottom:.5rem;padding:.75rem .85rem;border:1px solid #e2e8f0;border-radius:12px;cursor:pointer}\n.bl-font-field__option[aria-selected=\"true\"]{border-color:#7c1fa2;background:#f5f3ff}\n.bl-font-field__family{font-weight:600}\n.bl-font-field__hint{color:#64748b;font-size:12px}\n.bl-font-field__specimen{margin-top:.45rem;font-size:1.25rem;line-height:1.3}\n`;\n","import { useFormFields } from \"@payloadcms/ui\";\nimport { findFont, fontFaceCss, type FontId } from \"@bison-lab/fonts\";\nimport type { UIFieldClientComponent } from \"payload\";\n\nimport { SAME_AS_BODY } from \"../theme/fields\";\nimport { usePreviewCanvas } from \"./preview-mode\";\nimport { TypographyPairing, TYPOGRAPHY_PAIRING_CSS } from \"./typography-pairing\";\n\n/**\n * Pairing sample only — no weight, letter-spacing, line-height, or health\n * scores. Faces load from the site's font route.\n */\nexport const PairingField: UIFieldClientComponent = ({ field }) => {\n const custom = (field.admin?.custom ?? {}) as { fontsBaseUrl?: string };\n const fontsBaseUrl = custom.fontsBaseUrl ?? \"/fonts\";\n const { body, heading } = useFormFields(([fields]) => {\n const record = fields as Record<string, { value?: unknown } | undefined>;\n return {\n body: String(record[\"typography.body\"]?.value ?? \"\"),\n heading: String(record[\"typography.heading\"]?.value ?? SAME_AS_BODY),\n };\n });\n const headingId = heading || body;\n const bodyFont = findFont(body);\n const headingFont = findFont(headingId);\n const ids = [body, headingId].filter(Boolean) as FontId[];\n const canvas = usePreviewCanvas();\n\n return (\n <div className={`field-type bl-pairing-field ${canvas.className}`} data-preview={canvas.mode} style={canvas.style}>\n <style href=\"bl-pairing\" precedence=\"default\">\n {TYPOGRAPHY_PAIRING_CSS}\n </style>\n {ids.length > 0 ? <style data-bl-font-faces=\"\">{fontFaceCss(ids, fontsBaseUrl)}</style> : null}\n <TypographyPairing\n headingFamily={headingFont?.family ?? \"Georgia\"}\n bodyFamily={bodyFont?.family ?? \"system-ui\"}\n />\n </div>\n );\n};\n","import { APPEARANCE_CHOICES, APPEARANCE_FAMILY_COPY } from \"../theme/appearance-labels\";\n\ntype Family = keyof typeof APPEARANCE_CHOICES;\n\nfunction ChoicePreview({ family, value }: { family: Family; value: string }) {\n return (\n <div className=\"bl-appearance__preview\" data-family={family} data-value={value} aria-hidden=\"true\">\n {family === \"defaultTheme\" && value === \"system\" ? (\n <>\n <div className=\"bl-appearance__pane bl-appearance__pane--light\">\n <i />\n <b />\n </div>\n <div className=\"bl-appearance__pane bl-appearance__pane--dark\">\n <i />\n <b />\n </div>\n </>\n ) : family === \"motion\" ? (\n <span className=\"bl-appearance__dot\" />\n ) : family === \"shadow\" ? (\n <div className=\"bl-appearance__lift\" />\n ) : family === \"radius\" ? (\n <>\n <b>Button</b>\n <i className=\"bl-appearance__input\" />\n <i className=\"bl-appearance__card\" />\n </>\n ) : family === \"density\" ? (\n <>\n <b />\n <i className=\"bl-appearance__input\" />\n <i className=\"bl-appearance__card\" />\n </>\n ) : (\n <>\n <i />\n <i />\n <b />\n </>\n )}\n </div>\n );\n}\n\nexport function AppearanceChoices({\n values,\n onChange,\n readOnly,\n}: {\n values: Record<Family, string>;\n onChange: (name: Family, value: string) => void;\n readOnly?: boolean;\n}) {\n return (\n <div className=\"bl-appearance\">\n <header className=\"bl-appearance__intro\">\n <h2>Set the overall feel of your site</h2>\n <p>\n Choose how rounded, elevated, animated, and spacious the interface feels. You don’t manage the\n technical values — the system handles those.\n </p>\n </header>\n {(Object.keys(APPEARANCE_CHOICES) as Family[]).map((family) => {\n const choices = APPEARANCE_CHOICES[family];\n const copy = APPEARANCE_FAMILY_COPY[family];\n return (\n <fieldset key={family} className=\"bl-appearance__family\">\n <legend>\n <strong>{copy.title}</strong>\n <span>{copy.hint}</span>\n </legend>\n <div className=\"bl-appearance__choices\" data-family={family}>\n {Object.entries(choices).map(([value, item]) => {\n const selected = values[family] === value;\n return (\n <label\n key={value}\n className=\"bl-appearance__choice\"\n data-selected={selected ? \"\" : undefined}\n >\n <input\n type=\"radio\"\n name={family}\n value={value}\n checked={selected}\n disabled={readOnly}\n onChange={() => onChange(family, value)}\n />\n <ChoicePreview family={family} value={value} />\n <span className=\"bl-appearance__copy\">\n <strong>\n {item.label}\n {selected ? <em aria-hidden=\"true\">✓</em> : null}\n </strong>\n <span>{item.hint}</span>\n </span>\n </label>\n );\n })}\n </div>\n {family === \"motion\" ? (\n <p className=\"bl-appearance__note\">\n Visitors who prefer reduced motion will still see fewer animations automatically.\n </p>\n ) : null}\n </fieldset>\n );\n })}\n </div>\n );\n}\n\nexport const APPEARANCE_CHOICES_CSS = `\n.bl-appearance{display:flex;flex-direction:column;gap:1.25rem;color:var(--bl-preview-text,inherit)}\n.bl-appearance__intro h2{margin:0;font-size:1.1rem}\n.bl-appearance__intro p{margin:.35rem 0 0;font-size:13px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b));max-width:40rem}\n.bl-appearance__family{margin:0;padding:1rem 1.1rem 1.15rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:12px;background:var(--bl-preview-card,var(--theme-elevation-0,#fff))}\n.bl-appearance__family legend{padding:0;margin-bottom:.85rem}\n.bl-appearance__family legend strong{display:block;font-size:14px}\n.bl-appearance__family legend span{display:block;margin-top:.25rem;font-size:12px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b));font-weight:400}\n.bl-appearance__choices{display:grid;gap:.6rem}\n.bl-appearance__choices[data-family=defaultTheme],.bl-appearance__choices[data-family=shadow],.bl-appearance__choices[data-family=motion],.bl-appearance__choices[data-family=density]{grid-template-columns:repeat(3,minmax(0,1fr))}\n.bl-appearance__choices[data-family=radius]{grid-template-columns:repeat(4,minmax(0,1fr))}\n.bl-appearance__choice{display:flex;flex-direction:column;gap:.65rem;padding:.75rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:12px;background:var(--bl-preview-bg,var(--theme-elevation-0,#fff));cursor:pointer}\n.bl-appearance__choice[data-selected]{box-shadow:inset 0 0 0 2px var(--bl-preview-text,#0f172a);border-color:var(--bl-preview-text,#0f172a)}\n.bl-appearance__choice input{position:absolute;opacity:0;pointer-events:none}\n.bl-appearance__copy{display:flex;flex-direction:column;gap:.2rem}\n.bl-appearance__copy strong{display:flex;justify-content:space-between;align-items:center;gap:.4rem;font-size:14px}\n.bl-appearance__copy em{font-style:normal}\n.bl-appearance__copy span{font-size:12px;color:var(--theme-elevation-500,#64748b)}\n.bl-appearance__note{margin:.75rem 0 0;font-size:12px;color:var(--theme-elevation-500,#64748b)}\n.bl-appearance__preview{--bl-preview-brand:#db0082;--bl-preview-radius:8px;border-radius:10px;background:#f8fafc;overflow:hidden}\n.bl-appearance__preview[data-family=defaultTheme]{display:grid;min-height:5.5rem;padding:.65rem}\n.bl-appearance__preview[data-family=defaultTheme][data-value=system]{grid-template-columns:1fr 1fr;padding:0}\n.bl-appearance__preview[data-family=defaultTheme][data-value=dark]{background:#020617}\n.bl-appearance__pane{display:flex;flex-direction:column;gap:.45rem;padding:.65rem}\n.bl-appearance__pane--dark{background:#020617}\n.bl-appearance__pane i,.bl-appearance__preview[data-family=defaultTheme] > i{display:block;height:.4rem;width:42%;border-radius:99px;background:#0f172a}\n.bl-appearance__pane i + i,.bl-appearance__preview[data-family=defaultTheme] > i + i{width:64%;background:#cbd5e1}\n.bl-appearance__pane--dark i{background:#fff}\n.bl-appearance__pane--dark i + i{background:#334155}\n.bl-appearance__preview[data-family=defaultTheme][data-value=dark] > i{background:#fff}\n.bl-appearance__preview[data-family=defaultTheme][data-value=dark] > i + i{background:#334155}\n.bl-appearance__pane b,.bl-appearance__preview[data-family=defaultTheme] > b{display:block;height:1.6rem;margin-top:auto;border-radius:6px;background:var(--bl-preview-brand)}\n.bl-appearance__pane--dark b{background:var(--bl-preview-brand)}\n.bl-appearance__preview[data-family=radius]{display:flex;flex-direction:column;gap:.45rem;padding:.65rem;background:#fff}\n.bl-appearance__preview[data-family=radius] b{display:grid;place-items:center;height:1.85rem;background:var(--bl-preview-brand);color:#fff;font-size:10px;font-weight:600;border-radius:var(--bl-preview-radius)}\n.bl-appearance__input{display:block;height:1.85rem;border:1px solid #cbd5e1;background:#f8fafc;border-radius:var(--bl-preview-radius)}\n.bl-appearance__card{display:block;height:2.4rem;border:1px solid #e2e8f0;background:#fff;border-radius:var(--bl-preview-radius)}\n.bl-appearance__preview[data-value=sharp]{--bl-preview-radius:0}\n.bl-appearance__preview[data-value=subtle]{--bl-preview-radius:6px}\n.bl-appearance__preview[data-value=rounded]{--bl-preview-radius:12px}\n.bl-appearance__preview[data-value=pill]{--bl-preview-radius:999px}\n.bl-appearance__preview[data-value=pill] .bl-appearance__card{--bl-preview-radius:1.25rem}\n.bl-appearance__preview[data-family=shadow]{display:grid;place-items:center;min-height:6.5rem;padding:.85rem}\n.bl-appearance__lift{width:100%;height:3.5rem;border-radius:10px;background:#fff}\n.bl-appearance__preview[data-value=flat] .bl-appearance__lift{border:1px solid #e2e8f0}\n.bl-appearance__preview[data-value=subtle] .bl-appearance__lift{box-shadow:0 1px 2px rgba(15,23,42,.06),0 4px 12px rgba(15,23,42,.06)}\n.bl-appearance__preview[data-value=elevated] .bl-appearance__lift{box-shadow:0 10px 30px rgba(15,23,42,.12)}\n.bl-appearance__preview[data-family=motion]{display:flex;align-items:center;min-height:4.5rem;padding:0 .85rem}\n.bl-appearance__dot{width:1.15rem;height:1.15rem;border-radius:999px;background:var(--bl-preview-brand);animation:bl-appear-dot 1.8s ease-in-out infinite}\n.bl-appearance__preview[data-value=snappy] .bl-appearance__dot{animation-duration:1s}\n.bl-appearance__preview[data-value=minimal] .bl-appearance__dot{animation-duration:2.5s}\n@keyframes bl-appear-dot{0%,100%{transform:translateX(0)}50%{transform:translateX(4.5rem)}}\n.bl-appearance__preview[data-family=density]{display:flex;flex-direction:column;background:#f8fafc}\n.bl-appearance__preview[data-value=compact]{gap:.4rem;padding:.55rem}\n.bl-appearance__preview[data-value=default]{gap:.65rem;padding:.8rem}\n.bl-appearance__preview[data-value=spacious]{gap:.9rem;padding:1.05rem}\n.bl-appearance__preview[data-family=density] b{display:block;height:1.7rem;background:var(--bl-preview-brand);border-radius:6px}\n.bl-appearance__preview[data-value=compact] b,.bl-appearance__preview[data-value=compact] .bl-appearance__input{height:1.45rem}\n.bl-appearance__preview[data-value=spacious] b,.bl-appearance__preview[data-value=spacious] .bl-appearance__input{height:2.1rem}\n@media (max-width:720px){\n .bl-appearance__choices[data-family=defaultTheme],.bl-appearance__choices[data-family=shadow],.bl-appearance__choices[data-family=motion],.bl-appearance__choices[data-family=density],.bl-appearance__choices[data-family=radius]{grid-template-columns:1fr}\n}\n@media (prefers-reduced-motion:reduce){\n .bl-appearance__dot{animation:none}\n}\n`;\n","import { useField } from \"@payloadcms/ui\";\nimport type { GroupFieldClientComponent } from \"payload\";\n\nimport { APPEARANCE_CHOICES } from \"../theme/appearance-labels\";\nimport { AppearanceChoices, APPEARANCE_CHOICES_CSS } from \"./appearance-choices\";\nimport { usePreviewCanvas } from \"./preview-mode\";\n\ntype Family = keyof typeof APPEARANCE_CHOICES;\n\n/**\n * Named appearance choices. Soft → pill, Gentle → minimal, Balanced →\n * default, Follow device → system. No rem or ms.\n */\nexport const AppearanceField: GroupFieldClientComponent = ({ path, readOnly }) => {\n const defaultTheme = useField<string>({ path: `${path}.defaultTheme` });\n const radius = useField<string>({ path: `${path}.radius` });\n const shadow = useField<string>({ path: `${path}.shadow` });\n const motion = useField<string>({ path: `${path}.motion` });\n const density = useField<string>({ path: `${path}.density` });\n const fields = { defaultTheme, radius, shadow, motion, density };\n const canvas = usePreviewCanvas();\n\n function onChange(name: Family, value: string) {\n fields[name].setValue(value);\n }\n\n return (\n <div className={`field-type bl-appearance-field ${canvas.className}`} data-preview={canvas.mode} style={canvas.style}>\n <style href=\"bl-appearance\" precedence=\"default\">\n {APPEARANCE_CHOICES_CSS}\n </style>\n <AppearanceChoices\n values={{\n defaultTheme: defaultTheme.value ?? \"system\",\n radius: radius.value ?? \"rounded\",\n shadow: shadow.value ?? \"subtle\",\n motion: motion.value ?? \"smooth\",\n density: density.value ?? \"default\",\n }}\n onChange={onChange}\n readOnly={readOnly}\n />\n </div>\n );\n};\n","import { GREY_SCALES, presetHints, type GreyScale } from \"@bison-lab/tokens\";\nimport { useField } from \"@payloadcms/ui\";\nimport type { SelectFieldClientComponent } from \"payload\";\n\nimport { usePreviewCanvas } from \"./preview-mode\";\n\nconst FAMILIES = Object.keys(presetHints.greyScale) as GreyScale[];\nconst SWATCHES = [\"50\", \"200\", \"400\", \"700\", \"950\"] as const;\n\nexport function GreyScaleChoices({\n value,\n onChange,\n readOnly,\n}: {\n value: GreyScale;\n onChange: (next: GreyScale) => void;\n readOnly?: boolean;\n}) {\n const canvas = usePreviewCanvas();\n return (\n <section className={`bl-grey ${canvas.className}`} data-preview={canvas.mode} style={canvas.style}>\n <div className=\"bl-grey__section\">\n <h2>Neutrals</h2>\n <p>Choose the gray family used for backgrounds, borders, cards, inputs, and muted text.</p>\n </div>\n <header className=\"bl-grey__head\">\n <div>\n <h2>Gray family</h2>\n <p>Choose the neutral family used for page backgrounds, cards, borders, inputs, and muted text. Readability for these system neutrals is handled automatically.</p>\n </div>\n <span className=\"bl-grey__badge\">Required</span>\n </header>\n <div className=\"bl-grey__choices\">\n {FAMILIES.map((id) => {\n const copy = presetHints.greyScale[id];\n const selected = value === id;\n return (\n <label key={id} className=\"bl-grey__choice\" data-selected={selected ? \"\" : undefined}>\n <input\n type=\"radio\"\n name=\"greyScale\"\n value={id}\n checked={selected}\n disabled={readOnly}\n onChange={() => onChange(id)}\n />\n <span className=\"bl-grey__ramp\" aria-hidden=\"true\">\n {SWATCHES.map((step) => (\n <i key={step} style={{ background: `hsl(${GREY_SCALES[id][step]})` }} />\n ))}\n </span>\n <strong>\n {copy.label}\n {selected ? <em aria-hidden=\"true\">✓</em> : null}\n </strong>\n <span>{copy.hint}</span>\n </label>\n );\n })}\n </div>\n </section>\n );\n}\n\n/**\n * Visual picker over the five grey-scale presets. Replaces the stock select\n * on Colors; the stored value is still `colors.greyScale`.\n */\nexport const GreyScaleField: SelectFieldClientComponent = ({ field, path, readOnly }) => {\n const dataPath =\n typeof field.admin?.custom?.dataPath === \"string\" ? field.admin.custom.dataPath : path;\n const { value, setValue } = useField<GreyScale>({ path: dataPath });\n\n return (\n <div className=\"field-type bl-grey-field\">\n <style href=\"bl-grey\" precedence=\"default\">\n {GREY_SCALE_FIELD_CSS}\n </style>\n <GreyScaleChoices value={value ?? \"slate\"} onChange={setValue} readOnly={readOnly} />\n </div>\n );\n};\n\nexport const GREY_SCALE_FIELD_CSS = `\n.bl-grey{margin:0 0 1.75rem}\n.bl-grey__section{margin:1.25rem 0 .85rem}\n.bl-grey__section h2{margin:0;font-size:1.1rem}\n.bl-grey__section p{margin:.35rem 0 0;max-width:40rem;font-size:13px;color:color-mix(in srgb,var(--theme-text,#f8fafc) 92%,transparent)}\n.bl-grey__head{display:flex;justify-content:space-between;align-items:flex-start;gap:1rem;margin:0;padding:1.1rem 1.15rem .85rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-bottom:0;border-radius:12px 12px 0 0;background:var(--bl-preview-card,var(--theme-elevation-0,#fff));color:var(--bl-preview-text,inherit)}\n.bl-grey__head h2{margin:0;font-size:1.1rem}\n.bl-grey__head p{margin:.35rem 0 0;max-width:40rem;font-size:13px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b))}\n.bl-grey__badge{font:inherit;font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:.15rem .45rem;border-radius:999px;background:#e2e8f0;color:#0f172a}\n.bl-grey__choices{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:.6rem;padding:0 1.15rem 1.15rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-top:0;border-radius:0 0 12px 12px;background:var(--bl-preview-card,var(--theme-elevation-0,#fff));color:var(--bl-preview-text,inherit)}\n.bl-grey__choice{display:flex;flex-direction:column;gap:.45rem;padding:.75rem;border:1px solid var(--bl-preview-border,var(--theme-elevation-150,#e2e8f0));border-radius:12px;background:var(--bl-preview-bg,var(--theme-elevation-0,#fff));color:inherit;cursor:pointer}\n.bl-grey__choice[data-selected]{box-shadow:inset 0 0 0 2px var(--bl-preview-text,#0f172a);border-color:var(--bl-preview-text,#0f172a)}\n.bl-grey__choice input{position:absolute;opacity:0;pointer-events:none}\n.bl-grey__ramp{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:3px}\n.bl-grey__ramp i{display:block;height:2rem;border-radius:6px}\n.bl-grey__choice strong{display:flex;justify-content:space-between;align-items:center;gap:.4rem;font-size:14px}\n.bl-grey__choice em{font-style:normal}\n.bl-grey__choice > span{font-size:12px;color:var(--bl-preview-muted,var(--theme-elevation-500,#64748b))}\n@media (max-width:720px){.bl-grey__choices{grid-template-columns:1fr}}\n`;\n","import { useFormFields } from \"@payloadcms/ui\";\nimport { isThemeHex } from \"@bison-lab/tokens\";\nimport type { UIFieldClientComponent } from \"payload\";\nimport { useRef } from \"react\";\n\nimport { SYSTEM_COLOR_COPY } from \"../theme/appearance-labels\";\nimport { fillLabelWarning, READABILITY_TARGET, type FillLabelWarning } from \"../theme/readability\";\nimport { SYSTEM_COLOR_KEYS } from \"../theme/types\";\nimport { THEME_COLORS_LAYOUT_CSS } from \"./colors-layout\";\nimport { ReadabilityList, READABILITY_LIST_CSS } from \"./readability-list\";\n\nfunction hexAt(fields: Record<string, { value?: unknown } | undefined>, path: string): string {\n const value = fields[path]?.value;\n return typeof value === \"string\" ? value : \"\";\n}\n\n/**\n * Fill + automatic label only. Target 7:1, Light and Dark. No gray\n * ContrastStrip. Warnings do not block save.\n */\nexport const ContrastReport: UIFieldClientComponent = ({ field }) => {\n const target = Number((field.admin?.custom as { target?: number } | undefined)?.target) || READABILITY_TARGET;\n const hexes = useFormFields(([fields]) => {\n const record = fields as Record<string, { value?: unknown } | undefined>;\n const system = Object.fromEntries(\n SYSTEM_COLOR_KEYS.map((key) => [key, hexAt(record, `colors.brand.${key}.hex`)]),\n ) as Record<(typeof SYSTEM_COLOR_KEYS)[number], string>;\n const library = record[\"colors.library\"]?.value;\n const custom = Array.isArray(library)\n ? library.flatMap((row, index) => {\n const hex = typeof row === \"object\" && row && \"hex\" in row ? String(row.hex ?? \"\") : \"\";\n const name =\n typeof row === \"object\" && row && \"label\" in row ? String(row.label ?? row.key ?? \"Custom\") : \"Custom\";\n return hex ? [{ id: `library-${index}`, name, hex }] : [];\n })\n : [];\n return { system, custom };\n });\n\n const last = useRef<FillLabelWarning[] | null>(null);\n const complete = SYSTEM_COLOR_KEYS.every((key) => isThemeHex(hexes.system[key]));\n if (complete) {\n last.current = [\n ...SYSTEM_COLOR_KEYS.map((key) =>\n fillLabelWarning(key, SYSTEM_COLOR_COPY[key].label, hexes.system[key], target),\n ),\n ...hexes.custom.map((row) => fillLabelWarning(row.id, row.name, row.hex, target)),\n ].filter((item): item is FillLabelWarning => item !== null);\n }\n\n const warnings = last.current ?? [];\n const stale = Boolean(last.current) && !complete;\n\n return (\n <div className=\"field-type bl-contrast-report\">\n <style href=\"bl-readability\" precedence=\"default\">\n {READABILITY_LIST_CSS}\n </style>\n <style href=\"bl-theme-colors-layout\" precedence=\"default\">\n {THEME_COLORS_LAYOUT_CSS}\n </style>\n {stale ? (\n <p className=\"bl-contrast-report__stale\">Showing the last complete audit while a colour is being typed.</p>\n ) : null}\n {warnings.length > 0 ? <ReadabilityList warnings={warnings} target={target} /> : (\n <p>Enter hex colours to measure the automatic label on each fill.</p>\n )}\n </div>\n );\n};\n","import type { UIFieldClientComponent } from \"payload\";\n\nimport { THEME_COLORS_LAYOUT_CSS } from \"./colors-layout\";\n\n/**\n * Unnamed UI heading between Theme fields. No document path.\n */\nexport const SectionHeading: UIFieldClientComponent = ({ field }) => {\n const custom = (field.admin?.custom ?? {}) as { title?: string; hint?: string };\n if (!custom.title) return null;\n return (\n <header className=\"bl-section-heading\">\n <style href=\"bl-section-heading\" precedence=\"default\">\n {CSS}\n </style>\n <style href=\"bl-theme-colors-layout\" precedence=\"default\">\n {THEME_COLORS_LAYOUT_CSS}\n </style>\n <h2>{custom.title}</h2>\n {custom.hint ? <p>{custom.hint}</p> : null}\n </header>\n );\n};\n\nconst CSS = `\n.bl-section-heading{margin:1.25rem 0 .65rem}\n.bl-section-heading:first-child{margin-top:0}\n.bl-section-heading h2{margin:0;font-size:1.1rem}\n.bl-section-heading p{margin:.35rem 0 0;font-size:13px;color:color-mix(in srgb,var(--theme-text,#f8fafc) 92%,transparent);max-width:40rem}\n`;\n","import { SYSTEM_COLOR_KEYS, type ThemeDoc, type ThemeLibraryColorDoc } from \"./types\";\nimport type { ThemeChild } from \"./publish\";\n\n/** Payload may hand an empty array field as `{}`. `.map` on that crashes the Theme form. */\nexport function libraryRows(value: unknown): ThemeLibraryColorDoc[] {\n return Array.isArray(value) ? value : [];\n}\n\nfunction colorLine(name: string, before: unknown, after: unknown): string | null {\n const a = before && typeof before === \"object\" ? before : { hex: before };\n const b = after && typeof after === \"object\" ? after : { hex: after };\n const left = a as { hex?: unknown; sourceStep?: unknown };\n const right = b as { hex?: unknown; sourceStep?: unknown };\n if (left.hex === right.hex && String(left.sourceStep) === String(right.sourceStep)) return null;\n return `${name}: ${String(left.hex ?? \"—\")} → ${String(right.hex ?? \"—\")}`;\n}\n\n/**\n * Human lines for the Publish confirmation. Only this child's\n * differences; other responsibilities are not listed.\n */\nexport function themeChildChanges(child: ThemeChild, published: ThemeDoc, incoming: ThemeDoc): string[] {\n if (child === \"colors\") {\n const lines: string[] = [];\n for (const key of SYSTEM_COLOR_KEYS) {\n const line = colorLine(\n key[0].toUpperCase() + key.slice(1),\n published.colors?.brand?.[key],\n incoming.colors?.brand?.[key],\n );\n if (line) lines.push(line);\n }\n const beforeKeys = libraryRows(published.colors?.library)\n .map((row) => row.key)\n .join(\", \");\n const afterKeys = libraryRows(incoming.colors?.library)\n .map((row) => row.key)\n .join(\", \");\n if (beforeKeys !== afterKeys) lines.push(`Custom colors: ${beforeKeys || \"none\"} → ${afterKeys || \"none\"}`);\n if ((published.colors?.greyScale ?? \"\") !== (incoming.colors?.greyScale ?? \"\")) {\n lines.push(`Gray family: ${published.colors?.greyScale ?? \"—\"} → ${incoming.colors?.greyScale ?? \"—\"}`);\n }\n return lines;\n }\n if (child === \"typography\") {\n const lines: string[] = [];\n if ((published.typography?.heading ?? \"\") !== (incoming.typography?.heading ?? \"\")) {\n lines.push(`Heading: ${published.typography?.heading || \"same as body\"} → ${incoming.typography?.heading || \"same as body\"}`);\n }\n if ((published.typography?.body ?? \"\") !== (incoming.typography?.body ?? \"\")) {\n lines.push(`Body: ${published.typography?.body ?? \"—\"} → ${incoming.typography?.body ?? \"—\"}`);\n }\n return lines;\n }\n if (child === \"appearance\") {\n const keys = [\"defaultTheme\", \"radius\", \"shadow\", \"motion\", \"density\"] as const;\n return keys.flatMap((key) => {\n const left = published.appearance?.[key] ?? \"\";\n const right = incoming.appearance?.[key] ?? \"\";\n return left === right ? [] : [`${key}: ${left || \"—\"} → ${right || \"—\"}`];\n });\n }\n const lines: string[] = [];\n if (uploadId(published.logo) !== uploadId(incoming.logo)) lines.push(\"Logo updated\");\n if (uploadId(published.favicon) !== uploadId(incoming.favicon)) lines.push(\"Favicon updated\");\n if (uploadId(published.logoMark) !== uploadId(incoming.logoMark)) lines.push(\"Mobile menu logo updated\");\n return lines;\n}\n\nfunction uploadId(value: ThemeDoc[\"logo\"]): string {\n if (value && typeof value === \"object\" && value.id != null) return String(value.id);\n if (typeof value === \"string\" || typeof value === \"number\") return String(value);\n return \"\";\n}\n","import { THEME_SLUG, type ThemeColorDoc, type ThemeDoc } from \"./types\";\n\nexport const THEME_CHILDREN = [\"colors\", \"typography\", \"appearance\", \"identity\"] as const;\n\nexport type ThemeChild = (typeof THEME_CHILDREN)[number];\n\n/**\n * Publishing a child writes that slice only. Other responsibilities stay\n * as they already are on the stored document. Unsaved form state on a\n * different child never goes live. A first save (no stored row) still\n * writes only the named child; `getPublishedTheme` fills the rest from\n * the seed.\n */\nexport function publishThemeChild(stored: ThemeDoc, incoming: ThemeDoc, child: ThemeChild): ThemeDoc {\n if (child === \"colors\") return { ...stored, colors: incoming.colors };\n if (child === \"typography\") return { ...stored, typography: incoming.typography };\n if (child === \"appearance\") return { ...stored, appearance: incoming.appearance };\n return { ...stored, logo: incoming.logo, favicon: incoming.favicon, logoMark: incoming.logoMark };\n}\n\nexport function isThemeChild(value: unknown): value is ThemeChild {\n return typeof value === \"string\" && (THEME_CHILDREN as readonly string[]).includes(value);\n}\n\nexport function sliceFromTheme(theme: ThemeDoc, child: ThemeChild): ThemeDoc {\n if (child === \"colors\") return { colors: theme.colors };\n if (child === \"typography\") return { typography: theme.typography };\n if (child === \"appearance\") return { appearance: theme.appearance };\n return { logo: theme.logo, favicon: theme.favicon, logoMark: theme.logoMark };\n}\n\nfunction colorHex(color: ThemeColorDoc | string | null | undefined): string | undefined {\n if (typeof color === \"string\") return color;\n return color?.hex ?? undefined;\n}\n\n/**\n * A Theme page is a real Global. Hydrate from the store only when this\n * page has never been saved — otherwise afterRead would overwrite the form.\n */\nexport function hasThemeSlice(doc: ThemeDoc | null | undefined, child: ThemeChild): boolean {\n if (!doc) return false;\n if (child === \"colors\") return Boolean(colorHex(doc.colors?.brand?.primary));\n if (child === \"typography\") return Boolean(doc.typography?.body);\n if (child === \"appearance\") return Boolean(doc.appearance?.radius);\n return Boolean(doc.logo || doc.favicon || doc.logoMark);\n}\n\nexport interface ThemeStorePayload {\n findGlobal: (args: {\n slug: string;\n draft?: boolean;\n depth?: number;\n overrideAccess?: boolean;\n }) => Promise<ThemeDoc | null | undefined>;\n updateGlobal: (args: { slug: string; data: ThemeDoc; draft?: boolean }) => Promise<unknown>;\n}\n\n/**\n * Save on a Theme page writes that slice onto the hidden `theme` row.\n * Other children stay as stored.\n */\nexport async function persistThemeChild(\n payload: ThemeStorePayload,\n incoming: ThemeDoc,\n child: ThemeChild,\n): Promise<ThemeDoc> {\n const stored =\n (await payload.findGlobal({\n slug: THEME_SLUG,\n draft: false,\n overrideAccess: true,\n })) ?? {};\n const next = publishThemeChild(stored, incoming, child);\n await payload.updateGlobal({ slug: THEME_SLUG, data: next, draft: false });\n return next;\n}\n","import type { FillLabelWarning } from \"../theme/readability\";\nimport { ThemePortal } from \"./portal\";\nimport {\n hardToReadModes,\n hslCss,\n READABILITY_PUBLISH_NOTE,\n readabilityHeadline,\n} from \"../theme/readability\";\n\nexport interface PublishConfirmProps {\n childLabel: string;\n changes: string[];\n shorts?: FillLabelWarning[];\n onKeepEditing: () => void;\n onPublish: () => void;\n busy?: boolean;\n}\n\nconst OTHER_CHILDREN: Record<string, string> = {\n Colors: \"Typography, Appearance, and Identity stay as they are.\",\n Typography: \"Colors, Appearance, and Identity stay as they are.\",\n Appearance: \"Colors, Typography, and Identity stay as they are.\",\n Identity: \"Colors, Typography, and Appearance stay as they are.\",\n};\n\nexport function PublishConfirm({\n childLabel,\n changes,\n shorts,\n onKeepEditing,\n onPublish,\n busy,\n}: PublishConfirmProps) {\n const remaining = shorts?.filter((item) => !item.meets) ?? [];\n return (\n <ThemePortal>\n <div className=\"bl-publish\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"bl-publish-title\">\n <div className=\"bl-publish__panel\">\n <h2 id=\"bl-publish-title\">Publish {childLabel}</h2>\n <p>\n These {childLabel.toLowerCase()} changes go live now.{\" \"}\n {OTHER_CHILDREN[childLabel] ?? \"The other Theme sections stay as they are.\"}\n </p>\n {changes.length === 0 ? (\n <p className=\"bl-publish__empty\">No changes to publish.</p>\n ) : (\n <ul>\n {changes.map((change) => (\n <li key={change}>{change}</li>\n ))}\n </ul>\n )}\n {remaining.length > 0 ? (\n <div className=\"bl-publish__shorts\">\n <strong>Some colors may be hard to read</strong>\n <ul>\n {remaining.map((item) => (\n <li key={item.id}>\n <span\n aria-hidden=\"true\"\n className=\"bl-publish__swatch\"\n style={{ background: hslCss(item.light.fill), color: hslCss(item.light.label) }}\n >\n Aa\n </span>\n <span>\n {readabilityHeadline(item).replace(/^Text on /, \"\")} {hardToReadModes(item)}.\n </span>\n </li>\n ))}\n </ul>\n <p>{READABILITY_PUBLISH_NOTE}</p>\n </div>\n ) : null}\n <div className=\"bl-publish__actions\">\n <button type=\"button\" className=\"bl-publish__cancel\" onClick={onKeepEditing}>\n Cancel\n </button>\n <button type=\"button\" className=\"bl-publish__go\" disabled={busy || changes.length === 0} onClick={onPublish}>\n {remaining.length > 0 ? \"Publish anyway\" : \"Publish\"}\n </button>\n </div>\n </div>\n </div>\n </ThemePortal>\n );\n}\n\nexport const PUBLISH_CONFIRM_CSS = `\n.bl-publish{position:fixed;inset:0;z-index:10000;display:grid;place-items:center;padding:1rem;background:rgba(15,23,42,.45)}\n.bl-publish__panel{width:min(36rem,100%);padding:1.25rem 1.35rem;border-radius:16px;background:#fff;color:#0f172a;color-scheme:light;box-shadow:0 24px 60px rgba(15,23,42,.2)}\n.bl-publish__panel h2{margin:0;color:#0f172a}\n.bl-publish__panel p{margin:.5rem 0 0;color:#475569}\n.bl-publish__empty{font-style:italic;color:#64748b}\n.bl-publish__panel > ul{margin:.75rem 0 0;padding-left:1.1rem;color:#0f172a}\n.bl-publish__shorts{margin-top:1rem;padding:.85rem .9rem;border-radius:10px;background:#fffbeb;color:#0f172a}\n.bl-publish__shorts strong{display:block}\n.bl-publish__shorts ul{margin:.65rem 0 0;padding:0;list-style:none}\n.bl-publish__shorts li{display:flex;gap:.65rem;align-items:center;margin-top:.45rem;font-size:13px;color:#0f172a}\n.bl-publish__swatch{flex:none;display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:1.6rem;border-radius:6px;font-weight:700;font-size:12px}\n.bl-publish__shorts p{margin:.65rem 0 0;font-size:13px;color:#475569}\n.bl-publish__actions{display:flex;justify-content:flex-end;gap:.6rem;margin-top:1.1rem}\n.bl-publish__actions button{min-height:2.25rem;padding:.4rem .9rem;border-radius:8px;font:inherit;cursor:pointer}\n.bl-publish__cancel{border:1px solid #cbd5e1;background:#fff;color:#0f172a}\n.bl-publish__go{border:0;background:#0f172a;color:#fff;font-weight:600}\n.bl-publish__actions button:disabled{opacity:.45;cursor:not-allowed}\n`;\n","import { useField, useForm, useFormFields } from \"@payloadcms/ui\";\nimport type { UIFieldClientComponent } from \"payload\";\nimport { useMemo, useState } from \"react\";\n\nimport { SYSTEM_COLOR_COPY } from \"../theme/appearance-labels\";\nimport { themeChildChanges } from \"../theme/changes\";\nimport { isThemeChild, type ThemeChild } from \"../theme/publish\";\nimport { fillLabelWarning, type FillLabelWarning } from \"../theme/readability\";\nimport { SYSTEM_COLOR_KEYS, type ThemeColorDoc, type ThemeDoc, type ThemeLibraryColorDoc } from \"../theme/types\";\nimport { ThemePreviewToggle, THEME_PREVIEW_TOGGLE_CSS } from \"./preview-mode\";\nimport { PublishConfirm, PUBLISH_CONFIRM_CSS } from \"./publish-confirm\";\n\nconst LABELS: Record<ThemeChild, string> = {\n colors: \"Colors\",\n typography: \"Typography\",\n appearance: \"Appearance\",\n identity: \"Identity\",\n};\n\nfunction asColor(value: unknown): ThemeColorDoc | undefined {\n if (value && typeof value === \"object\") return value as ThemeColorDoc;\n if (typeof value === \"string\") return { hex: value };\n return undefined;\n}\n\nfunction formDoc(fields: Record<string, { value?: unknown } | undefined>): ThemeDoc {\n const brand = Object.fromEntries(\n SYSTEM_COLOR_KEYS.map((key) => [\n key,\n {\n hex: fields[`colors.brand.${key}.hex`]?.value as string | undefined,\n sourceStep: fields[`colors.brand.${key}.sourceStep`]?.value as ThemeColorDoc[\"sourceStep\"],\n },\n ]),\n ) as NonNullable<NonNullable<ThemeDoc[\"colors\"]>[\"brand\"]>;\n return {\n colors: {\n brand,\n library: Array.isArray(fields[\"colors.library\"]?.value)\n ? (fields[\"colors.library\"]?.value as ThemeLibraryColorDoc[])\n : [],\n greyScale: fields[\"colors.greyScale\"]?.value as NonNullable<ThemeDoc[\"colors\"]>[\"greyScale\"],\n },\n typography: {\n body: fields[\"typography.body\"]?.value as string | undefined,\n heading: fields[\"typography.heading\"]?.value as string | undefined,\n },\n appearance: {\n defaultTheme: fields[\"appearance.defaultTheme\"]?.value as NonNullable<ThemeDoc[\"appearance\"]>[\"defaultTheme\"],\n radius: fields[\"appearance.radius\"]?.value as NonNullable<ThemeDoc[\"appearance\"]>[\"radius\"],\n shadow: fields[\"appearance.shadow\"]?.value as NonNullable<ThemeDoc[\"appearance\"]>[\"shadow\"],\n motion: fields[\"appearance.motion\"]?.value as NonNullable<ThemeDoc[\"appearance\"]>[\"motion\"],\n density: fields[\"appearance.density\"]?.value as NonNullable<ThemeDoc[\"appearance\"]>[\"density\"],\n },\n logo: fields.logo?.value as ThemeDoc[\"logo\"],\n favicon: fields.favicon?.value as ThemeDoc[\"favicon\"],\n logoMark: fields.logoMark?.value as ThemeDoc[\"logoMark\"],\n };\n}\n\nfunction publishedDoc(fields: Record<string, { initialValue?: unknown; value?: unknown } | undefined>): ThemeDoc {\n return formDoc(\n Object.fromEntries(Object.entries(fields).map(([path, field]) => [path, { value: field?.initialValue }])),\n );\n}\n\nfunction shortsFrom(doc: ThemeDoc): FillLabelWarning[] {\n const brand = doc.colors?.brand ?? {};\n const custom = doc.colors?.library ?? [];\n return [\n ...SYSTEM_COLOR_KEYS.flatMap((key) => {\n const hex = asColor(brand[key])?.hex;\n const warning = typeof hex === \"string\" ? fillLabelWarning(key, SYSTEM_COLOR_COPY[key].label, hex) : null;\n return warning ? [warning] : [];\n }),\n ...custom.flatMap((row, index) => {\n const warning = row.hex ? fillLabelWarning(`library-${index}`, row.label ?? row.key ?? \"Custom\", row.hex) : null;\n return warning ? [warning] : [];\n }),\n ];\n}\n\n/**\n * Per-child Publish. Lives in the document Save slot so Payload's\n * `--doc-controls-height` row is the action row, not an empty gap.\n * Sets `publishChild` then submits; `beforeChange` writes only that slice.\n * On Colors, remaining automatic-label shorts open in this modal only.\n */\nexport function ThemePublishActions({ child }: { child: ThemeChild }) {\n const label = LABELS[child];\n const { submit } = useForm();\n const publishChild = useField<string>({ path: \"publishChild\" });\n const snapshot = useFormFields(([fields]) => {\n const record = fields as Record<string, { initialValue?: unknown; value?: unknown } | undefined>;\n return { incoming: formDoc(record), published: publishedDoc(record) };\n });\n const [open, setOpen] = useState(false);\n const [busy, setBusy] = useState(false);\n\n const changes = useMemo(\n () => themeChildChanges(child, snapshot.published, snapshot.incoming),\n [child, snapshot],\n );\n const shorts = child === \"colors\" ? shortsFrom(snapshot.incoming) : undefined;\n\n async function publish() {\n setBusy(true);\n publishChild.setValue(child);\n try {\n await submit();\n setOpen(false);\n } finally {\n setBusy(false);\n }\n }\n\n return (\n <div className=\"bl-publish-child\">\n <style href=\"bl-publish\" precedence=\"default\">\n {PUBLISH_CONFIRM_CSS}\n </style>\n <style href=\"bl-publish-child\" precedence=\"default\">\n {`${THEME_PREVIEW_TOGGLE_CSS}.bl-publish-child{display:flex;align-items:center;justify-content:flex-end;gap:.5rem}.bl-publish-child__button{min-height:2.25rem;padding:.4rem 1rem;border:0;border-radius:8px;background:var(--theme-text,#0f172a);color:var(--theme-bg,#fff);font:inherit;font-weight:600;cursor:pointer}`}\n </style>\n {child !== \"identity\" ? (\n <>\n <ThemePreviewToggle />\n </>\n ) : null}\n <button type=\"button\" className=\"bl-publish-child__button\" onClick={() => setOpen(true)}>\n Publish {label}\n </button>\n {open ? (\n <PublishConfirm\n childLabel={label}\n changes={changes}\n shorts={shorts}\n busy={busy}\n onKeepEditing={() => setOpen(false)}\n onPublish={() => {\n void publish();\n }}\n />\n ) : null}\n </div>\n );\n}\n\n/** @deprecated Alias — Theme pages use ThemePublishActions; tabbed Save used this name. */\nexport const ThemePublishControls = ThemePublishActions;\n\nexport const PublishChild: UIFieldClientComponent = ({ field }) => {\n const child = (field.admin?.custom as { child?: string } | undefined)?.child;\n if (!isThemeChild(child)) return null;\n return <ThemePublishActions child={child} />;\n};\n","import { THEME_CHILDREN, type ThemeChild } from \"../theme/publish\";\n\nexport const THEME_TAB_LABELS = {\n colors: \"Colors\",\n typography: \"Typography\",\n appearance: \"Appearance\",\n identity: \"Identity\",\n} as const satisfies Record<ThemeChild, string>;\n\n/**\n * The selected Payload field tab on Theme. Defaults to Colors when the\n * tabs have not painted yet (SSR, first paint).\n */\nexport function readActiveThemeTab(root: ParentNode | null | undefined = typeof document === \"undefined\" ? null : document): ThemeChild {\n if (!root) return \"colors\";\n const selected =\n root.querySelector('.tabs-field__tab-button[aria-selected=\"true\"]') ??\n root.querySelector(\".tabs-field__tab-button--active\") ??\n root.querySelector('[role=\"tab\"][aria-selected=\"true\"]');\n const text = selected?.textContent?.replace(/\\s+/g, \" \").trim();\n return THEME_CHILDREN.find((id) => THEME_TAB_LABELS[id] === text) ?? \"colors\";\n}\n","import { useEffect, useState } from \"react\";\n\nimport type { ThemeChild } from \"../theme/publish\";\nimport { ThemePreviewToggle, THEME_PREVIEW_TOGGLE_CSS } from \"./preview-mode\";\nimport { ThemePublishControls } from \"./publish-child\";\nimport { readActiveThemeTab } from \"./theme-tab\";\n\n/**\n * Light/Dark preview for Colors, Typography, and Appearance. Lives in\n * `beforeDocumentControls` so Payload's Save stays in the Save slot.\n * Save writes that page's slice onto the stored Theme row.\n */\nexport function ThemeDocumentControls() {\n return (\n <>\n <style href=\"bl-doc-controls\" precedence=\"default\">\n {THEME_PREVIEW_TOGGLE_CSS}\n </style>\n <ThemePreviewToggle />\n </>\n );\n}\n\n/**\n * Import-map Save slot used by the older single-Global Theme. Theme pages\n * keep Payload's Save and put Light/Dark in `ThemeDocumentControls`.\n */\nexport function ThemeSaveButton() {\n const [child, setChild] = useState<ThemeChild>(\"colors\");\n\n useEffect(() => {\n const sync = () => setChild(readActiveThemeTab());\n sync();\n const tabs = document.querySelector(\".tabs-field\");\n const target = tabs ?? document.body;\n const observer = new MutationObserver(sync);\n observer.observe(target, {\n subtree: true,\n attributes: true,\n attributeFilter: [\"aria-selected\", \"class\"],\n childList: true,\n });\n target.addEventListener(\"click\", sync);\n return () => {\n observer.disconnect();\n target.removeEventListener(\"click\", sync);\n };\n }, []);\n\n return <ThemePublishControls child={child} />;\n}\n\n/** @deprecated Import map alias — ThemeDocumentControls is the Save-adjacent slot. */\nexport function HiddenSaveButton() {\n return <ThemeDocumentControls />;\n}\n","import type { UIFieldClientComponent } from \"payload\";\n\nimport type { ThemeIdentityFallback } from \"../theme/identity\";\n\n/**\n * Identity child when the site has not registered a cupboard yet.\n * Shows the fallback lockup and mark; uploads wait on `logo.collection`.\n */\nexport const IdentityFallback: UIFieldClientComponent = ({ field }) => {\n const fallback = (field.admin?.custom as { fallback?: ThemeIdentityFallback } | undefined)?.fallback;\n return (\n <section className=\"bl-identity-fallback\">\n <style href=\"bl-identity-fallback\" precedence=\"default\">\n {CSS}\n </style>\n <header>\n <h2>Site identity</h2>\n <p>Today&apos;s lockup and mark until a brand editor uploads replacements.</p>\n </header>\n <div className=\"bl-identity-fallback__grid\">\n {fallback?.lockup ? (\n <figure>\n <img src={fallback.lockup.url} alt={fallback.lockup.alt} />\n <figcaption>Lockup</figcaption>\n </figure>\n ) : null}\n {fallback?.mark ? (\n <figure>\n <img src={fallback.mark.url} alt={fallback.mark.alt} />\n <figcaption>Mark</figcaption>\n </figure>\n ) : null}\n </div>\n </section>\n );\n};\n\nconst CSS = `\n.bl-identity-fallback header h2{margin:0;font-size:1.1rem}\n.bl-identity-fallback header p{margin:.35rem 0 1rem;color:var(--theme-elevation-600,#475569)}\n.bl-identity-fallback__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));gap:1rem}\n.bl-identity-fallback figure{margin:0;padding:1rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:10px;background:var(--theme-elevation-50,#f8fafc)}\n.bl-identity-fallback img{display:block;max-width:100%;height:4rem;object-fit:contain}\n.bl-identity-fallback figcaption{margin-top:.5rem;font-size:.8rem;color:var(--theme-elevation-600,#475569)}\n`;\n","import { FieldDescription, FieldError, FieldLabel, useConfig, useField } from \"@payloadcms/ui\";\nimport type { TextFieldClientComponent } from \"payload\";\nimport { useEffect, useId, useState } from \"react\";\n\nimport { pageEditorLooks, pageEditorTokens, type LookOption } from \"../theme/looks\";\nimport type { LookFieldMode } from \"../theme/look-field\";\nimport type { ThemeDoc } from \"../theme/types\";\n\n/**\n * Loads the Theme global and offers page-editor looks or included steps.\n * A custom scale published on Colors appears here on the next load.\n */\nexport const LookField: TextFieldClientComponent = ({ field, path, readOnly }) => {\n const { value, setValue, showError, errorMessage } = useField<string>({ path });\n const { config } = useConfig();\n const mode = ((field.admin?.custom as { mode?: LookFieldMode } | undefined)?.mode ?? \"look\") as LookFieldMode;\n const [options, setOptions] = useState<LookOption[]>(\n mode === \"token\" ? pageEditorTokens(null) : pageEditorLooks(null),\n );\n const id = useId();\n const required = Boolean(field.required);\n\n useEffect(() => {\n const serverURL = config.serverURL ?? \"\";\n const api = config.routes?.api ?? \"/api\";\n const controller = new AbortController();\n fetch(`${serverURL}${api}/globals/theme?depth=0`, { signal: controller.signal, credentials: \"include\" })\n .then((response) => (response.ok ? response.json() : null))\n .then((doc: ThemeDoc | null) => {\n setOptions(mode === \"token\" ? pageEditorTokens(doc) : pageEditorLooks(doc));\n })\n .catch(() => {\n /* keep the system-only fallback */\n });\n return () => controller.abort();\n }, [config.routes?.api, config.serverURL, mode]);\n\n return (\n <div className=\"field-type\">\n <FieldLabel htmlFor={id} label={field.label} required={required} />\n <select\n id={id}\n disabled={readOnly}\n value={value ?? \"\"}\n onChange={(event) => setValue(event.target.value || undefined)}\n >\n <option value=\"\">{required ? \"Select…\" : \"None\"}</option>\n {options.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n <FieldDescription description={field.admin?.description} path={path} />\n <FieldError path={path} showError={showError} message={errorMessage} />\n </div>\n );\n};\n","/**\n * The Roles Global a site's generated types will describe. Optional and\n * nullable, no index signature: a generated Global is assignable to this,\n * never the reverse.\n */\n\nexport const ROLES = [\"developer\", \"admin\", \"designer\", \"author\"] as const;\n\nexport type Role = (typeof ROLES)[number];\n\nexport const ROLE_LABELS: Record<Role, string> = {\n developer: \"Developer\",\n admin: \"Admin\",\n designer: \"Designer\",\n author: \"Author\",\n};\n\nexport const CAPABILITIES = [\"content\", \"brand\", \"publish\", \"users\"] as const;\n\nexport type Capability = (typeof CAPABILITIES)[number];\n\nexport interface RoleRow {\n id?: string | null;\n role: Role;\n content: boolean;\n brand: boolean;\n publish: boolean;\n users: boolean;\n}\n\nexport interface RolesDoc {\n roles?: RoleRow[] | null;\n}\n\n/**\n * `req.user` as Payload hands it over. Structural so this module never\n * imports a site's generated `User`. `roles` is optional because a row\n * that predates the field must come back powerless.\n */\nexport type MaybeUser = { id?: string | number; roles?: readonly string[] | null } | null | undefined;\n\nexport function isRole(value: unknown): value is Role {\n return typeof value === \"string\" && (ROLES as readonly string[]).includes(value);\n}\n","import { CAPABILITIES, isRole, ROLE_LABELS, ROLES, type Capability, type Role, type RoleRow } from \"./types\";\n\nexport const ROLES_SLUG = \"roles\";\n\n/**\n * Default rank and ticks. Brand is Designer only. The API tab is not a\n * column — it is locked to Developer in `isDeveloper`.\n */\nexport const DEFAULT_ROLE_MATRIX: readonly RoleRow[] = [\n { role: \"developer\", content: true, brand: true, publish: true, users: true },\n { role: \"admin\", content: true, brand: false, publish: true, users: true },\n { role: \"designer\", content: false, brand: true, publish: false, users: false },\n { role: \"author\", content: true, brand: false, publish: false, users: false },\n];\n\nexport const DEVELOPER_DESCRIPTION = \"Everything Admin can do, plus the document API tab.\";\n\nexport const LAST_USERS_TICK_MESSAGE =\n \"Keep Users ticked on at least one of Admin or Developer.\";\n\nconst CAPABILITY_LABELS: Record<Capability, string> = {\n content: \"Content\",\n brand: \"Brand\",\n publish: \"Publish\",\n users: \"Users\",\n};\n\nexport function defaultRolesFieldValue(): RoleRow[] {\n return DEFAULT_ROLE_MATRIX.map((row) => ({ id: row.role, ...row }));\n}\n\nexport function parseRolesMatrix(\n value: unknown,\n): { ok: true; rows: RoleRow[] } | { ok: false; message: string } {\n if (!Array.isArray(value)) {\n return { ok: false, message: \"Roles must be Developer, Admin, Designer, and Author.\" };\n }\n\n const rows: RoleRow[] = [];\n const seen = new Set<Role>();\n for (const item of value) {\n if (!item || typeof item !== \"object\") continue;\n const role = \"role\" in item ? item.role : undefined;\n if (!isRole(role) || seen.has(role)) continue;\n seen.add(role);\n rows.push({\n id: role,\n role,\n content: Boolean(\"content\" in item && item.content),\n brand: Boolean(\"brand\" in item && item.brand),\n publish: Boolean(\"publish\" in item && item.publish),\n users: Boolean(\"users\" in item && item.users),\n });\n }\n\n if (rows.length !== ROLES.length || ROLES.some((role) => !seen.has(role))) {\n return { ok: false, message: \"Roles must be Developer, Admin, Designer, and Author.\" };\n }\n return { ok: true, rows };\n}\n\nexport function hasPrivilegedUsersTick(rows: readonly RoleRow[]): boolean {\n return rows.some((row) => (row.role === \"admin\" || row.role === \"developer\") && row.users);\n}\n\nexport function validateRolesMatrix(value: unknown): true | string {\n const parsed = parseRolesMatrix(value);\n if (!parsed.ok) return parsed.message;\n if (!hasPrivilegedUsersTick(parsed.rows)) return LAST_USERS_TICK_MESSAGE;\n return true;\n}\n\n/**\n * Developer is exclusive. Admin does not swallow Designer: both store.\n */\nexport function normalizeStoredRoles(value: unknown): Role[] {\n if (!Array.isArray(value)) return [];\n const roles = [...new Set(value.filter(isRole))];\n if (roles.includes(\"developer\")) return [\"developer\"];\n return roles;\n}\n\nexport function roleSelectOptions(matrix: readonly RoleRow[] = DEFAULT_ROLE_MATRIX) {\n return matrix.map((row) => ({ label: ROLE_LABELS[row.role], value: row.role }));\n}\n\n/** Capability copy only. Developer names the API tab; nothing about MCP or seed. */\nexport function roleDescription(role: Role, matrix: readonly RoleRow[] = DEFAULT_ROLE_MATRIX): string {\n if (role === \"developer\") return DEVELOPER_DESCRIPTION;\n const row = matrix.find((entry) => entry.role === role);\n if (!row) return \"No capabilities\";\n const ticks = CAPABILITIES.filter((capability) => row[capability]).map(\n (capability) => CAPABILITY_LABELS[capability],\n );\n return ticks.join(\", \") || \"No capabilities\";\n}\n","import { ArrayField, useField } from \"@payloadcms/ui\";\nimport type { ArrayFieldClientComponent } from \"payload\";\n\nimport { defaultRolesFieldValue } from \"../roles/matrix\";\n\nconst HIDE_ROW_CHROME = `.bl-roles-matrix .array-field__add-row,.bl-roles-matrix .array-actions__add,.bl-roles-matrix .array-actions__remove,.bl-roles-matrix .array-actions__duplicate,.bl-roles-matrix .array-actions__copy{display:none}.bl-roles-matrix__toolbar{display:flex;justify-content:flex-end;margin-block-end:.75rem}.bl-roles-matrix__reset{min-height:2.25rem;padding:.35rem .9rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:8px;background:transparent;color:inherit;font:inherit;cursor:pointer}`;\n\n/**\n * Payload's array field: drag rank stays, add/remove go away. Reset writes\n * the package seed back onto the field.\n */\nexport const RolesMatrixField: ArrayFieldClientComponent = (props) => {\n const { setValue } = useField({ path: props.path });\n\n return (\n <div className=\"bl-roles-matrix\">\n <style href=\"bl-roles-matrix\" precedence=\"default\">\n {HIDE_ROW_CHROME}\n </style>\n <div className=\"bl-roles-matrix__toolbar\">\n <button type=\"button\" className=\"bl-roles-matrix__reset\" onClick={() => setValue(defaultRolesFieldValue())}>\n Reset to defaults\n </button>\n </div>\n <ArrayField {...props} />\n </div>\n );\n};\n","import type { OptionObject, SelectFieldClientComponent, Validate } from \"payload\";\nimport {\n CheckboxInput,\n FieldDescription,\n FieldError,\n FieldLabel,\n fieldBaseClass,\n useField,\n} from \"@payloadcms/ui\";\nimport { useCallback } from \"react\";\n\nimport { roleDescription, roleSelectOptions } from \"../roles/matrix\";\nimport { isRole, ROLE_LABELS, type Role } from \"../roles/types\";\n\nconst GRID_CSS = `.bl-roles__grid{display:grid;gap:.75rem;grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));margin-block:.35rem 0}.bl-roles__option{display:flex;flex-direction:column;gap:.25rem;padding:.65rem .75rem;border:1px solid var(--theme-elevation-150,#e2e8f0);border-radius:8px}.bl-roles__option.is-checked{border-color:var(--theme-elevation-400,#94a3b8)}.bl-roles__option.is-included{opacity:.7}.bl-roles__what{font-size:.8rem;line-height:1.35;color:var(--theme-elevation-500,#64748b)}`;\n\nfunction optionValue(option: string | OptionObject): string {\n return typeof option === \"string\" ? option : String(option.value);\n}\n\nfunction optionLabel(option: string | OptionObject): string {\n return typeof option === \"string\" ? option : String(option.label);\n}\n\n/**\n * Users Roles checklist. Order and labels come from the field options (the\n * Roles Global, or the seed). Copy is `roleDescription`. Developer is\n * exclusive; Admin does not swallow Designer.\n */\nexport const RolesField: SelectFieldClientComponent = ({\n field,\n path: pathFromProps,\n readOnly,\n validate,\n}) => {\n const { admin: { description } = {}, label, localized, options = [], required } = field;\n const offered = (options.length ? options : roleSelectOptions()).map((option) => ({\n value: optionValue(option),\n label: optionLabel(option),\n }));\n\n const memoizedValidate = useCallback<Validate>(\n (value, validationOptions) => {\n if (typeof validate === \"function\") {\n return validate(value, {\n ...validationOptions,\n hasMany: true,\n options,\n required,\n } as Parameters<typeof validate>[1]);\n }\n return true;\n },\n [validate, options, required],\n );\n\n const { disabled, errorMessage, path, setValue, showError, value } = useField<Role[]>({\n potentiallyStalePath: pathFromProps,\n validate: memoizedValidate,\n });\n\n const selected: Role[] = Array.isArray(value) ? value : [];\n const exclusive = selected.includes(\"developer\") ? \"developer\" : null;\n const locked = Boolean(readOnly) || disabled;\n\n function toggle(role: Role): void {\n if (locked) return;\n if (role === \"developer\") {\n setValue(selected.includes(role) ? [] : [\"developer\"]);\n return;\n }\n if (exclusive) return;\n setValue(selected.includes(role) ? selected.filter((entry) => entry !== role) : [...selected, role]);\n }\n\n const groupLabel = typeof label === \"string\" ? label : \"Roles\";\n\n return (\n <div\n className={[fieldBaseClass, \"select\", \"bl-roles\", showError && \"error\", locked && \"read-only\"]\n .filter(Boolean)\n .join(\" \")}\n id={`field-${path.replace(/\\./g, \"__\")}`}\n >\n <style href=\"bl-roles\" precedence=\"default\">\n {GRID_CSS}\n </style>\n <FieldLabel as=\"span\" label={label} localized={localized} path={path} required={required} />\n <div className={`${fieldBaseClass}__wrap`}>\n <FieldError message={errorMessage} path={path} showError={showError} />\n <div aria-label={groupLabel} className=\"bl-roles__grid\" role=\"group\">\n {offered.map((option) => {\n const role = isRole(option.value) ? option.value : null;\n if (!role) return null;\n const included = exclusive !== null && role !== exclusive;\n const checked = selected.includes(role);\n return (\n <div\n className={[\"bl-roles__option\", checked && \"is-checked\", included && \"is-included\"]\n .filter(Boolean)\n .join(\" \")}\n key={role}\n >\n <CheckboxInput\n checked={checked}\n id={`${path}-${role}`}\n label={option.label || ROLE_LABELS[role]}\n onToggle={() => toggle(role)}\n readOnly={locked || included}\n />\n <span className=\"bl-roles__what\">\n {included ? \"Included in Developer\" : roleDescription(role)}\n </span>\n </div>\n );\n })}\n </div>\n </div>\n <FieldDescription description={description} path={path} />\n </div>\n );\n};\n"],"mappings":"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"}