/* GENERATED by ds/build-css.js — tokens + component chunks. Do not edit; edit ds/tokens/*.json or ds/components/*.js */
/* GENERATED by ds/build-tokens.js — do not edit. Source: ds/tokens/*.json */
:root[data-theme="afterimage"] {
  --ux-bg: #0A0611;
  --ux-surface: #171024;
  --ux-raised: #1e1533;
  --ux-overlay: rgba(6,4,10,.92);
  --ux-code-bg: #0d0817;
  --ux-ink: #F4EFFB;
  --ux-ink-soft: #d7cae8;
  --ux-ink-muted: #B39BD8;
  --ux-code-ink: #d7cae8;
  --ux-on-brand: #ffffff;
  --ux-brand: #FF2FB9;
  --ux-brand-hover: #e0219f;
  --ux-brand-ink: #ff6fce;
  --ux-brand-tint: rgba(255,47,185,.13);
  --ux-accent: #7A2BFF;
  --ux-accent-ink: #c4b5fd;
  --ux-accent-tint: rgba(122,43,255,.12);
  --ux-grad: linear-gradient(120deg,#FF2FB9,#7A2BFF);
  --ux-glass: rgba(10,6,17,.82);
  --ux-hairline: linear-gradient(90deg,transparent,rgba(255,47,185,.4),rgba(122,43,255,.4),transparent);
  --ux-line: rgba(179,155,216,.14);
  --ux-line-strong: rgba(179,155,216,.30);
  --ux-focus: #FF2FB9;
  --ux-focus-ring: 0 0 0 3px rgba(255,47,185,.45);
  --ux-ok: #35D69B;
  --ux-ok-tint: rgba(53,214,155,.13);
  --ux-warn: #FFC24B;
  --ux-warn-tint: rgba(255,194,75,.13);
  --ux-danger: #FF5C72;
  --ux-danger-tint: rgba(255,92,114,.13);
  --ux-info: #8AA2FF;
  --ux-info-tint: rgba(138,162,255,.13);
  --ux-band-a: #1a9e5f;
  --ux-band-b: #5fae3a;
  --ux-band-c: #c99a1e;
  --ux-band-d: #d9772b;
  --ux-band-e: #d4552e;
  --ux-band-f: #c23b3b;
  --ux-radius-xs: 6px;
  --ux-radius-sm: 10px;
  --ux-radius-md: 14px;
  --ux-radius-lg: 18px;
  --ux-radius-pill: 99px;
  --ux-space-1: 4px;
  --ux-space-2: 8px;
  --ux-space-3: 12px;
  --ux-space-4: 16px;
  --ux-space-5: 24px;
  --ux-space-6: 34px;
  --ux-space-7: 48px;
  --ux-space-8: 64px;
  --ux-text-display: clamp(30px,6vw,48px);
  --ux-text-h1: clamp(26px,4.5vw,44px);
  --ux-text-h2: clamp(20px,3vw,27px);
  --ux-text-h3: 18px;
  --ux-text-body: 16px;
  --ux-text-small: 14px;
  --ux-text-caption: 12px;
  --ux-text-micro: 11px;
  --ux-weight-normal: 400;
  --ux-weight-medium: 500;
  --ux-weight-semibold: 600;
  --ux-weight-bold: 700;
  --ux-weight-heavy: 800;
  --ux-leading-solid: 1;
  --ux-leading-tight: 1.15;
  --ux-leading-snug: 1.4;
  --ux-leading-normal: 1.55;
  --ux-leading-loose: 1.7;
  --ux-track-tight: -.02em;
  --ux-track-snug: -.01em;
  --ux-track-normal: 0;
  --ux-track-wide: .04em;
  --ux-track-caps: .12em;
  --ux-track-kicker: .2em;
  --ux-font-sans: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  --ux-font-mono: ui-monospace,'SF Mono',Menlo,monospace;
  --ux-font-display: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  --ux-shadow-sm: 0 6px 24px rgba(0,0,0,.28);
  --ux-shadow-md: 0 12px 40px rgba(0,0,0,.36);
  --ux-shadow-lg: 0 24px 80px rgba(0,0,0,.5);
  --ux-glow: 0 0 44px rgba(255,47,185,.35);
  --ux-dur-fast: 120ms;
  --ux-dur-base: 200ms;
  --ux-dur-slow: 320ms;
  --ux-ease-out: cubic-bezier(.2,.7,.2,1);
  --ux-ease-in-out: cubic-bezier(.65,.05,.35,.95);
  --ux-z-raised: 10;
  --ux-z-sticky: 100;
  --ux-z-overlay: 1000;
  --ux-z-modal: 1100;
  --ux-z-toast: 1200;
  --ux-maxw: 1120px;
  --ux-maxw-narrow: 720px;
  --ux-maxw-wide: 1360px;
}
:root[data-theme="paper"] {
  --ux-bg: #FBFAF8;
  --ux-surface: #FFFFFF;
  --ux-raised: #FFFFFF;
  --ux-overlay: rgba(22,22,26,.86);
  --ux-code-bg: #F3F1EC;
  --ux-ink: #16161A;
  --ux-ink-soft: #3E3E46;
  --ux-ink-muted: #6B6B76;
  --ux-code-ink: #3E3E46;
  --ux-on-brand: #ffffff;
  --ux-brand: #C2087F;
  --ux-brand-hover: #9c0665;
  --ux-brand-ink: #B40776;
  --ux-brand-tint: rgba(194,8,127,.10);
  --ux-accent: #5b21b6;
  --ux-accent-ink: #5b21b6;
  --ux-accent-tint: rgba(91,33,182,.10);
  --ux-grad: linear-gradient(120deg,#C2087F,#9c0665);
  --ux-glass: rgba(251,250,248,.86);
  --ux-hairline: linear-gradient(90deg,transparent,#C2087F,transparent);
  --ux-line: #E7E4DE;
  --ux-line-strong: #D8D4CC;
  --ux-focus: #C2087F;
  --ux-focus-ring: 0 0 0 3px rgba(194,8,127,.35);
  --ux-ok: #0F7A53;
  --ux-ok-tint: rgba(15,122,83,.10);
  --ux-warn: #8A5A06;
  --ux-warn-tint: rgba(138,90,6,.10);
  --ux-danger: #B3243C;
  --ux-danger-tint: rgba(179,36,60,.09);
  --ux-info: #2563EB;
  --ux-info-tint: rgba(37,99,235,.10);
  --ux-band-a: #0F7A53;
  --ux-band-b: #3F7A1F;
  --ux-band-c: #8A5A06;
  --ux-band-d: #9A4A12;
  --ux-band-e: #A6371C;
  --ux-band-f: #B3243C;
  --ux-radius-xs: 4px;
  --ux-radius-sm: 6px;
  --ux-radius-md: 10px;
  --ux-radius-lg: 14px;
  --ux-radius-pill: 99px;
  --ux-space-1: 4px;
  --ux-space-2: 8px;
  --ux-space-3: 12px;
  --ux-space-4: 16px;
  --ux-space-5: 24px;
  --ux-space-6: 34px;
  --ux-space-7: 48px;
  --ux-space-8: 64px;
  --ux-text-display: clamp(38px,6vw,68px);
  --ux-text-h1: clamp(30px,4.6vw,46px);
  --ux-text-h2: clamp(22px,3vw,31px);
  --ux-text-h3: 19px;
  --ux-text-body: 17px;
  --ux-text-small: 14.5px;
  --ux-text-caption: 12.5px;
  --ux-text-micro: 11px;
  --ux-weight-normal: 400;
  --ux-weight-medium: 500;
  --ux-weight-semibold: 600;
  --ux-weight-bold: 700;
  --ux-weight-heavy: 800;
  --ux-leading-solid: 1;
  --ux-leading-tight: 1.06;
  --ux-leading-snug: 1.4;
  --ux-leading-normal: 1.6;
  --ux-leading-loose: 1.75;
  --ux-track-tight: -.03em;
  --ux-track-snug: -.01em;
  --ux-track-normal: 0;
  --ux-track-wide: .04em;
  --ux-track-caps: .12em;
  --ux-track-kicker: .2em;
  --ux-font-sans: 'Hanken Grotesk',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  --ux-font-mono: 'JetBrains Mono',ui-monospace,'SF Mono',Menlo,monospace;
  --ux-font-display: 'Fraunces',Georgia,'Times New Roman',serif;
  --ux-shadow-sm: 0 1px 2px rgba(22,22,26,.06);
  --ux-shadow-md: 0 10px 26px -14px rgba(22,22,26,.28);
  --ux-shadow-lg: 0 26px 60px -28px rgba(22,22,26,.40);
  --ux-glow: 0 0 0 1px rgba(194,8,127,.18);
  --ux-dur-fast: 120ms;
  --ux-dur-base: 200ms;
  --ux-dur-slow: 320ms;
  --ux-ease-out: cubic-bezier(.2,.7,.2,1);
  --ux-ease-in-out: cubic-bezier(.65,.05,.35,.95);
  --ux-z-raised: 10;
  --ux-z-sticky: 100;
  --ux-z-overlay: 1000;
  --ux-z-modal: 1100;
  --ux-z-toast: 1200;
  --ux-maxw: 1080px;
  --ux-maxw-narrow: 720px;
  --ux-maxw-wide: 1360px;
}
:root {
  --ux-bg: #0a0a0a;
  --ux-surface: #0a0a0a;
  --ux-raised: #131313;
  --ux-overlay: rgba(6,6,6,.92);
  --ux-code-bg: #131313;
  --ux-ink: #ffffff;
  --ux-ink-soft: #ffffff;
  --ux-ink-muted: rgba(255,255,255,.58);
  --ux-code-ink: #ffffff;
  --ux-on-brand: #0a0a0a;
  --ux-brand: #FF2FB9;
  --ux-brand-hover: #e0219f;
  --ux-brand-ink: #ff54c4;
  --ux-brand-tint: rgba(255,47,185,.16);
  --ux-accent: #FF2FB9;
  --ux-accent-ink: #FF2FB9;
  --ux-accent-tint: rgba(255,47,185,.12);
  --ux-grad: linear-gradient(120deg,#FF2FB9,#ff54c4);
  --ux-glass: rgba(10,10,10,.82);
  --ux-hairline: linear-gradient(90deg,transparent,#FF2FB9,transparent);
  --ux-line: rgba(255,255,255,.14);
  --ux-line-strong: rgba(255,255,255,.32);
  --ux-focus: #FF2FB9;
  --ux-focus-ring: 0 0 0 3px rgba(255,47,185,.5);
  --ux-ok: #35D69B;
  --ux-ok-tint: rgba(53,214,155,.13);
  --ux-warn: #FFC24B;
  --ux-warn-tint: rgba(255,194,75,.13);
  --ux-danger: #FF5C72;
  --ux-danger-tint: rgba(255,92,114,.13);
  --ux-info: #8AA2FF;
  --ux-info-tint: rgba(138,162,255,.13);
  --ux-band-a: #1a9e5f;
  --ux-band-b: #5fae3a;
  --ux-band-c: #c99a1e;
  --ux-band-d: #d9772b;
  --ux-band-e: #d4552e;
  --ux-band-f: #c23b3b;
  --ux-radius-xs: 6px;
  --ux-radius-sm: 10px;
  --ux-radius-md: 14px;
  --ux-radius-lg: 18px;
  --ux-radius-pill: 99px;
  --ux-space-1: 4px;
  --ux-space-2: 8px;
  --ux-space-3: 12px;
  --ux-space-4: 16px;
  --ux-space-5: 24px;
  --ux-space-6: 34px;
  --ux-space-7: 48px;
  --ux-space-8: 64px;
  --ux-text-display: clamp(34px,6.5vw,58px);
  --ux-text-h1: clamp(28px,5vw,46px);
  --ux-text-h2: clamp(20px,3vw,27px);
  --ux-text-h3: 18px;
  --ux-text-body: 16px;
  --ux-text-small: 14px;
  --ux-text-caption: 12px;
  --ux-text-micro: 11px;
  --ux-weight-normal: 400;
  --ux-weight-medium: 500;
  --ux-weight-semibold: 600;
  --ux-weight-bold: 700;
  --ux-weight-heavy: 800;
  --ux-leading-solid: 1;
  --ux-leading-tight: 1.1;
  --ux-leading-snug: 1.4;
  --ux-leading-normal: 1.55;
  --ux-leading-loose: 1.7;
  --ux-track-tight: -.03em;
  --ux-track-snug: -.01em;
  --ux-track-normal: 0;
  --ux-track-wide: .04em;
  --ux-track-caps: .12em;
  --ux-track-kicker: .2em;
  --ux-font-sans: 'Hanken Grotesk',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  --ux-font-mono: 'JetBrains Mono',ui-monospace,'SF Mono',Menlo,monospace;
  --ux-font-display: 'Unbounded',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  --ux-shadow-sm: 0 2px 10px rgba(0,0,0,.4);
  --ux-shadow-md: 0 10px 30px rgba(0,0,0,.5);
  --ux-shadow-lg: 0 26px 70px rgba(0,0,0,.6);
  --ux-glow: 0 0 44px rgba(255,47,185,.35);
  --ux-dur-fast: 120ms;
  --ux-dur-base: 200ms;
  --ux-dur-slow: 320ms;
  --ux-ease-out: cubic-bezier(.2,.7,.2,1);
  --ux-ease-in-out: cubic-bezier(.65,.05,.35,.95);
  --ux-z-raised: 10;
  --ux-z-sticky: 100;
  --ux-z-overlay: 1000;
  --ux-z-modal: 1100;
  --ux-z-toast: 1200;
  --ux-maxw: 1120px;
  --ux-maxw-narrow: 720px;
  --ux-maxw-wide: 1360px;
}
:root[data-theme="signal"], [data-theme="signal"] {
  --ux-bg: #0a0a0a;
  --ux-surface: #0a0a0a;
  --ux-raised: #131313;
  --ux-overlay: rgba(6,6,6,.92);
  --ux-code-bg: #131313;
  --ux-ink: #ffffff;
  --ux-ink-soft: #ffffff;
  --ux-ink-muted: rgba(255,255,255,.58);
  --ux-code-ink: #ffffff;
  --ux-on-brand: #0a0a0a;
  --ux-brand: #FF2FB9;
  --ux-brand-hover: #e0219f;
  --ux-brand-ink: #ff54c4;
  --ux-brand-tint: rgba(255,47,185,.16);
  --ux-accent: #FF2FB9;
  --ux-accent-ink: #FF2FB9;
  --ux-accent-tint: rgba(255,47,185,.12);
  --ux-grad: linear-gradient(120deg,#FF2FB9,#ff54c4);
  --ux-glass: rgba(10,10,10,.82);
  --ux-hairline: linear-gradient(90deg,transparent,#FF2FB9,transparent);
  --ux-line: rgba(255,255,255,.14);
  --ux-line-strong: rgba(255,255,255,.32);
  --ux-focus: #FF2FB9;
  --ux-focus-ring: 0 0 0 3px rgba(255,47,185,.5);
  --ux-ok: #35D69B;
  --ux-ok-tint: rgba(53,214,155,.13);
  --ux-warn: #FFC24B;
  --ux-warn-tint: rgba(255,194,75,.13);
  --ux-danger: #FF5C72;
  --ux-danger-tint: rgba(255,92,114,.13);
  --ux-info: #8AA2FF;
  --ux-info-tint: rgba(138,162,255,.13);
  --ux-band-a: #1a9e5f;
  --ux-band-b: #5fae3a;
  --ux-band-c: #c99a1e;
  --ux-band-d: #d9772b;
  --ux-band-e: #d4552e;
  --ux-band-f: #c23b3b;
  --ux-radius-xs: 6px;
  --ux-radius-sm: 10px;
  --ux-radius-md: 14px;
  --ux-radius-lg: 18px;
  --ux-radius-pill: 99px;
  --ux-space-1: 4px;
  --ux-space-2: 8px;
  --ux-space-3: 12px;
  --ux-space-4: 16px;
  --ux-space-5: 24px;
  --ux-space-6: 34px;
  --ux-space-7: 48px;
  --ux-space-8: 64px;
  --ux-text-display: clamp(34px,6.5vw,58px);
  --ux-text-h1: clamp(28px,5vw,46px);
  --ux-text-h2: clamp(20px,3vw,27px);
  --ux-text-h3: 18px;
  --ux-text-body: 16px;
  --ux-text-small: 14px;
  --ux-text-caption: 12px;
  --ux-text-micro: 11px;
  --ux-weight-normal: 400;
  --ux-weight-medium: 500;
  --ux-weight-semibold: 600;
  --ux-weight-bold: 700;
  --ux-weight-heavy: 800;
  --ux-leading-solid: 1;
  --ux-leading-tight: 1.1;
  --ux-leading-snug: 1.4;
  --ux-leading-normal: 1.55;
  --ux-leading-loose: 1.7;
  --ux-track-tight: -.03em;
  --ux-track-snug: -.01em;
  --ux-track-normal: 0;
  --ux-track-wide: .04em;
  --ux-track-caps: .12em;
  --ux-track-kicker: .2em;
  --ux-font-sans: 'Hanken Grotesk',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  --ux-font-mono: 'JetBrains Mono',ui-monospace,'SF Mono',Menlo,monospace;
  --ux-font-display: 'Unbounded',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  --ux-shadow-sm: 0 2px 10px rgba(0,0,0,.4);
  --ux-shadow-md: 0 10px 30px rgba(0,0,0,.5);
  --ux-shadow-lg: 0 26px 70px rgba(0,0,0,.6);
  --ux-glow: 0 0 44px rgba(255,47,185,.35);
  --ux-dur-fast: 120ms;
  --ux-dur-base: 200ms;
  --ux-dur-slow: 320ms;
  --ux-ease-out: cubic-bezier(.2,.7,.2,1);
  --ux-ease-in-out: cubic-bezier(.65,.05,.35,.95);
  --ux-z-raised: 10;
  --ux-z-sticky: 100;
  --ux-z-overlay: 1000;
  --ux-z-modal: 1100;
  --ux-z-toast: 1200;
  --ux-maxw: 1120px;
  --ux-maxw-narrow: 720px;
  --ux-maxw-wide: 1360px;
}
:root[data-theme="v2"] {
  --ux-bg: #f7f7f8;
  --ux-surface: #ffffff;
  --ux-raised: #ffffff;
  --ux-overlay: rgba(19,19,22,.48);
  --ux-code-bg: #f1f0f4;
  --ux-ink: #131316;
  --ux-ink-soft: #2e2e33;
  --ux-ink-muted: #4b5563;
  --ux-code-ink: #2e2e33;
  --ux-on-brand: #ffffff;
  --ux-brand: #c2087f;
  --ux-brand-hover: #a1066a;
  --ux-brand-ink: #FF2FB9;
  --ux-brand-tint: rgba(194,8,127,.10);
  --ux-accent: #5b21b6;
  --ux-accent-ink: #5b21b6;
  --ux-accent-tint: rgba(91,33,182,.10);
  --ux-grad: linear-gradient(120deg,#FF2FB9,#c2087f);
  --ux-glass: rgba(255,255,255,.86);
  --ux-hairline: linear-gradient(90deg,transparent,rgba(194,8,127,.35),transparent);
  --ux-line: #e4e4e9;
  --ux-line-strong: #cfcfd6;
  --ux-focus: #c2087f;
  --ux-focus-ring: 0 0 0 3px rgba(194,8,127,.35);
  --ux-ok: #157f5a;
  --ux-ok-tint: rgba(21,127,90,.10);
  --ux-warn: #9a6a00;
  --ux-warn-tint: rgba(154,106,0,.10);
  --ux-danger: #c22b45;
  --ux-danger-tint: rgba(194,43,69,.10);
  --ux-info: #3554c9;
  --ux-info-tint: rgba(53,84,201,.10);
  --ux-band-a: #157f5a;
  --ux-band-b: #4a8f2a;
  --ux-band-c: #9a6a00;
  --ux-band-d: #b25f16;
  --ux-band-e: #c2452e;
  --ux-band-f: #b32222;
  --ux-radius-xs: 4px;
  --ux-radius-sm: 6px;
  --ux-radius-md: 10px;
  --ux-radius-lg: 14px;
  --ux-radius-pill: 99px;
  --ux-space-1: 4px;
  --ux-space-2: 8px;
  --ux-space-3: 12px;
  --ux-space-4: 16px;
  --ux-space-5: 24px;
  --ux-space-6: 34px;
  --ux-space-7: 48px;
  --ux-space-8: 64px;
  --ux-text-display: clamp(32px,5.5vw,48px);
  --ux-text-h1: clamp(26px,4.5vw,40px);
  --ux-text-h2: clamp(20px,3vw,24px);
  --ux-text-h3: 18px;
  --ux-text-body: 16px;
  --ux-text-small: 14px;
  --ux-text-caption: 12px;
  --ux-text-micro: 11px;
  --ux-weight-normal: 400;
  --ux-weight-medium: 500;
  --ux-weight-semibold: 600;
  --ux-weight-bold: 600;
  --ux-weight-heavy: 700;
  --ux-leading-solid: 1;
  --ux-leading-tight: 1.15;
  --ux-leading-snug: 1.4;
  --ux-leading-normal: 1.6;
  --ux-leading-loose: 1.7;
  --ux-track-tight: -.02em;
  --ux-track-snug: -.01em;
  --ux-track-normal: 0;
  --ux-track-wide: .04em;
  --ux-track-caps: .1em;
  --ux-track-kicker: .16em;
  --ux-font-sans: Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  --ux-font-mono: 'Geist Mono',ui-monospace,'SF Mono',Menlo,monospace;
  --ux-font-display: Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  --ux-shadow-sm: 0 1px 2px rgba(19,19,22,.06), 0 4px 12px rgba(19,19,22,.05);
  --ux-shadow-md: 0 2px 4px rgba(19,19,22,.06), 0 10px 28px rgba(19,19,22,.08);
  --ux-shadow-lg: 0 4px 8px rgba(19,19,22,.07), 0 24px 56px rgba(19,19,22,.12);
  --ux-glow: 0 0 0 rgba(0,0,0,0);
  --ux-dur-fast: 120ms;
  --ux-dur-base: 200ms;
  --ux-dur-slow: 320ms;
  --ux-ease-out: cubic-bezier(.2,.7,.2,1);
  --ux-ease-in-out: cubic-bezier(.65,.05,.35,.95);
  --ux-z-raised: 10;
  --ux-z-sticky: 100;
  --ux-z-overlay: 1000;
  --ux-z-modal: 1100;
  --ux-z-toast: 1200;
  --ux-maxw: 1120px;
  --ux-maxw-narrow: 720px;
  --ux-maxw-wide: 1360px;
}
@media (prefers-reduced-motion: reduce){*,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}}


/* ── Badge ── */

.badge{display:inline-flex;align-items:center;gap:5px;font:var(--ux-weight-semibold) var(--ux-text-caption)/1 var(--ux-font-mono);
  letter-spacing:var(--ux-track-wide);padding:5px 10px;border-radius:var(--ux-radius-pill);border:1px solid transparent;white-space:nowrap}
/* neutral */
.badge--neutral.badge--tint{background:var(--ux-surface);color:var(--ux-ink-muted);border-color:var(--ux-line)}
.badge--neutral.badge--outline{background:transparent;color:var(--ux-ink-muted);border-color:var(--ux-line)}
.badge--neutral.badge--solid{background:var(--ux-ink-muted);color:var(--ux-bg)}
/* brand */
.badge--brand.badge--tint{background:var(--ux-brand-tint);color:var(--ux-brand-ink);border-color:var(--ux-brand-tint)}
.badge--brand.badge--outline{background:transparent;color:var(--ux-brand-ink);border-color:var(--ux-brand)}
.badge--brand.badge--solid{background:var(--ux-brand);color:var(--ux-on-brand)}
/* accent */
.badge--accent.badge--tint{background:var(--ux-accent-tint);color:var(--ux-accent-ink);border-color:var(--ux-accent-tint)}
.badge--accent.badge--outline{background:transparent;color:var(--ux-accent-ink);border-color:var(--ux-accent)}
/* signals */
.badge--ok.badge--tint{background:var(--ux-ok-tint);color:var(--ux-ok);border-color:var(--ux-ok-tint)}
.badge--warn.badge--tint{background:var(--ux-warn-tint);color:var(--ux-warn);border-color:var(--ux-warn-tint)}
.badge--danger.badge--tint{background:var(--ux-danger-tint);color:var(--ux-danger);border-color:var(--ux-danger-tint)}
.badge--ok.badge--solid{background:var(--ux-ok);color:var(--ux-bg)}
.badge--warn.badge--solid{background:var(--ux-warn);color:var(--ux-bg)}
.badge--danger.badge--solid{background:var(--ux-danger);color:var(--ux-bg)}


/* ── Brand ── */

/* ────────────────────────────────────────────────────────────────────────────
   BRAND — the wordmark, in every context that shows it.
   Depends on exactly two custom properties: --ux-ink and --ux-grad. A host without
   the token block declares those two itself (see /factory/).
   ──────────────────────────────────────────────────────────────────────────── */

.brand{flex:0 0 auto;font-family:var(--ux-font-display,var(--ux-font-sans,inherit));font-size:clamp(17px,3vw,28px);font-weight:700;letter-spacing:-.01em;color:var(--ux-ink);text-decoration:none;white-space:nowrap}

/* The gradient half. background-clip:text needs a painted background and a transparent
   foreground; the extra letter-spacing compensates for the optical tightening that clipping
   introduces at display weights. */
.brand-ux{background:var(--ux-grad);-webkit-background-clip:text;background-clip:text;color:transparent;letter-spacing:.02em}

/* Standalone header variants. The bar variant has no wrapper at all — Nav owns that layout. */
.brand-bar{position:relative;z-index:1;display:flex}
.brand-bar--center{justify-content:center;padding:30px 24px 0}
.brand-bar--back{max-width:760px;margin:0 auto;padding:22px clamp(20px,5vw,32px) 0}

/* The return label. The arrow is a pseudo-element so it is decoration, not text a screen reader
   reads out as a character.

   THE SPACING LIVES ON THE LABEL, NEVER ON THE ANCHOR. A gap here was a 10px word-space
   INSIDE the wordmark: Brand() emits a brand-ux span holding UX, then a BARE TEXT NODE holding
   XRAY, then the brand-back span. A bare text node in a flex container becomes an anonymous flex
   item, which gap then pushes away from UX. Measured 2026-08-25 on the one page that
   renders this modifier — dist/factory/index.html, the page every other page's banner promotes —
   the logo read UX-space-XRAY at a 10px gap while every other page read the wordmark closed up.

   test/brand-canonical.test.js could not see it: the MARKUP is canonical and the split happens at
   layout time. .agent/verify/_render.mjs brand-gap measures the real distance between the end of
   the UX span and the start of the XRAY text node via a Range, which is the only way to give a
   bare text node a box. Keep the spacing as a margin on .brand-back so nothing can ever land
   between UX and XRAY again. */
.brand--back{display:inline-flex;align-items:baseline;border-radius:6px}
.brand-back{font-weight:500;font-size:13px;letter-spacing:0;margin-inline-start:10px;color:var(--ux-ink-muted,var(--ux-ink))}
.brand-back::before{content:'\2190\00a0'}
.brand--back:hover .brand-back,.brand--back:focus-visible .brand-back{color:var(--ux-ink)}

/* The fallback ring is currentColor, not a brand pink literal. A host that has not mapped
   --ux-focus-ring has by definition not mapped the brand either, so a hardcoded pink would be
   both a token-lint violation and the wrong colour; currentColor resolves to --ux-ink, which
   every host must supply, so the ring is always visible and never off-palette. */
.brand:focus-visible{outline:none;box-shadow:var(--ux-focus-ring,0 0 0 3px currentColor);border-radius:var(--ux-radius-xs,6px)}


/* ── Button ── */

.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;font-family:var(--ux-font-sans);font-weight:var(--ux-weight-bold);
  border:1px solid transparent;border-radius:var(--ux-radius-pill);cursor:pointer;text-decoration:none;white-space:nowrap;line-height:1;
  transition:transform var(--ux-dur-fast) var(--ux-ease-out),box-shadow var(--ux-dur-fast) var(--ux-ease-out),background var(--ux-dur-fast),border-color var(--ux-dur-fast)}
.btn:active{transform:translateY(1px)}
.btn:focus-visible{outline:none;box-shadow:var(--ux-focus-ring)}
.btn__icon{font-size:.9em}
/* sizes */
.btn--sm{font-size:var(--ux-text-caption);padding:7px 14px}
.btn--md{font-size:var(--ux-text-small);padding:11px 20px}
.btn--lg{font-size:var(--ux-text-body);padding:14px 26px}
/* primary — the gradient, the brand */
.btn--primary{background:var(--ux-grad);color:var(--ux-on-brand);box-shadow:0 4px 22px var(--ux-brand-tint)}
.btn--primary:hover{transform:translateY(-1px);box-shadow:0 8px 30px var(--ux-brand-tint)}
/* secondary — bordered */
.btn--secondary{background:var(--ux-surface);color:var(--ux-ink);border-color:var(--ux-line-strong)}
.btn--secondary:hover{border-color:var(--ux-brand)}
/* ghost — quiet */
.btn--ghost{background:transparent;color:var(--ux-ink-muted);border-color:var(--ux-line)}
.btn--ghost:hover{color:var(--ux-ink);border-color:var(--ux-line-strong)}
/* ghost-grad — the brand gradient as a BORDER, not a fill. Two backgrounds in one declaration:
   a flat surface clipped to the padding box, the gradient clipped to the border box, so the 1px
   ring is the gradient and the interior stays readable. border-color:transparent is what lets
   the border-box layer show through — a real colour there would paint over it.
   Measured on the paper theme: ink #16161A on surface #FFFFFF is 18.04:1, and the border's
   lightest stop #C2087F on #FFFFFF is 5.78:1, past the 3:1 WCAG 1.4.11 floor for a non-text UI
   boundary. NO BACKTICKS IN THIS CSS BLOCK — it is a template literal.
   Re-measure if a theme changes --ux-grad; a gradient that fails is invisible here. */
.btn--ghost-grad{color:var(--ux-ink);border-color:transparent;
  background:linear-gradient(var(--ux-surface),var(--ux-surface)) padding-box,var(--ux-grad) border-box}
.btn--ghost-grad:hover{transform:translateY(-1px);box-shadow:0 6px 22px var(--ux-brand-tint)}
/* link — text only */
.btn--link{background:transparent;color:var(--ux-brand);padding-left:0;padding-right:0;border-radius:0}
.btn--link:hover{text-decoration:underline}
/* responsive label — only rendered when a caller passes short. 560px is where the two nav CTAs
   plus the brand stop fitting a 320px-class phone; below it the shorter string is shown and the
   longer one leaves the accessibility tree with display:none. */
.btn__narrow{display:none}
@media(max-width:560px){
  .btn__wide{display:none}
  .btn__narrow{display:inline}
}


/* ── Callout ── */

.callout{display:block;border:1px solid;border-radius:var(--ux-radius-md);padding:var(--ux-space-4) var(--ux-space-4) var(--ux-space-4) var(--ux-space-5);border-left:3px solid;background-clip:padding-box}
.callout__title{font-family:var(--ux-font-sans);font-size:var(--ux-text-small);font-weight:var(--ux-weight-semibold);margin:0 0 var(--ux-space-2);letter-spacing:var(--ux-track-snug);text-transform:uppercase}
.callout__body{font-size:var(--ux-text-small);line-height:var(--ux-leading-normal)}
.callout__body p{margin:0}

/* tone: info — blue signal */
.callout--info{border-color:var(--ux-info);border-left-color:var(--ux-info);background:var(--ux-info-tint)}
.callout--info .callout__title{color:var(--ux-info)}
.callout--info .callout__body{color:var(--ux-ink-soft)}

/* tone: ok — green signal */
.callout--ok{border-color:var(--ux-ok);border-left-color:var(--ux-ok);background:var(--ux-ok-tint)}
.callout--ok .callout__title{color:var(--ux-ok)}
.callout--ok .callout__body{color:var(--ux-ink-soft)}

/* tone: warn — yellow signal */
.callout--warn{border-color:var(--ux-warn);border-left-color:var(--ux-warn);background:var(--ux-warn-tint)}
.callout--warn .callout__title{color:var(--ux-warn)}
.callout--warn .callout__body{color:var(--ux-ink-soft)}

/* tone: danger — red signal */
.callout--danger{border-color:var(--ux-danger);border-left-color:var(--ux-danger);background:var(--ux-danger-tint)}
.callout--danger .callout__title{color:var(--ux-danger)}
.callout--danger .callout__body{color:var(--ux-ink-soft)}

/* tone: brand — gradient signal */
.callout--brand{border-color:var(--ux-brand);border-left-color:var(--ux-brand);background:var(--ux-brand-tint)}
.callout--brand .callout__title{color:var(--ux-brand)}
.callout--brand .callout__body{color:var(--ux-ink-soft)}


/* ── Card ── */

.card{display:block;background:var(--ux-surface);border:1px solid var(--ux-line);border-radius:var(--ux-radius-md);color:inherit;text-decoration:none;overflow:hidden}
.card--radius-lg{border-radius:var(--ux-radius-lg)}
.card--pad-none{padding:0}
.card--pad-sm{padding:var(--ux-space-3)}
.card--pad-md{padding:var(--ux-space-4) 18px}
.card--pad-lg{padding:var(--ux-space-5)}
.card--link{transition:border-color var(--ux-dur-fast) var(--ux-ease-out)}
.card--link:hover{border-color:var(--ux-brand)}
/* non-link card whose CHILD is the real link/button (figure/article shapes) — same feedback,
   fired on :hover (pointer anywhere over the box) or :focus-within (keyboard on the child). */
.card--interactive{transition:border-color var(--ux-dur-fast) var(--ux-ease-out)}
.card--interactive:hover,.card--interactive:focus-within{border-color:var(--ux-brand)}
.card--lift{transition:transform var(--ux-dur-fast) var(--ux-ease-out),box-shadow var(--ux-dur-fast) var(--ux-ease-out),border-color var(--ux-dur-fast) var(--ux-ease-out)}
.card--lift:hover,.card--lift:focus-within{transform:translateY(-2px)}
.card--lift-shadow:hover,.card--lift-shadow:focus-within{box-shadow:var(--ux-shadow-md)}
.card--raised{background:var(--ux-raised)}
.card--brand{border-left:3px solid var(--ux-brand)}


/* ── CheckList ── */

.ckl{display:grid;gap:var(--ux-space-5)}
.ckl-top{margin:0;display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--ux-space-2) var(--ux-space-4)}
.ckl-hl{font-family:var(--ux-font-display);font-size:var(--ux-text-h3);font-weight:var(--ux-weight-semibold);letter-spacing:var(--ux-track-snug)}
.ckl-hl--bad{color:var(--ux-danger)}
.ckl-hl--ok{color:var(--ux-ok)}
.ckl-hl--none{color:var(--ux-ink-muted)}
.ckl-unk{font:var(--ux-text-caption)/1.5 var(--ux-font-mono);color:var(--ux-ink-muted)}
.ckl-bad{display:grid;gap:var(--ux-space-3)}
.ckl-card{border:1px solid var(--ux-danger);background:var(--ux-danger-tint);border-radius:var(--ux-radius-md);padding:var(--ux-space-4) var(--ux-space-5)}
.ckl-card__h{margin:0 0 var(--ux-space-2);font-size:var(--ux-text-h3);font-weight:var(--ux-weight-semibold);color:var(--ux-ink)}
.ckl-fact{margin:0 0 var(--ux-space-2);color:var(--ux-ink);font-size:var(--ux-text-small);line-height:var(--ux-leading-snug)}
.ckl-ev{margin:0 0 var(--ux-space-2);font:var(--ux-text-caption)/1.55 var(--ux-font-mono);color:var(--ux-ink-muted)}
.ckl-fix{margin:0;font-size:var(--ux-text-small);line-height:var(--ux-leading-snug);color:var(--ux-ink-soft)}
.ckl-fix__k{display:inline-block;margin-right:var(--ux-space-2);font:var(--ux-weight-semibold) var(--ux-text-micro)/1 var(--ux-font-mono);letter-spacing:var(--ux-track-caps);text-transform:uppercase;color:var(--ux-brand-ink)}
.ckl-grp{display:grid;gap:var(--ux-space-2)}
.ckl-grp__h{margin:0;display:flex;align-items:baseline;gap:var(--ux-space-2);font:var(--ux-weight-semibold) var(--ux-text-micro)/1 var(--ux-font-mono);letter-spacing:var(--ux-track-caps);text-transform:uppercase;color:var(--ux-ink-muted)}
.ckl-grp__h span{color:var(--ux-ink-muted);font-weight:var(--ux-weight-normal)}
.ckl-q{border-bottom:1px solid var(--ux-line)}
.ckl-q>summary{cursor:pointer;padding:var(--ux-space-2) 0;font-size:var(--ux-text-small);color:var(--ux-ink-soft);list-style:none}
.ckl-q>summary::-webkit-details-marker{display:none}
.ckl-q>summary::before{content:"+";display:inline-block;width:1.1em;color:var(--ux-ink-muted);font-family:var(--ux-font-mono)}
.ckl-q[open]>summary::before{content:"–"}
.ckl-q>summary:focus-visible{outline:none;box-shadow:var(--ux-focus-ring);border-radius:var(--ux-radius-xs)}
.ckl-q>p{margin:0 0 var(--ux-space-2) 1.1em}
.ckl-pass__a{color:inherit;text-decoration:underline;text-underline-offset:3px;text-decoration-color:var(--ux-line-strong)}
.ckl-pass__a:hover{color:var(--ux-brand-ink)}
.ckl-pass__a:focus-visible{outline:none;box-shadow:var(--ux-focus-ring);border-radius:var(--ux-radius-xs)}
.ckl-id{display:inline-block;margin:0 0 var(--ux-space-2);overflow-wrap:anywhere;font:var(--ux-text-micro)/1 var(--ux-font-mono);font-weight:var(--ux-weight-normal);color:var(--ux-ink-muted);text-decoration:none;word-break:break-all}
.ckl-id:hover{color:var(--ux-brand-ink)}
.ckl-id:focus-visible{outline:none;box-shadow:var(--ux-focus-ring);border-radius:var(--ux-radius-xs)}
.ckl-card,.ckl-q{scroll-margin-top:var(--ux-space-7)}
.ckl-pass{margin:0;font-size:var(--ux-text-small);color:var(--ux-ink-muted);line-height:var(--ux-leading-snug)}


/* ── Cite ── */

/* Footnote markers and the source list. Quiet by design: a citation should be findable, not loud.
   NO BACKTICKS IN THIS BLOCK. */
/* A FLOOR ON THE MARKER SIZE. .62em against a 14px parent computes to 8.68px, which is what the
   homepage markers actually measured at 390px — a speck, not a reference, and the whole point of
   the apparatus is that a reader can SEE a figure has provenance (issue 200). max() keeps the relative
   sizing where the parent is large and stops it collapsing where the parent is small.
   The tap target is widened separately below: 11px of glyph is legible but not tappable. */
.cite-ref{font-size:max(11px,.62em);line-height:0;vertical-align:super;margin-left:2px}
.cite-ref a{text-decoration:none;color:var(--ux-brand-ink);padding:2px 4px;border-radius:3px;
  background:var(--ux-brand-tint);font-weight:600}
.cite-ref a:hover,.cite-ref a:focus-visible{background:var(--ux-brand-tint);color:var(--ux-brand)}
.cite-notes{margin:44px 0 0;padding:20px 22px;border-top:1px solid var(--ux-line-strong);background:var(--ux-raised);border-radius:var(--ux-radius-md)}
.cite-notes-h{font:700 11.5px/1 var(--ux-font-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ux-ink-muted);margin:0 0 12px}
.cite-list{margin:0;padding-left:20px}
.cite-list li{font-size:13.5px;line-height:1.65;color:var(--ux-ink-soft);margin:0 0 8px}
.cite-list li:target{background:var(--ux-brand-tint);border-radius:var(--ux-radius-xs);padding:2px 6px;margin-left:-6px}
.cite-src{color:var(--ux-ink);font-family:var(--ux-font-mono);font-size:12.5px;word-break:break-word}
.cite-back{text-decoration:none;color:var(--ux-ink-muted);margin-left:4px}
.cite-back:hover{color:var(--ux-brand-ink)}
.cite-foot{margin:14px 0 0;font-size:12.5px;color:var(--ux-ink-muted)}


/* ── CorpusSearch ── */

/* ── CorpusSearch — the name→funnel door (#446). Token-only; no literal colours. ── */
.cs{max-width:640px;margin:0 auto;text-align:left}
.cs-label{display:block;font:700 13px/1.4 var(--ux-font-mono);letter-spacing:var(--ux-track-kicker);text-transform:uppercase;color:var(--ux-ink-muted);margin:0 0 10px}
.cs-row{display:flex;gap:10px;flex-direction:column}
@media(min-width:600px){.cs-row{flex-direction:row}}
.cs-input{flex:1;min-width:0;background:var(--ux-code-bg);border:2px solid var(--ux-line-strong);border-radius:14px;color:var(--ux-ink);font-family:var(--ux-font-mono);font-size:16px;padding:14px 18px;min-height:52px;outline:0;transition:border-color .2s,box-shadow .2s}
.cs-input::placeholder{color:var(--ux-ink-muted)}
.cs-input:focus{border-color:var(--ux-brand);box-shadow:var(--ux-focus-ring)}
.cs-go{flex:none;min-height:52px;border:0;cursor:pointer;font:800 15px/1 var(--ux-font-sans);color:var(--ux-on-brand);background:var(--ux-brand);padding:14px 26px;border-radius:14px;transition:transform .18s cubic-bezier(.2,.7,.2,1),box-shadow .18s}
.cs-go:hover{transform:translateY(-2px);box-shadow:var(--ux-shadow-md)}
.cs-hint{font:600 13px/1.5 var(--ux-font-mono);color:var(--ux-ink-muted);margin:10px 0 0}
.cs-hint b{color:var(--ux-ink)}
/* results */
.cs-out{margin:14px 0 0}
.cs-list{list-style:none;margin:0;padding:0;border:1px solid var(--ux-line);border-radius:14px;overflow:hidden;background:var(--ux-surface)}
.cs-item + .cs-item{border-top:1px solid var(--ux-line)}
.cs-link{display:flex;align-items:center;gap:10px;padding:12px 14px;text-decoration:none;color:var(--ux-ink);font-family:var(--ux-font-sans);font-size:15px}
.cs-link:hover{background:var(--ux-code-bg)}
.cs-link:focus-visible{outline:2px solid var(--ux-brand);outline-offset:-2px}
.cs-fav{width:20px;height:20px;flex:none;border-radius:4px;object-fit:contain}
.cs-fav-none{display:inline-flex;align-items:center;justify-content:center;font:800 11px/1 var(--ux-font-mono);background:var(--ux-code-bg);color:var(--ux-ink-muted)}
.cs-name{font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cs-type{font:600 11px/1 var(--ux-font-mono);text-transform:uppercase;letter-spacing:var(--ux-track-kicker);color:var(--ux-ink-muted);border:1px solid var(--ux-line);border-radius:999px;padding:4px 8px;flex:none}
.cs-when{margin-left:auto;font:600 12px/1 var(--ux-font-mono);color:var(--ux-ink-muted);flex:none;white-space:nowrap}
/* the miss — the common case for a recognisable name, and the one that must not read as "empty" */
.cs-none{margin:0;padding:14px;border:1px dashed var(--ux-line-strong);border-radius:14px;font-family:var(--ux-font-sans);font-size:15px;color:var(--ux-ink);background:var(--ux-surface)}
.cs-none b{font-weight:700}
.cs-scan{color:var(--ux-brand);font-weight:800;text-decoration:none;white-space:nowrap}
.cs-scan:hover{text-decoration:underline}
.cs-none-sub{margin:8px 0 0;font:600 12.5px/1.5 var(--ux-font-mono);color:var(--ux-ink-muted)}
.cs-more{margin:8px 0 0;font:600 12.5px/1.5 var(--ux-font-mono);color:var(--ux-ink-muted)}
@media(max-width:520px){.cs-type{display:none}}


/* ── DeviceToggle ── */
/* DeviceToggle (#555) — the desktop/mobile segmented control.
   Lifted verbatim from report.css:884-887, so the report renders byte-identically.

   IN css/ RATHER THAN A TEMPLATE LITERAL IN THE MODULE, and that is forced rather than stylistic:
   ds/components/device-toggle.js reaches the Worker bundle (worker/api.js imports shotCard from
   factory/library-ui.js, which imports this), so it cannot read a file at module scope — and
   issue-375 refuses NEW CSS inside a JS template literal. css/<basename>.css is the convention
   lint-component-css.mjs resolves for exactly this case: a Worker-bundled module whose CSS lives
   on disk. ds/build-css.js reads it at BUILD time, where fs is available, and compiles it into
   ds/ds.css — which the report bundle and every signalShell page both already load. */
.ed-seg{display:inline-flex;border:1px solid var(--ux-line-strong);border-radius:var(--ux-radius-sm);overflow:hidden;background:var(--ux-surface)}
.ed-seg button{display:flex;align-items:center;gap:7px;border:0;background:none;color:var(--ux-ink-muted);font:var(--ux-weight-semibold) 13px/1 var(--ux-font-sans);padding:9px 14px;cursor:pointer;border-right:1px solid var(--ux-line)}
.ed-seg button:last-child{border-right:0}
.ed-seg button[aria-pressed=true]{background:var(--ux-ink);color:var(--ux-surface)}


/* ── Engagement ── */

.stats{display:inline-flex;align-items:center;gap:14px}
.stats .stat{display:inline-flex;align-items:center;gap:5px;background:none;border:0;padding:0;
  color:var(--ux-ink-muted);font:var(--ux-weight-semibold) var(--ux-text-caption)/1 var(--ux-font-mono);
  font-variant-numeric:tabular-nums}
.stats .stat-n{min-width:1.6ch;text-align:left}
.stats .eye{cursor:default}
.stats .heart{cursor:pointer;transition:color var(--ux-dur-fast) var(--ux-ease-out)}
.stats .heart:hover{color:var(--ux-brand)}
.stats .heart[aria-pressed="true"]{color:var(--ux-brand)}
.stats .heart:focus-visible{outline:2px solid var(--ux-brand);outline-offset:3px;border-radius:6px}


/* ── FAQ ── */

.faq{background:var(--ux-bg);padding:var(--ux-space-7) var(--ux-space-4);position:relative}
.faq::before{content:"";position:absolute;top:0;left:50%;transform:translateX(-50%);width:min(1180px,90%);height:1px;background:var(--ux-hairline)}
.faq__wrap{max-width:760px;margin:0 auto}
.faq-item{background:var(--ux-surface);border:1px solid var(--ux-line);border-radius:var(--ux-radius-lg);margin-bottom:var(--ux-space-3);transition:border-color var(--ux-dur-base) var(--ux-ease-out),box-shadow var(--ux-dur-base) var(--ux-ease-out)}
.faq-item:hover{border-color:color-mix(in srgb,var(--ux-accent) 35%,transparent)}
.faq-item[open]{border-color:color-mix(in srgb,var(--ux-brand) 35%,transparent);box-shadow:0 8px 32px color-mix(in srgb,var(--ux-accent) 12%,transparent)}
.faq-item summary{cursor:pointer;list-style:none;display:flex;justify-content:space-between;align-items:center;gap:var(--ux-space-4);padding:var(--ux-space-5) var(--ux-space-6);font-family:var(--ux-font-sans);font-size:var(--ux-text-h3);font-weight:var(--ux-weight-semibold);color:var(--ux-ink)}
.faq-item summary::-webkit-details-marker{display:none}
.faq-item summary::after{content:"+";font-family:var(--ux-font-mono);font-size:20px;color:var(--ux-brand);flex:none;transition:transform var(--ux-dur-base) var(--ux-ease-out)}
.faq-item[open] summary::after{transform:rotate(45deg)}
.faq-item p{margin:0;padding:0 var(--ux-space-6) var(--ux-space-5);color:var(--ux-ink-muted);font-size:var(--ux-text-small);line-height:var(--ux-leading-normal)}
@media(max-width:760px){
  .faq{padding:var(--ux-space-7) var(--ux-space-4)}
  .faq-item summary{padding:var(--ux-space-5) var(--ux-space-4);font-size:var(--ux-text-body)}
  .faq-item p{padding:0 var(--ux-space-4) var(--ux-space-4)}
}


/* ── DataFigure ── */

.datafig{margin:var(--ux-space-5) 0;padding:var(--ux-space-4);border:1px solid var(--ux-line);border-radius:var(--ux-radius-md);background:var(--ux-surface)}
/* NOT a coloured left border. Ben, 2026-08-19: "critical rule; no left border color, ever."
   scripts/lint-no-left-border.mjs ratchets these down and refused the 20th, which was this line.
   The lead variant earns its emphasis from a tint and a stronger edge instead — same signal, none
   of the treatment he named. */
.datafig--lead{background:color-mix(in srgb,var(--ux-brand) 4%,var(--ux-surface));border-color:var(--ux-line-strong)}
.datafig__title{font-family:var(--ux-font-sans);font-size:var(--ux-text-small);font-weight:var(--ux-weight-semibold);color:var(--ux-ink);margin:0 0 var(--ux-space-3);letter-spacing:var(--ux-track-snug)}
.datafig__body{margin:0}
.datafig__cap{font-family:var(--ux-font-mono);font-size:var(--ux-text-caption);line-height:var(--ux-leading-normal);color:var(--ux-ink-muted);margin:var(--ux-space-3) 0 0}
.datafig__src{color:var(--ux-ink-muted);text-decoration:underline}
.datafig__big{font-family:var(--ux-font-display);font-weight:var(--ux-weight-heavy);font-size:clamp(44px,11vw,84px);line-height:.95;letter-spacing:var(--ux-track-tight);color:var(--ux-brand-ink)}
.datafig__unit{font-size:.42em;margin-left:.12em;color:var(--ux-ink-muted)}


/* ── FinalCta ── */

.finalcta{background:var(--ux-brand);width:100vw;margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw);padding:clamp(72px,10vw,120px) 0 clamp(80px,10vw,128px);text-align:center;position:relative;overflow:hidden}
.finalcta::before{content:"";position:absolute;inset:0;pointer-events:none;background-image:repeating-linear-gradient(115deg,rgba(255,255,255,.10) 0 1px,transparent 1px 46px)}
.finalcta-chip{display:inline-flex;align-items:center;gap:8px;font:800 12px/1 var(--ux-font-mono);letter-spacing:.16em;text-transform:uppercase;color:var(--ux-on-brand);background:rgba(10,10,10,.14);border:1px solid rgba(10,10,10,.3);padding:10px 18px;border-radius:99px;margin:0 0 26px;position:relative}
.finalcta h2{font-family:var(--ux-font-display);color:#fff;font-size:clamp(34px,6.4vw,66px);line-height:1.02;margin:0 0 36px;font-weight:800;position:relative;text-wrap:balance;overflow-wrap:break-word}
.cta-card{max-width:660px;margin:0 auto;position:relative;background:#fff;border-radius:22px;padding:clamp(20px,3vw,30px);box-shadow:0 30px 70px rgba(0,0,0,.28)}
.cta-card .scan-url{background:rgba(10,10,10,.045);color:#0a0a0a;border-color:rgba(10,10,10,.18)}
.cta-card .scan-url::placeholder{color:transparent}
.cta-card .scan-ghost{color:rgba(10,10,10,.62)}
.cta-card .scan-go{background:#0a0a0a;color:#fff;box-shadow:0 14px 30px rgba(0,0,0,.35)}
.cta-card .scan-hint{color:rgba(10,10,10,.6)}
.cta-card .scan-hint b{color:#0a0a0a}


/* ── FindingRow ── */

.fr{background:var(--ux-surface);border:1px solid var(--ux-line);border-radius:var(--ux-radius-md);padding:var(--ux-space-4) var(--ux-space-4) var(--ux-space-4);display:grid;gap:var(--ux-space-3)}
/* NO COLOURED LEFT BORDER (Ben, 2026-08-19: "critical rule; no left border color, ever").
   These five were a 3px severity stripe down the side of every FindingRow — the accent-bar card
   that reads as generic AI output, and the specific thing Ben named on the report page. Tone is
   still expressed, just not as a rail: the status pill already carries the word AND its colour,
   which is the accessible signal anyway (a colour-only bar says nothing to a screen reader).
   The tone classes are KEPT as hooks, so callers do not change and a future treatment has
   somewhere to attach — they simply no longer paint an edge. Gated by
   scripts/lint-no-left-border.mjs. */
.fr-tone-ok,.fr-tone-warn,.fr-tone-danger,.fr-tone-neutral,.fr-tone-brand{border-left:0}
.fr-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--ux-space-3);flex-wrap:wrap}
.fr-headline{margin:0;font-size:var(--ux-text-body);font-weight:var(--ux-weight-semibold);color:var(--ux-ink);line-height:var(--ux-leading-snug);flex:1;min-width:220px}
.fr-status{display:inline-flex;align-items:center;gap:8px;flex:none;padding:4px 10px 4px 4px;border-radius:var(--ux-radius-pill);background:var(--ux-raised);border:1px solid var(--ux-line)}
.fr-status-flat{padding:5px 12px}
.fr-status-meter{width:44px;height:6px;border-radius:var(--ux-radius-pill);background:var(--ux-line);overflow:hidden;flex:none}
.fr-status-meter i{display:block;height:100%;border-radius:var(--ux-radius-pill)}
.fr-status-ok .fr-status-meter i{background:var(--ux-ok)}
.fr-status-warn .fr-status-meter i{background:var(--ux-warn)}
.fr-status-danger .fr-status-meter i{background:var(--ux-danger)}
.fr-status-neutral .fr-status-meter i{background:var(--ux-ink-muted)}
.fr-status-brand .fr-status-meter i{background:var(--ux-brand)}
.fr-status-val{font:var(--ux-weight-bold) var(--ux-text-small)/1 var(--ux-font-mono);color:var(--ux-ink);font-variant-numeric:tabular-nums}
.fr-status-val small{font-weight:var(--ux-weight-medium);color:var(--ux-ink-muted)}
.fr-status-l{font-size:var(--ux-text-caption);font-weight:var(--ux-weight-semibold);letter-spacing:var(--ux-track-wide);text-transform:uppercase;color:var(--ux-ink-muted)}
.fr-status-ok .fr-status-l{color:var(--ux-ok)}
.fr-status-warn .fr-status-l{color:var(--ux-warn)}
.fr-status-danger .fr-status-l{color:var(--ux-danger)}
.fr-status-brand .fr-status-l{color:var(--ux-brand)}
.fr-evidence-list{list-style:none;margin:0;padding:0;display:grid;gap:10px}
.fr-ev{display:grid;gap:5px}
.fr-ev-label{font-size:var(--ux-text-small);font-weight:var(--ux-weight-semibold);color:var(--ux-ink)}
.fr-ev-quotes{display:flex;flex-wrap:wrap;gap:7px}
.fr-ev-quotes q{quotes:none;font-family:var(--ux-font-mono);font-size:var(--ux-text-caption);color:var(--ux-ink);background:var(--ux-brand-tint);border:1px solid var(--ux-line);border-radius:7px;padding:3px 10px}
.fr-ev-quotes q::before,.fr-ev-quotes q::after{content:'"';color:var(--ux-ink-muted)}
.fr-ev-note{font-size:var(--ux-text-caption);color:var(--ux-ink-muted)}
.fr-evidence{margin:0}
.fr-evidence-empty{margin:0;font-size:var(--ux-text-small);color:var(--ux-ink-muted);font-style:italic}
.fr-gaps{border-top:1px dashed var(--ux-line);padding-top:var(--ux-space-3);display:grid;gap:8px}
.fr-gaps-h{margin:0;font-family:var(--ux-font-mono);font-size:var(--ux-text-micro);letter-spacing:var(--ux-track-caps);text-transform:uppercase;color:var(--ux-ink-muted)}
.fr-gaps-list{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:8px}
.fr-gap{display:inline-flex;align-items:baseline;gap:7px;padding:5px 12px;border-radius:999px;border:1px dashed var(--ux-line);font-size:var(--ux-text-caption);color:var(--ux-ink-muted)}
.fr-gap-label{color:var(--ux-ink);font-weight:var(--ux-weight-medium)}
.fr-gap-note{font-size:var(--ux-text-caption);color:var(--ux-ink-muted)}
/* actionHtml slot (e.g. CategoryResult's per-tactic dispute button) sits last in the chip. */
.fr-gap > .fr-gap-action{margin-left:2px}
.fr-gaps-empty{margin:0;font-size:var(--ux-text-small);color:var(--ux-ink-muted)}
.fr-measurement{margin:0;font-family:var(--ux-font-mono);font-size:var(--ux-text-micro);color:var(--ux-ink-muted);line-height:var(--ux-leading-normal);border-top:1px solid var(--ux-line);padding-top:var(--ux-space-2)}
.fr-detail{margin:0}
.fr-detail-sum{cursor:pointer;font-size:var(--ux-text-caption);font-weight:var(--ux-weight-semibold);color:var(--ux-accent);list-style:none}
.fr-detail-sum::-webkit-details-marker{display:none}
.fr-detail-body{margin-top:var(--ux-space-3)}


/* ── Footer ── */

/* #255: overflow:clip (not the default visible) is THE FIX, not a container clamp. Nothing about
   .footer's own height changes and no report row is touched — this crops exactly one thing, the
   decorative .footer__wordmark below, at the box that already owns it. Full story on that rule. */
.footer{background:var(--ux-bg);padding:var(--ux-space-7) var(--ux-space-4) var(--ux-space-5);position:relative;overflow:clip}
.footer::before{content:"";position:absolute;top:0;left:50%;transform:translateX(-50%);width:min(1180px,90%);height:1px;background:var(--ux-hairline)}
.footer__wrap{max-width:1180px;margin:0 auto;display:grid;grid-template-columns:1.4fr repeat(3,1fr);gap:var(--ux-space-6)}
/* The giant ghost mark. LIVES HERE, not in signal-shell.js, because the component that emits the
   markup must own its rule: while it sat in the shell, every /ux-report/ page rendered a naked,
   full-size "UXXRAY" above the footer columns, since that chain never loads the shell's CSS.
   Colour is theme-derived rather than the old rgba(255,255,255,.035) — a white ghost is invisible
   on the paper ground every surface now uses, and a raw rgba is what the token ratchet exists to
   stop.
   The bottom:-6vw below is DELIBERATE bleed (#217) — the mark is meant to hang off the footer's
   own edge, the same way its right edge already bleeds past the viewport. On the homepage
   (signal-shell.js) that bleed is invisible because its body element carries an inline
   position:relative style that happens to size the document to its own content and leaves the
   tail unreachable; a /ux-report/<slug> page (components.js PageShell, no such body style) has no
   such accident, so the SAME geometry — measured live, #255: the wordmark's own box reaches 86px
   (1440px) / 24px (390px) past .footer's bottom edge — was landing directly in
   document.documentElement.scrollHeight as 119px / 37px of genuine, scrollable,
   nothing-painted-there space below the footer. The overflow:clip added to .footer above crops the
   bleed at the box that already owns it, matching what already (accidentally) happens elsewhere,
   without relying on a body-level accident. It does not touch the html,body overflow-x:clip pair
   (report.css ~line 448) and does not sit anywhere near the sticky docs sidebar's ancestor chain,
   so neither of that rule's two known failure modes applies here. */
.footer__wordmark{position:absolute;right:clamp(-40px,-2vw,0px);bottom:-6vw;font-family:var(--ux-font-display,var(--ux-font-sans));font-weight:var(--ux-weight-bold);font-size:clamp(120px,20vw,320px);line-height:1;color:color-mix(in srgb,var(--ux-ink) 5%,transparent);letter-spacing:-.03em;pointer-events:none;white-space:nowrap;z-index:0;user-select:none}
/* LAYOUT ONLY (#239). The wordmark's font, size, weight and tracking come from .brand in
   ds/components/brand.js — this rule used to restate all four and render a different logo. */
.footer__mark{margin:0 0 10px}
/* The .footer__mark em rule was REMOVED 2026-08-11 (#239). It painted the gradient on an <em> the mark
   has not contained since it became Brand({variant:'plain'}), which emits
   <span class="brand"><span class="brand-ux">UX</span>XRAY</span>. Verified against the live
   page: zero <em> inside any footer__mark. Dead CSS that LOOKED like it owned the wordmark's
   gradient — the real gradient comes from .brand-ux in ds/components/brand.js. Exactly the
   class of never-matching selector #147 exists to find. */
.footer__tag{font-family:var(--ux-font-mono);font-size:var(--ux-text-micro);letter-spacing:var(--ux-track-wide);text-transform:uppercase;color:var(--ux-ink-muted);margin:0}
.footer__col h2{font-family:var(--ux-font-mono);font-size:12px;letter-spacing:var(--ux-track-caps);text-transform:uppercase;color:var(--ux-ink-muted);margin:0 0 18px;font-weight:var(--ux-weight-semibold)}
.footer__col ul{list-style:none;margin:0;padding:0}
.footer__col li{margin-bottom:var(--ux-space-3)}
.footer__col a{color:var(--ux-ink);opacity:.75;text-decoration:none;font-size:var(--ux-text-small);font-family:var(--ux-font-sans);transition:opacity var(--ux-dur-fast) var(--ux-ease-out),color var(--ux-dur-fast) var(--ux-ease-out)}
.footer__col a:hover{opacity:1;color:var(--ux-brand)}
.footer__legal{max-width:1180px;margin:var(--ux-space-6) auto 0;padding-top:var(--ux-space-4);border-top:1px solid var(--ux-line);display:flex;justify-content:space-between;gap:var(--ux-space-4);flex-wrap:wrap}
.footer__legal p{font-family:var(--ux-font-mono);font-size:12px;color:var(--ux-ink-muted);opacity:.6;margin:0}
@media(max-width:760px){
  .footer{padding:var(--ux-space-7) var(--ux-space-4) var(--ux-space-5)}
  .footer__wrap{grid-template-columns:1fr;gap:var(--ux-space-7)}
  .footer__legal{flex-direction:column}
}


/* ── Meter ── */

.meter{margin:0 0 var(--ux-space-3)}
.meter__head{display:flex;justify-content:space-between;align-items:baseline;gap:var(--ux-space-3);margin:0 0 6px}
.meter__label{font-size:var(--ux-text-small);color:var(--ux-ink);font-weight:var(--ux-weight-semibold)}
.meter__val{font:var(--ux-weight-bold) var(--ux-text-small)/1 var(--ux-font-mono);color:var(--ux-ink);font-variant-numeric:tabular-nums}
.meter__track{height:6px;border-radius:var(--ux-radius-pill);background:var(--ux-raised);overflow:hidden}
.meter__fill{display:block;height:100%;border-radius:var(--ux-radius-pill);transition:width var(--ux-dur-slow) var(--ux-ease-out)}
.meter__fill--brand{background:var(--ux-grad)}
.meter__fill--ok{background:var(--ux-ok)}
.meter__fill--warn{background:var(--ux-warn)}
.meter__fill--danger{background:var(--ux-danger)}
.meter__hint{font-size:var(--ux-text-caption);color:var(--ux-ink-muted);margin-top:4px}


/* ── Nav ── */

/* ────────────────────────────────────────────────────────────────────────────
   NAV — sticky top bar, main nav + submenu variants. Backdrop blur, bottom border.
   ──────────────────────────────────────────────────────────────────────────── */

.nav{position:sticky;top:0;z-index:var(--ux-z-sticky);border-bottom:1px solid var(--ux-line);background:var(--ux-glass);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}

/* ── top variant ──
   EVERY child of .nav-in states its flex behaviour. The bug this replaces was flex:0 on a
   nowrap row: nothing could shrink, so the bar overran its own box and overflow-x:clip on
   <html> ate the evidence. Keep the row shrinkable and keep the row SHORT. */
.nav--top .nav-in{max-width:var(--ux-maxw);margin:0 auto;padding:var(--ux-space-3) var(--ux-space-4);display:flex;align-items:center;gap:clamp(var(--ux-space-3),3vw,var(--ux-space-6));min-width:0}

/* THE BAR SIZES THE MARK; IT DOES NOT DRAW IT (#150). .nav-brand / .nav-brand-ux are gone — they
   were a second copy of the wordmark's appearance, and the markup they styled is no longer
   emitted (Nav now calls Brand()). Identity — the string, the UX split, the gradient — belongs to
   ds/components/brand.js. Scale is contextual, so it stays here: the bar wants display size,
   /scan wants 19px, /factory/ wants something quieter. */
/* .nav--top .brand REMOVED (#239): the display font and clamp size are now the
   canonical treatment in ds/components/brand.js, inherited everywhere. */

.nav-links{flex:1 1 auto;min-width:0;display:flex}
.nav-list{display:flex;align-items:center;gap:clamp(var(--ux-space-3),2.5vw,var(--ux-space-6));list-style:none;margin:0;padding:0;min-width:0}
.nav-item{position:relative;display:flex;align-items:center}
.nav-links a{color:var(--ux-ink-muted);text-decoration:none;font-size:var(--ux-text-small);letter-spacing:.01em;transition:color var(--ux-dur-fast) var(--ux-ease-out)}
.nav-links a:hover{color:var(--ux-ink)}
.nav-links a.active{color:var(--ux-ink);box-shadow:inset 0 -2px 0 var(--ux-brand)}

/* ── right-hand actions: BOTH are Button() now, so this block owns LAYOUT ONLY ──
   .nav-btn / .nav-cta are gone. They were two hand-written rules whose only real difference was
   horizontal padding (space-4 vs space-5), which is why the two CTAs rendered at visibly
   different widths for the same label length. Styling a button here again would recreate exactly
   that drift: variant and size belong to ds/components/button.js. */
.nav-actions{flex:0 0 auto;margin-left:auto;display:flex;align-items:center;gap:var(--ux-space-3)}

/* focus must be VISIBLE on every interactive thing in the bar — the old bar shipped with only
   the UA default, which the brand-filled CTA all but swallowed. */
.nav--top .nav-link:focus-visible{outline:none;box-shadow:var(--ux-focus-ring);border-radius:var(--ux-radius-xs)}
/* the brand's own focus ring travels with Brand's CSS chunk, so it is identical on /scan and
   /factory/ where this bar does not exist */
/* NOT a bare .nav--top a selector — that swept up the CTAs too and forced radius-xs onto them, squaring off a
   pill on focus only. Button owns .btn:focus-visible; the bar must not reach into it. */

/* long labels shrink on a phone rather than pushing the row off screen */
.nav-t-short{display:none}

/* THE TIER GROUP AND ITS STAND-IN ARE MUTUALLY EXCLUSIVE, ALWAYS. Exactly one of them is in the
   layout at any width — never both, never neither. The stand-in is display:none by default so a
   wide bar shows the four real tiers; below the breakpoint they swap. */
.nav-item--collapsed{display:none}

/* 640px is MEASURED. Forcing the tiers visible at every width and stepping the viewport in 10px
   increments, the widest viewport at which the four tier links do not all fit is 620px; 640 leaves
   a small margin. Raising this hides the IA on screens that can show it, which is the mistake the
   dropdown made. Lowering it clips links.
   AND THE METRIC MATTERS: .nav-in overflow is NOT the signal here. .nav-links is
   flex:1 1 auto;min-width:0, so a tight row is absorbed by the shrinkable child — measured
   barOver=0 at every width from 560 to 620 while .nav-links itself overflowed by up to 42px and
   the links were silently clipped INSIDE it. Measure .nav-links scrollWidth vs clientWidth, which
   is what test/nav-fit.test.js now asserts. */
@media(max-width:640px){
  .nav-item--tier{display:none}
  .nav-item--collapsed{display:flex}
}

@media(max-width:760px){
  .nav--top .nav-in{padding:var(--ux-space-2) var(--ux-space-4)}
  .nav-t-full{display:none}
  .nav-t-short{display:inline}
  .nav-actions{gap:var(--ux-space-2)}
}

/* The narrowest supported phone. At 320px the brand + Library + both CTAs overran .nav-links by
   1px with space-4 gutters — measured, and 1px is still a clipped link. Tighten the row's own
   padding rather than dropping a destination: nothing here is optional at this size.

   #299: that 1px was measured in the SETTLED webfont. In the fallback face the same row overran by
   6px, because the fallback is wider and .nav-links is the only shrinkable child — so brand and
   actions grow and starve it. Measured at 320px, fallback vs settled:

       .brand   (Fraunces) 81px -> 76px   +5
       .nav-actions (Hanken) 150 -> 143   +7
       .nav-links            45px <- 58px  -13, then overflows by 6px

   The fix is button padding, and ONLY button padding. Measured at 320px the row is brand 81 +
   links 45 + actions 150 + 2x8px gap in a 320px box, and .nav-actions is two .btn--sm at 14px side
   padding — 56px across the two. Dropping to space-2 frees 24px, covering the gap with room spare.
   SCOPED to .nav-actions on purpose: .btn--sm is a shared primitive and this is a nav-at-320px
   problem, not a button problem. Tap targets are untouched — only side padding moves.

   WHAT WAS TRIED AND REMOVED, so nobody re-adds it: metric-matched fallback @font-face faces
   ('Hanken-fallback' / 'Fraunces-fallback' with size-adjust, added to --g-sans/--g-display). They
   were INERT and the gate proved it — deleting them left it green, and the fallback-vs-settled
   width delta was byte-identical at all eight widths. Two reasons: the brand does not read
   --g-display at all (it computes to 'Fraunces, Georgia, "Times New Roman", serif'), and a face
   whose src is only local() is skipped outright where those families are absent. Tuning size-adjust
   to a fit needed ~89% anyway — an 11% shrink that trades a horizontal reflow for a visible
   type-size jump when the real face lands.

   THE RULE IS "the header fits in the fallback face", not "use padding". font-display:optional, a
   genuinely loaded metric-matched face, or a nav that fits either way are all valid — the gate
   asserts the outcome, so it cannot pin this implementation. */
@media(max-width:400px){
  .nav--top .nav-in{padding:var(--ux-space-2) var(--ux-space-3);gap:var(--ux-space-2)}
  .nav-actions .btn--sm{padding-left:var(--ux-space-2);padding-right:var(--ux-space-2)}
}

/* ── sub variant ── */
.nav--sub{background:color-mix(in srgb,var(--ux-overlay) 65%,transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}

.nav--sub .nav-sub-in{max-width:var(--ux-maxw);margin:0 auto;padding:var(--ux-space-2) clamp(var(--ux-space-4),4vw,var(--ux-space-6));display:flex;align-items:center;gap:var(--ux-space-3) var(--ux-space-5);flex-wrap:wrap}

.nav-sub-count{display:inline-flex;align-items:center;gap:var(--ux-space-2);color:var(--ux-ink-muted);text-decoration:none;font-family:var(--ux-font-mono);font-size:var(--ux-text-caption);letter-spacing:.03em;white-space:nowrap}
.nav-sub-count b{color:var(--ux-brand);font-size:var(--ux-text-micro)}
.nav-sub-count:hover{color:var(--ux-ink)}

.nav-sub-seg{display:inline-flex;gap:1px;padding:1px;background:color-mix(in srgb,var(--ux-ink) 4%,transparent);border:1px solid var(--ux-line);border-radius:var(--ux-radius-sm)}

.nav-sub-pill{display:inline-flex;align-items:center;gap:var(--ux-space-2);padding:var(--ux-space-2) var(--ux-space-4);border-radius:var(--ux-radius-sm);font-size:var(--ux-text-small);color:var(--ux-ink-muted);text-decoration:none;white-space:nowrap;transition:background var(--ux-dur-fast) var(--ux-ease-out),color var(--ux-dur-fast)}
.nav-sub-pill:hover{color:var(--ux-ink);background:color-mix(in srgb,var(--ux-ink) 6%,transparent)}
.nav-sub-pill.active{color:var(--ux-on-brand);background:var(--ux-grad);box-shadow:0 2px var(--ux-space-4) var(--ux-brand-tint)}

.nav-sub-all{margin-left:auto;color:var(--ux-brand);text-decoration:none;font-size:var(--ux-text-small);font-weight:var(--ux-weight-semibold);white-space:nowrap}
.nav-sub-all:hover{text-decoration:underline}

@media(max-width:640px){
  .nav--sub .nav-sub-in{padding:var(--ux-space-2) var(--ux-space-4);gap:var(--ux-space-2) var(--ux-space-3)}
  .nav-sub-count{order:1}
  .nav-sub-all{order:2;margin-left:auto}
  .nav-sub-seg{order:3;width:100%}
  .nav-sub-pill{flex:1;justify-content:center;padding:var(--ux-space-2) var(--ux-space-2)}
}


/* ── OgCard ── */

/* NO BACKTICKS IN THIS BLOCK. Absolute px throughout: the render viewport is 1200x630 and is the
   only viewport this markup ever sees, so there is nothing for a relative unit to be relative to. */
.og-card{position:relative;width:1200px;height:630px;background:var(--ux-bg);display:grid;
  grid-template-columns:1fr 440px;gap:56px;padding:72px 72px 64px;box-sizing:border-box;overflow:hidden}
.og-left{display:flex;flex-direction:column;justify-content:center;min-width:0}
.og-eyebrow{margin:0 0 26px;font:700 15px/1 var(--ux-font-mono);letter-spacing:.18em;color:var(--ux-brand)}
.og-title{margin:0;font:800 60px/1.08 var(--ux-font-display);letter-spacing:-.022em;color:var(--ux-ink);
  text-wrap:balance}
.og-statline{display:flex;align-items:baseline;gap:16px;margin:38px 0 0}
.og-stat{font:800 76px/1 var(--ux-font-display);letter-spacing:-.03em;color:var(--ux-brand)}
.og-stat-label{font:600 19px/1.3 var(--ux-font-sans);color:var(--ux-ink-soft);max-width:270px}
.og-source{margin:26px 0 0;font:500 15px/1.4 var(--ux-font-mono);color:var(--ux-ink-muted)}
/* the one accent rule: a full-bleed brand bar along the bottom edge */
.og-rule{position:absolute;left:0;right:0;bottom:0;height:10px;background:var(--ux-brand)}

/* ---- thumbnail: a 1200x420 strip for the /research/ listing, GRAPHIC ONLY -------------------
   One centred column, no text at any size. The diagram is drawn LARGER than in the full card and
   with heavier strokes, because it is about to be scaled to roughly 0.39x on the listing and a 2px
   hairline at that scale is a grey smudge. Height is set on .og-card itself: the screenshot is of
   that node, so its bounding box, not the viewport, decides the PNG's dimensions. */
.og-card--thumb{height:420px;padding:0;grid-template-columns:1fr;gap:0;place-items:center}
.og-card--thumb .og-right{width:100%;height:100%}
.og-card--thumb .og-mock{width:auto;height:300px}
.og-card--thumb .og-pg{border-width:3px;border-radius:14px;padding:22px}
.og-card--thumb .og-chrome i{width:11px;height:11px}
.og-card--thumb .og-bar{height:11px}
.og-card--thumb .og-r{height:18px;margin-bottom:16px;border-radius:4px}

/* depth: the three frames become the whole picture, centred rather than hugging a column edge.
   The offset stays DIAGONAL. Offsetting on x alone (the first attempt) reads as one frame with tabs
   down its side, not as pages stacked behind each other, and the stack IS the finding. */
.og-card--thumb .og-mock-depth{width:400px}
.og-card--thumb .og-mock-depth .og-pg{width:260px;height:260px}
.og-card--thumb .og-mock-depth .og-pg-3{top:0;right:0}
.og-card--thumb .og-mock-depth .og-pg-2{top:20px;right:30px}
.og-card--thumb .og-mock-depth .og-pg-1{top:40px;right:60px}

/* absence: one frame, and the empty slot is the point, so it gets more of the height */
.og-card--thumb .og-mock-absence{width:340px}
.og-card--thumb .og-mock-absence .og-pg-1{top:0;left:0;width:340px;height:300px}
.og-card--thumb .og-slot{height:74px;margin:16px 0;border-width:3px}
/* the slot's "NO PROOF" caption is hidden here, not shrunk. It is 13px in a 1200px image that the
   listing renders at ~470px, so it arrives as a 5px smear — the same unreadable-text problem the
   whole thumb variant exists to remove. A dashed empty box already says empty without words. */
.og-card--thumb .og-slot span{display:none}
.og-card--thumb .og-cta{height:40px}

/* census: a wide population reads better than a tall one in a 1200x420 strip */
.og-card--thumb .og-mock-census{width:620px}
.og-card--thumb .og-grid{inset:0;grid-template-columns:repeat(8,1fr);grid-template-rows:repeat(3,1fr);gap:14px}
.og-card--thumb .og-tile{border-width:3px;border-radius:8px}

/* ---- the mockup column ------------------------------------------------------------------ */
.og-right{position:relative;display:flex;align-items:center;justify-content:center}
.og-mock{position:relative;width:100%;height:420px}
.og-pg{position:absolute;background:var(--ux-surface);border:2px solid var(--ux-ink);
  border-radius:10px;padding:16px;box-sizing:border-box}
.og-chrome{display:flex;align-items:center;gap:6px;margin:0 0 16px}
.og-chrome i{width:8px;height:8px;border-radius:50%;background:var(--ux-line-strong)}
.og-bar{flex:1;height:8px;margin-left:8px;border-radius:4px;background:var(--ux-line)}
.og-r{height:13px;border-radius:3px;background:var(--ux-line-strong);margin:0 0 12px}
.og-r-lg{width:100%}
.og-r-md{width:74%}
.og-r-sm{width:46%}
.og-r.is-accent{background:var(--ux-brand)}

/* depth: three frames, the two behind faded and offset — the pages a shallow crawl never opens */
.og-mock-depth .og-pg{width:300px;height:300px}
.og-mock-depth .og-pg-3{top:0;right:0;opacity:.22}
.og-mock-depth .og-pg-2{top:38px;right:38px;opacity:.5}
.og-mock-depth .og-pg-1{top:76px;right:76px}

/* absence: one frame with an empty outlined slot where proof should be */
.og-mock-absence .og-pg-1{top:20px;left:32px;width:340px;height:380px}
.og-slot{height:78px;margin:18px 0;border:2px dashed var(--ux-brand);border-radius:8px;
  display:flex;align-items:center;justify-content:center;background:var(--ux-brand-tint)}
.og-slot span{font:700 13px/1 var(--ux-font-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ux-brand)}
.og-cta{height:34px;width:56%;border-radius:6px;background:var(--ux-ink)}

/* census: a population of tiles, one of them accented */
.og-grid{position:absolute;inset:24px 0;display:grid;grid-template-columns:repeat(4,1fr);
  grid-auto-rows:1fr;gap:14px}
.og-tile{border:2px solid var(--ux-ink);border-radius:6px;opacity:.28}
.og-tile.is-hit{background:var(--ux-brand);border-color:var(--ux-brand);opacity:1}


/* ── ScanBlock ── */

/* ── kicker + headline, only rendered when a caller passes heading/sub (the report's
   standalone CTA); the homepage hero form omits both and gets no extra markup. ── */
.scan-block-kicker{margin:0 0 12px;font:800 12px/1 var(--ux-font-mono);letter-spacing:var(--ux-track-kicker);text-transform:uppercase;color:var(--ux-brand)}
.scan-block-h{margin:0 0 20px;font-family:var(--ux-font-display);font-size:var(--ux-text-h2);font-weight:var(--ux-weight-bold);color:var(--ux-ink);line-height:1.15}
/* ── the scan form itself — moved from signal-shell.js so the Worker-safe report pipeline
   gets the same input/button without importing a file that reads ds.css off disk. ── */
.scanzone{max-width:720px}
/* flex:1 lives HERE, not on .scan-url. .scan-field is the flex CHILD of .scanbar-row; .scan-url
   is its grandchild, so a flex:1 declared there would govern nothing and the field would size to
   content. min-width:0 lets it shrink below the input's intrinsic width instead of overflowing.
   One rule fixes every surface that renders this form — same markup, same fix. */
.scan-field{position:relative;flex:1;min-width:0}
.scanbar-row{display:flex;gap:12px;flex-direction:column}
@media(min-width:600px){.scanbar-row{flex-direction:row}}
.scan-url{width:100%;flex:1;min-width:0;background:var(--ux-code-bg);border:2px solid var(--ux-line-strong);border-radius:18px;color:var(--ux-ink);font-family:var(--ux-font-mono);font-size:clamp(16px,2vw,18px);padding:20px 22px;min-height:60px;outline:0;transition:border-color .2s,box-shadow .2s;position:relative;z-index:1;background-color:transparent}
.scan-url::placeholder{color:transparent}
.scan-url:focus{border-color:var(--ux-brand);box-shadow:var(--ux-focus-ring)}
.scan-ghost{position:absolute;left:23px;top:0;bottom:0;display:flex;align-items:center;font-family:var(--ux-font-mono);font-size:clamp(16px,2vw,18px);color:var(--ux-ink-muted);pointer-events:none;white-space:nowrap;overflow:hidden;z-index:0}
.scan-caret{margin-left:2px;color:var(--ux-brand);animation:caret-blink 1s steps(1) infinite}
@keyframes caret-blink{50%{opacity:0}}
.scan-url:focus + .scan-ghost,.scan-url:not(:placeholder-shown) + .scan-ghost{display:none}
.scan-go{flex:none;min-height:60px;border:0;cursor:pointer;font:800 17px/1 var(--ux-font-sans);color:var(--ux-on-brand);background:var(--ux-brand);padding:18px 30px;border-radius:18px;box-shadow:var(--ux-shadow-md);display:inline-flex;align-items:center;justify-content:center;gap:10px;transition:transform .18s cubic-bezier(.2,.7,.2,1),box-shadow .18s;white-space:nowrap}
.scan-go .arw{display:inline-block;transition:transform .2s cubic-bezier(.2,.7,.2,1)}
.scan-go:hover{transform:translateY(-2px);box-shadow:var(--ux-shadow-lg)}
.scan-go:hover .arw{transform:translateX(5px)}
.scan-hint{font:600 13.5px/1.5 var(--ux-font-mono);color:var(--ux-ink-muted);margin:14px 0 0}
.scan-hint b{color:var(--ux-ink)}


/* ── Score ── */

.score__n{font-family:var(--ux-font-sans);font-weight:var(--ux-weight-bold);letter-spacing:var(--ux-track-tight);color:var(--ux-brand-ink);font-variant-numeric:tabular-nums;line-height:var(--ux-leading-solid)}
.score__d{font-family:var(--ux-font-mono);color:var(--ux-ink-muted)}
.score__band{font:var(--ux-weight-semibold) var(--ux-text-caption)/1 var(--ux-font-mono);letter-spacing:var(--ux-track-wide);text-transform:uppercase;color:var(--ux-ink-muted)}
/* dial */
.score--dial{position:relative;width:120px;height:120px;display:grid;place-items:center}
.score__ring{position:absolute;inset:0;transform:rotate(-90deg)}
.score__ring circle{fill:none;stroke-width:7}
.score__track{stroke:var(--ux-line)}
.score__fill{stroke:var(--ux-brand);stroke-linecap:round;filter:drop-shadow(0 0 6px var(--ux-brand));transition:stroke-dashoffset var(--ux-dur-slow) var(--ux-ease-out)}
.score--dial .score__center{display:flex;flex-direction:column;align-items:center}
.score--dial .score__n{font-size:var(--ux-text-h1)}
.score--dial .score__d{font-size:var(--ux-text-caption)}
/* badge */
.score--badge{display:inline-flex;align-items:baseline;gap:3px;padding:6px 12px;border:1px solid var(--ux-line-strong);border-radius:var(--ux-radius-pill);background:var(--ux-surface)}
.score--badge .score__n{font-size:var(--ux-text-body)}
.score--badge .score__d{font-size:var(--ux-text-caption)}
/* inline */
.score--inline{display:inline-flex;align-items:baseline;gap:4px}
.score--inline .score__n{font-size:var(--ux-text-body)}
.score--inline .score__d{font-size:var(--ux-text-small)}


/* ── Section ── */

.section{margin:var(--ux-space-6) 0}
.kicker{font:var(--ux-weight-semibold) var(--ux-text-caption)/1 var(--ux-font-mono);letter-spacing:var(--ux-track-kicker);text-transform:uppercase;color:var(--ux-brand);margin:0 0 12px}
.section__title{font-size:var(--ux-text-h2);line-height:var(--ux-leading-tight);letter-spacing:var(--ux-track-snug);font-weight:var(--ux-weight-heavy);color:var(--ux-ink);margin:0 0 4px}
.section__blurb{color:var(--ux-ink-muted);font-size:var(--ux-text-small);margin:0 0 18px;line-height:var(--ux-leading-snug)}


/* ── Steps ── */

.steps{display:grid;gap:var(--ux-space-3)}
.steps--marketing{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}
.step{display:flex;gap:var(--ux-space-3);align-items:flex-start;padding:var(--ux-space-4);border:1px solid var(--ux-line);border-radius:var(--ux-radius-md);background:var(--ux-surface)}
.step__n{font:var(--ux-weight-heavy) var(--ux-text-h3)/1 var(--ux-font-mono);color:var(--ux-brand-ink);flex:none}
.step__title{font-weight:var(--ux-weight-bold);color:var(--ux-ink);font-size:var(--ux-text-body)}
.step__text{color:var(--ux-ink-muted);font-size:var(--ux-text-small);margin-top:4px;line-height:var(--ux-leading-snug)}
.step__bar{align-self:center;margin-left:auto;width:64px;height:5px;border-radius:var(--ux-radius-pill);background:var(--ux-raised);overflow:hidden;flex:none}
.step__bar i{display:block;height:100%;background:var(--ux-grad)}
.steps--funnel{grid-template-columns:1fr}
.steps--funnel .step{border-left:3px solid var(--ux-brand-tint)}


/* ── Table ── */

.table{width:100%;border-collapse:collapse;font-size:var(--ux-text-small)}
.table th,.table td{text-align:left;padding:var(--ux-space-2) var(--ux-space-2);border-bottom:1px solid var(--ux-line)}
.table th{font:var(--ux-weight-semibold) var(--ux-text-micro)/1 var(--ux-font-mono);letter-spacing:var(--ux-track-caps);text-transform:uppercase;color:var(--ux-ink-muted)}
.table td{color:var(--ux-ink-muted)}
.table .td--lead{font-weight:var(--ux-weight-bold);color:var(--ux-ink);font-variant-numeric:tabular-nums}
.table--comparison td{text-align:center}
.table--comparison td:first-child{text-align:left;color:var(--ux-ink)}
.table--comparison .col--us{color:var(--ux-brand-ink);font-weight:var(--ux-weight-semibold)}

