/* oqrely styles. Every value is a token from the generated block below (source: scripts/brand/tokens.mjs).
   One stylesheet set for the site and the app. Sections: fonts, base, layout, header and nav, buttons,
   cards and plan tiles, proof frame, tables, FAQ, breadcrumbs, steps, closing band, badges, meter,
   forms, alerts, tabs, toast, empty state, loading mark, footer, prose, utilities, motion. */

/* tokens:start */
/* Generated by scripts/brand/build.mjs from scripts/brand/tokens.mjs. Do not edit by hand. */
/* Light is the default; dark follows the system unless the visitor chose light, or applies when chosen. */
:root {
  --unit: 0.8px;
  --space-1: 4px;
  --space-2: 6px;
  --space-3: 10px;
  --space-4: 12px;
  --space-5: 16px;
  --space-6: 20px;
  --space-7: 26px;
  --space-8: 32px;
  --space-9: 38px;
  --space-10: 52px;
  --space-11: 64px;
  --space-12: 76px;
  --space-section: clamp(38px, 3px + 5.6vw, 76px);
  --radius-xs: 4px;
  --radius-s: 6px;
  --radius-m: 10px;
  --radius-l: 16px;
  --radius-pill: 999px;
  --step--2: clamp(0.7188rem, 0.7065rem + 0.0543vw, 0.75rem);
  --step--1: clamp(0.8125rem, 0.8003rem + 0.0543vw, 0.8438rem);
  --step-0: clamp(0.9375rem, 0.913rem + 0.1087vw, 1rem);
  --step-1: clamp(1.0313rem, 0.9946rem + 0.163vw, 1.125rem);
  --step-2: clamp(1.1563rem, 1.0829rem + 0.3261vw, 1.3438rem);
  --step-3: clamp(1.3125rem, 1.1658rem + 0.6522vw, 1.6875rem);
  --step-4: clamp(1.5rem, 1.2432rem + 1.1413vw, 2.1563rem);
  --step-5: clamp(1.7188rem, 1.2174rem + 2.2283vw, 3rem);
  --font-display: "Bricolage Grotesque", "Atkinson Hyperlegible Next", ui-sans-serif, system-ui, sans-serif;
  --font-text: "Atkinson Hyperlegible Next", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "Atkinson Hyperlegible Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --leading-tight: 1.08;
  --leading-snug: 1.3;
  --leading-body: 1.6;
  --measure: 66ch;
  --max-width: 1120px;
  --gutter: clamp(16px, 4px + 3.2vw, 32px);
  --bar-height: 56px;
  --tap-min: 40px;
  --tap-large: 46px;
  --target-min: 24px;
  --focus-width: 3px;
  --focus-offset: 2px;
  --ease-out: cubic-bezier(0.2, 0.7, 0.2, 1);
  --duration-fast: 140ms;
  --duration-theme: 220ms;
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-press: 100ms;
  --dur-hover: 140ms;
  --dur-swap: 160ms;
  --dur-stamp: 180ms;
  --dur-sheet: 240ms;
  --dur-sweep: 420ms;
  --dur-calm: 120ms;
  --bg: #F4FAF5;
  --surface: #FFFFFF;
  --surface-sunken: #EAF5EC;
  --surface-raised: #FFFFFF;
  --line: #DCE8DF;
  --line-strong: #C2D4C6;
  --line-input: #74857A;
  --text: #0E1A12;
  --text-muted: #4F6256;
  --text-inverse: #F4FAF5;
  --brand: #0C9D54;
  --brand-fill: #2FBF78;
  --brand-hover: #29A86A;
  --on-brand: #06140B;
  --brand-tint: #E0FFF0;
  --brand-tint-text: #066B38;
  --neon: #2FBF78;
  --neon-ink: #06140B;
  --neon-glow: rgba(47, 191, 120, 0.5);
  --neon-tint: #E0FFF0;
  --paper-ink: #0B1A10;
  --link: #0E1A12;
  --link-hover: #0E1A12;
  --link-line: #2FBF78;
  --focus: #098B4A;
  --selection: #CCFFE6;
  --code-bg: #EAF5EC;
  --code-text: #0E1A12;
  --danger-solid: #B3261E;
  --on-danger: #FFFFFF;
  --toast-bg: #0E1A12;
  --toast-text: #F4FAF5;
  --overlay: rgba(14, 26, 18, 0.48);
  --fixed-white: #FFFFFF;
  --hue-wheel: conic-gradient(from 90deg, #D03A2B, #C77700, #4C9A22, #0D4F57, #1F3F99, #5B2149, #D03A2B);
  --proof-mark: #9AA59F;
  --tile-rest: 0 0 0 1px rgba(20, 32, 26, 0.06), 0 1px 2px rgba(20, 32, 26, 0.04);
  --tile-lift: 0 0 0 2px rgba(47, 191, 120, 0.9), 0 8px 18px -8px rgba(20, 32, 26, 0.24), 0 2px 4px rgba(20, 32, 26, 0.04);
  --sheet-shadow: 0 1px 2px rgba(20, 32, 26, 0.04), 0 24px 56px -30px rgba(20, 32, 26, 0.28);
  --paper-shadow: 0 1px 1px rgba(20, 32, 26, 0.06), 0 12px 26px -14px rgba(20, 32, 26, 0.3);
  --paper-lift: 0 2px 3px rgba(20, 32, 26, 0.06), 0 30px 48px -20px rgba(20, 32, 26, 0.5);
  --device-bezel: #1C2622;
  --device-shadow: 0 2px 4px rgba(20, 32, 26, 0.12), 0 30px 60px -28px rgba(20, 32, 26, 0.55);
  --status-active-bg: #E6F2D9;
  --status-active-text: #2D6A12;
  --status-active-dot: #4C9A22;
  --status-trial-bg: #FCEFD3;
  --status-trial-text: #8A4B00;
  --status-trial-dot: #C77700;
  --status-neutral-bg: #E9ECEA;
  --status-neutral-text: #4A5550;
  --status-neutral-dot: #7D8984;
  --status-danger-bg: #FBE5E1;
  --status-danger-text: #A1271C;
  --status-danger-dot: #D03A2B;
  --meter-track: #EFF3F0;
  --meter-ok: #098B4A;
  --meter-warn: #B86E00;
  --meter-full: #B3261E;
  --shadow-1: 0 1px 2px rgba(20, 32, 26, 0.05);
  --shadow-2: 0 4px 14px rgba(20, 32, 26, 0.06), 0 1px 3px rgba(20, 32, 26, 0.04);
  --shadow-3: 0 16px 40px rgba(20, 32, 26, 0.1), 0 4px 10px rgba(20, 32, 26, 0.04);
  --button-rest: 0 1px 2px rgba(4, 23, 13, 0.1), 0 2px 6px -3px rgba(12, 157, 84, 0.45);
  --button-lift: 0 2px 4px rgba(4, 23, 13, 0.08), 0 10px 24px -6px rgba(47, 191, 120, 0.75);
  --button-quiet-lift: 0 1px 2px rgba(20, 32, 26, 0.05), 0 8px 16px -10px rgba(20, 32, 26, 0.3);
  --island-bg: #2FBF78;
  --island-text: #06140B;
  --island-muted: #0C4629;
  --island-button-bg: #06140B;
  --island-button-text: #2FBF78;
  --island-line: #2BBF75;
  --theme-color: #F4FAF5;
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #070D09;
    --surface: #0E1611;
    --surface-sunken: #040805;
    --surface-raised: #141F18;
    --line: #1F2D24;
    --line-strong: #2F4236;
    --line-input: #5F7367;
    --text: #E8F3EB;
    --text-muted: #9DB2A4;
    --text-inverse: #070D09;
    --brand: #2FBF78;
    --brand-fill: #2FBF78;
    --brand-hover: #85FFC2;
    --on-brand: #06140B;
    --brand-tint: #0F3321;
    --brand-tint-text: #99FFCC;
    --neon: #2FBF78;
    --neon-ink: #06140B;
    --neon-glow: rgba(47, 191, 120, 0.45);
    --neon-tint: #0F3321;
    --paper-ink: #0B1A10;
    --link: #71F4B3;
    --link-hover: #99FFCC;
    --link-line: #71F4B3;
    --focus: #71F4B3;
    --selection: #195C3B;
    --code-bg: #141F18;
    --code-text: #E8F3EB;
    --danger-solid: #FF8A7A;
    --on-danger: #1A0907;
    --toast-bg: #E8F3EB;
    --toast-text: #070D09;
    --overlay: rgba(0, 0, 0, 0.6);
    --fixed-white: #FFFFFF;
    --hue-wheel: conic-gradient(from 90deg, #D03A2B, #C77700, #4C9A22, #0D4F57, #1F3F99, #5B2149, #D03A2B);
    --proof-mark: #5D6B64;
    --tile-rest: 0 0 0 1px rgba(255, 255, 255, 0.06), 0 1px 2px rgba(0, 0, 0, 0.5);
    --tile-lift: 0 0 0 2px rgba(47, 191, 120, 0.85), 0 10px 22px -8px rgba(0, 0, 0, 0.75);
    --sheet-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 30px 70px -26px rgba(0, 0, 0, 0.8);
    --paper-shadow: 0 1px 1px rgba(0, 0, 0, 0.5), 0 14px 28px -12px rgba(0, 0, 0, 0.75);
    --paper-lift: 0 2px 3px rgba(0, 0, 0, 0.5), 0 32px 52px -18px rgba(0, 0, 0, 0.9);
    --device-bezel: #2C3833;
    --device-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06), 0 30px 60px -24px rgba(0, 0, 0, 0.85);
    --status-active-bg: #1E2C16;
    --status-active-text: #A8DC86;
    --status-active-dot: #7CC254;
    --status-trial-bg: #33270F;
    --status-trial-text: #F3C470;
    --status-trial-dot: #E3A13A;
    --status-neutral-bg: #242C28;
    --status-neutral-text: #BAC4BF;
    --status-neutral-dot: #8C9993;
    --status-danger-bg: #3A1C18;
    --status-danger-text: #FF9D8F;
    --status-danger-dot: #F0675A;
    --meter-track: #1A2520;
    --meter-ok: #2FBF78;
    --meter-warn: #E3A13A;
    --meter-full: #F0675A;
    --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-2: 0 4px 12px rgba(0, 0, 0, 0.45), 0 1px 3px rgba(0, 0, 0, 0.3);
    --shadow-3: 0 16px 40px rgba(0, 0, 0, 0.55), 0 4px 10px rgba(0, 0, 0, 0.3);
    --button-rest: 0 1px 2px rgba(0, 0, 0, 0.45), 0 2px 8px -3px rgba(47, 191, 120, 0.3);
    --button-lift: 0 2px 4px rgba(0, 0, 0, 0.45), 0 10px 26px -6px rgba(47, 191, 120, 0.6);
    --button-quiet-lift: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 18px -10px rgba(0, 0, 0, 0.8);
    --island-bg: #2FBF78;
    --island-text: #06140B;
    --island-muted: #0C4629;
    --island-button-bg: #06140B;
    --island-button-text: #2FBF78;
    --island-line: #2BBF75;
    --theme-color: #070D09;
    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --bg: #070D09;
  --surface: #0E1611;
  --surface-sunken: #040805;
  --surface-raised: #141F18;
  --line: #1F2D24;
  --line-strong: #2F4236;
  --line-input: #5F7367;
  --text: #E8F3EB;
  --text-muted: #9DB2A4;
  --text-inverse: #070D09;
  --brand: #2FBF78;
  --brand-fill: #2FBF78;
  --brand-hover: #85FFC2;
  --on-brand: #06140B;
  --brand-tint: #0F3321;
  --brand-tint-text: #99FFCC;
  --neon: #2FBF78;
  --neon-ink: #06140B;
  --neon-glow: rgba(47, 191, 120, 0.45);
  --neon-tint: #0F3321;
  --paper-ink: #0B1A10;
  --link: #71F4B3;
  --link-hover: #99FFCC;
  --link-line: #71F4B3;
  --focus: #71F4B3;
  --selection: #195C3B;
  --code-bg: #141F18;
  --code-text: #E8F3EB;
  --danger-solid: #FF8A7A;
  --on-danger: #1A0907;
  --toast-bg: #E8F3EB;
  --toast-text: #070D09;
  --overlay: rgba(0, 0, 0, 0.6);
  --fixed-white: #FFFFFF;
  --hue-wheel: conic-gradient(from 90deg, #D03A2B, #C77700, #4C9A22, #0D4F57, #1F3F99, #5B2149, #D03A2B);
  --proof-mark: #5D6B64;
  --tile-rest: 0 0 0 1px rgba(255, 255, 255, 0.06), 0 1px 2px rgba(0, 0, 0, 0.5);
  --tile-lift: 0 0 0 2px rgba(47, 191, 120, 0.85), 0 10px 22px -8px rgba(0, 0, 0, 0.75);
  --sheet-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 30px 70px -26px rgba(0, 0, 0, 0.8);
  --paper-shadow: 0 1px 1px rgba(0, 0, 0, 0.5), 0 14px 28px -12px rgba(0, 0, 0, 0.75);
  --paper-lift: 0 2px 3px rgba(0, 0, 0, 0.5), 0 32px 52px -18px rgba(0, 0, 0, 0.9);
  --device-bezel: #2C3833;
  --device-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06), 0 30px 60px -24px rgba(0, 0, 0, 0.85);
  --status-active-bg: #1E2C16;
  --status-active-text: #A8DC86;
  --status-active-dot: #7CC254;
  --status-trial-bg: #33270F;
  --status-trial-text: #F3C470;
  --status-trial-dot: #E3A13A;
  --status-neutral-bg: #242C28;
  --status-neutral-text: #BAC4BF;
  --status-neutral-dot: #8C9993;
  --status-danger-bg: #3A1C18;
  --status-danger-text: #FF9D8F;
  --status-danger-dot: #F0675A;
  --meter-track: #1A2520;
  --meter-ok: #2FBF78;
  --meter-warn: #E3A13A;
  --meter-full: #F0675A;
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-2: 0 4px 12px rgba(0, 0, 0, 0.45), 0 1px 3px rgba(0, 0, 0, 0.3);
  --shadow-3: 0 16px 40px rgba(0, 0, 0, 0.55), 0 4px 10px rgba(0, 0, 0, 0.3);
  --button-rest: 0 1px 2px rgba(0, 0, 0, 0.45), 0 2px 8px -3px rgba(47, 191, 120, 0.3);
  --button-lift: 0 2px 4px rgba(0, 0, 0, 0.45), 0 10px 26px -6px rgba(47, 191, 120, 0.6);
  --button-quiet-lift: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 18px -10px rgba(0, 0, 0, 0.8);
  --island-bg: #2FBF78;
  --island-text: #06140B;
  --island-muted: #0C4629;
  --island-button-bg: #06140B;
  --island-button-text: #2FBF78;
  --island-line: #2BBF75;
  --theme-color: #070D09;
  color-scheme: dark;
}

/* Touch keeps pointer targets at 44px or more (spec 18 UX-040). */
@media (pointer: coarse) {
  :root {
    --tap-min: 44px;
    --tap-large: 50px;
  }
}
/* tokens:end */

/* ---------- fonts (self-hosted, OFL; licences in /fonts) ---------- */
@font-face {
  font-family: "Atkinson Hyperlegible Next";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("/fonts/atkinson-hyperlegible-next-latin-wght.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Atkinson Hyperlegible Next";
  font-style: italic;
  font-weight: 200 800;
  font-display: swap;
  src: url("/fonts/atkinson-hyperlegible-next-latin-wght-italic.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("/fonts/bricolage-grotesque-latin-opsz.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Atkinson Hyperlegible Mono";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("/fonts/atkinson-hyperlegible-mono-latin-wght.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-padding-top: var(--space-6); }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-text);
  font-size: var(--step-0);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
}
::selection { background: var(--selection); color: var(--text); }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  color: var(--text);
  text-wrap: balance;
  margin: 0 0 var(--space-4);
}
h1 { font-size: var(--step-5); line-height: var(--leading-tight); font-weight: 750; letter-spacing: -0.025em; }
h2 { font-size: var(--step-3); line-height: 1.15; font-weight: 700; letter-spacing: -0.015em; }
h3 { font-size: var(--step-1); line-height: var(--leading-snug); font-weight: 650; letter-spacing: -0.005em; }
h4 { font-size: var(--step-0); line-height: var(--leading-snug); font-weight: 650; }
p, ul, ol, dl { margin: 0 0 var(--space-4); }
p { text-wrap: pretty; }
a { color: var(--link); text-decoration-color: var(--link-line); text-decoration-thickness: 2px; text-underline-offset: 0.18em; }
a:hover { color: var(--link-hover); text-decoration-thickness: 3px; }
img, svg { max-width: 100%; }
img { height: auto; }
hr { border: 0; border-top: 1px solid var(--line); margin: var(--space-8) 0; }
code, kbd, samp, .mono {
  font-family: var(--font-mono);
  font-size: 0.92em;
  font-variant-ligatures: none;
}
code { background: var(--code-bg); color: var(--code-text); padding: 0.1em 0.35em; border-radius: var(--radius-xs); overflow-wrap: anywhere; }
pre { background: var(--code-bg); color: var(--code-text); padding: var(--space-4); border-radius: var(--radius-s); overflow-x: auto; }
pre code { background: none; padding: 0; }

:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
:focus:not(:focus-visible) { outline: none; }

/* ---------- layout ---------- */
.wrap { width: 100%; max-width: calc(var(--max-width) + 2 * var(--gutter)); margin-inline: auto; padding-inline: var(--gutter); }
main { display: block; padding-top: var(--space-9); padding-bottom: var(--space-section); min-height: 60vh; }
.section { margin-top: var(--space-section); }
.section-head { max-width: var(--measure); margin-bottom: var(--space-7); }
.section-head p { color: var(--text-muted); }
.lead { font-size: var(--step-1); line-height: 1.5; color: var(--text-muted); max-width: 40ch; }
.measure, .prose { max-width: var(--measure); }
.narrow { max-width: calc(460 * var(--unit)); margin-inline: auto; }
/* Sign-up (views/auth/signup.ejs): wide screens balance the form with a real code and what the account adds. */
.auth-split { display: grid; gap: var(--space-8); justify-content: center; align-items: center; }
.auth-split > .card.narrow { width: 100%; margin: 0; }
.auth-split [data-signup="form"] + .oauth, .auth-split [data-signup="form"] ~ p.muted:not(.small) { margin-top: var(--space-5); }
.auth-aside { display: none; }
@media (width >= 900px) {
  .auth-split { grid-template-columns: minmax(0, calc(460 * var(--unit))) minmax(0, calc(400 * var(--unit))); gap: var(--space-10); padding-block: var(--space-4); }
  .auth-aside { display: grid; gap: var(--space-4); align-content: center; }
  .auth-proof { width: calc(260 * var(--unit)); padding: var(--space-5); border-radius: var(--radius-l); background: var(--island-bg); box-shadow: var(--shadow-2); transform: rotate(-2deg); margin-bottom: var(--space-3); }
  .auth-proof .auth-code { display: block; width: 100%; height: auto; border-radius: var(--radius-xs); background: var(--fixed-white); box-shadow: var(--shadow-1); }
  .auth-aside h2 { font-size: var(--step-2); margin: 0; }
  .auth-gets { display: grid; gap: var(--space-3); margin: 0; padding: 0; list-style: none; }
  .auth-gets li { display: flex; gap: var(--space-3); align-items: flex-start; font-weight: 600; }
  .auth-gets svg { flex: none; width: calc(22 * var(--unit)); height: calc(22 * var(--unit)); margin-top: 2px; padding: 3px; border-radius: 50%; background: var(--brand-tint); stroke: var(--brand-tint-text); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; fill: none; }
  .auth-aside > p { margin: 0; }
}
.narrow h1, .card h1 { font-size: var(--step-4); }
.stack, form.stack { display: grid; gap: var(--space-4); }
.actions { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
.grid { display: grid; gap: var(--space-5); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(260 * var(--unit))), 1fr)); margin: var(--space-6) 0; }
.split { display: grid; gap: var(--space-9); align-items: center; }
@media (width >= 900px) { .split { grid-template-columns: 1.1fr 0.9fr; gap: var(--space-10); } }

.hero { padding-block: var(--space-6) var(--space-8); }
.hero h1 { max-width: 13ch; }
.hero .lead { margin-bottom: var(--space-7); }

/* ---------- skip link ---------- */
.skip {
  position: absolute;
  left: var(--space-4);
  top: var(--space-2);
  z-index: 100;
  padding: var(--space-3) var(--space-4);
  background: var(--surface);
  color: var(--text);
  border: 2px solid var(--focus);
  border-radius: var(--radius-s);
  font-weight: 650;
  transform: translateY(-200%);
}
.skip:focus, .skip:focus-visible { transform: none; }

/* ---------- header and nav ---------- */
.site-header { border-bottom: 1px solid var(--line); background: var(--bg); position: relative; z-index: 20; }
.bar { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); min-height: var(--bar-height); }
.brand { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--text); text-decoration: none; min-height: var(--tap-min); }
.brand:hover { color: var(--text); }
.logo-mark { width: auto; height: calc(26 * var(--unit)); color: var(--brand); flex: none; }
.logo-word { font-family: var(--font-display); font-weight: 750; font-size: 1.5rem; letter-spacing: -0.035em; line-height: 1; padding-bottom: 0.08em; }

.nav { display: flex; align-items: center; gap: var(--space-2); }
.nav .nav-toggle { display: none; }
.nav-panel { display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; }
.nav-links { display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; list-style: none; margin: 0; padding: 0; }
.nav-links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  padding-inline: var(--space-3);
  color: var(--text);
  text-decoration: none;
  border-radius: var(--radius-s);
  font-weight: 550;
}
.nav-links a:hover { background: var(--surface-sunken); color: var(--text); }
.nav-links a[aria-current="page"] { text-decoration: underline; text-decoration-color: var(--brand); text-decoration-thickness: 2px; text-underline-offset: 0.45em; }
.nav-actions { display: flex; align-items: center; gap: var(--space-2); margin-left: var(--space-2); }

/* WEB-032 mega-menu under "QR code types": 12 types, 6 use cases, the free tools. Opens on hover, focus or the toggle. */
.mega { position: relative; display: flex; align-items: center; }
.mega-toggle { display: inline-grid; place-items: center; width: var(--tap-min); min-height: var(--tap-min); margin-left: calc(-1 * var(--space-2)); padding: 0; border: 0; border-radius: var(--radius-s); background: none; color: var(--text-muted, var(--text)); cursor: pointer; }
.mega-toggle:hover { background: var(--surface-sunken); }
.mega-toggle svg { width: calc(16 * var(--unit)); height: calc(16 * var(--unit)); transition: transform 0.15s ease; }
.mega-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
.mega-panel {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 40;
  width: max-content;
  max-width: calc(100vw - 2 * var(--gutter, var(--space-4)));
  grid-template-columns: repeat(3, minmax(calc(170 * var(--unit)), auto));
  gap: var(--space-5);
  padding: var(--space-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-2);
}
.mega:hover .mega-panel, .mega:focus-within .mega-panel, .mega .mega-panel[data-open] { display: grid; }
.mega-title { margin: 0 0 var(--space-2); font-size: var(--step--1); font-weight: 650; color: var(--text-muted, var(--text)); text-transform: uppercase; letter-spacing: 0.04em; }
.mega-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.mega-group[data-mega-group="types"] .mega-list { grid-template-columns: repeat(2, minmax(0, auto)); column-gap: var(--space-3); }
.nav-links .mega-list a, .nav-links .mega-all { min-height: calc(34 * var(--unit)); padding-inline: var(--space-2); font-weight: 500; white-space: nowrap; }
.nav-links .mega-all { display: inline-flex; margin-top: var(--space-2); color: var(--brand); font-weight: 600; }

.icon-button {
  display: inline-grid;
  place-items: center;
  width: var(--tap-min);
  height: var(--tap-min);
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  flex: none;
}
.icon-button:hover { background: var(--surface-sunken); }
.icon-button svg { width: calc(20 * var(--unit)); height: calc(20 * var(--unit)); }

.theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }
:root:not(.js) .theme-toggle { display: none; }

@media (width < 760px) {
  .js .nav .nav-toggle { display: inline-grid; order: 2; }
  .js .nav .theme-toggle { order: 1; }
  .js .nav-panel {
    display: none;
    position: fixed;
    inset: var(--bar-height) 0 0 0;
    z-index: 30;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-6);
    padding: var(--space-6) var(--gutter) var(--space-9);
    background: var(--bg);
    border-top: 1px solid var(--line);
    overflow-y: auto;
  }
  .js .nav-panel[data-open] { display: flex; }
  .js .nav-links { flex-direction: column; align-items: stretch; gap: 0; }
  .js .nav-links a { display: flex; min-height: var(--tap-large); font-size: var(--step-1); border-bottom: 1px solid var(--line); border-radius: 0; padding-inline: 0; }
  .js .mega { flex-wrap: wrap; justify-content: space-between; }
  .js .mega > a { flex: 1 1 auto; }
  .js .mega-toggle { width: var(--tap-large); min-height: var(--tap-large); border-bottom: 1px solid var(--line); border-radius: 0; }
  .js .mega:hover .mega-panel, .js .mega:focus-within .mega-panel { display: none; }
  .js .mega .mega-panel[data-open] { display: grid; }
  .js .mega-panel { position: static; width: 100%; max-width: none; grid-template-columns: 1fr; padding: var(--space-3) 0; border: 0; box-shadow: none; background: none; }
  .js .nav-links .mega-list a, .js .nav-links .mega-all { font-size: var(--step-0); min-height: var(--tap-min); border-bottom: 0; }
  .js .nav-actions { margin: 0; flex-wrap: wrap; }
  .js .nav-actions .button { flex: 1 1 auto; }
  .js body.nav-open { overflow: hidden; }
}

/* ---------- buttons ---------- */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--tap-min);
  padding: var(--space-2) var(--space-5);
  border: 1px solid var(--neon);
  border-radius: var(--radius-m);
  background: var(--neon);
  color: var(--neon-ink);
  font: inherit;
  font-weight: 650;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  box-shadow: var(--button-rest);
  transition: background-color var(--dur-hover) var(--ease-out), border-color var(--dur-hover) var(--ease-out), box-shadow var(--dur-hover) var(--ease-out), transform var(--dur-hover) var(--ease-out);
}
.button:hover { background: var(--neon); border-color: var(--neon); color: var(--neon-ink); text-decoration: none; box-shadow: var(--button-lift); }
@media (prefers-reduced-motion: no-preference) { .button:hover { transform: translateY(-1px); } .button:active { transform: none; } }
.button:active { box-shadow: var(--button-rest); }
/* Secondary: a quiet surface button with ink text; it lifts like the primary but carries no fill. */
.button.ghost { background: var(--surface); color: var(--text); border-color: var(--line-strong); box-shadow: none; }
.button.ghost:hover { background: var(--brand-tint); color: var(--brand-tint-text); border-color: var(--brand); box-shadow: var(--button-quiet-lift); transform: none; }
.button.large { min-height: var(--tap-large); padding-inline: var(--space-7); font-size: var(--step-1); }
.button.small { padding-inline: var(--space-4); font-size: var(--step--1); }
.button.danger { background: var(--danger-solid); border-color: var(--danger-solid); color: var(--on-danger); }
.button.danger:hover { background: var(--danger-solid); border-color: var(--text); }
.button.block { width: 100%; }
.button[disabled], .button[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; box-shadow: none; }

/* Clickable affordances (spec 18 UX-042). Everything you can press shows it: a pointer cursor, a hover
   state, a press state and the focus ring above. Colour and shadow change at every motion setting; the
   lift and the press (transform) only move with prefers-reduced-motion: no-preference, and the global
   reduced-motion rule below turns the transitions off. Selected states stay with each component. */
.chip, .type-card, .option-card, .seg-option, .rb-chip, .toggle-option, .demo-seg, .demo-change, .studio-shape, .swatch-pick, .gen-surprise, .gen-formats .option, .helper-domain .option, #generator .mode-seg .mode-card {
  cursor: pointer;
  transition: background-color var(--dur-hover) var(--ease-out), border-color var(--dur-hover) var(--ease-out), box-shadow var(--dur-hover) var(--ease-out), transform var(--dur-press) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .chip:hover, .type-card:hover, .option-card:hover, .rb-chip:hover, .toggle-option:hover, .studio-shape:hover, .gen-formats .option:hover, .helper-domain .option:hover { border-color: var(--brand); box-shadow: var(--tile-rest); }
  .chip:not(:has(input:checked)):hover, .option-card:hover, .rb-chip:hover { background: var(--brand-tint); }
}
@media (prefers-reduced-motion: no-preference) {
  .button:active, .chip:active, .type-card:active, .option-card:active, .rb-chip:active, .toggle-option:active, .demo-seg:active, .demo-change:active, .studio-shape:active, .swatch-pick:active, .gen-surprise:active, .gen-formats .option:active, .helper-domain .option:active { transform: translateY(1px) scale(0.98); }
}
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .button:not([disabled], [aria-disabled="true"]):hover { transform: translateY(-1px); }
  .button:not([disabled], [aria-disabled="true"]):hover:active { transform: translateY(1px) scale(0.98); }
  .type-card:hover, .option-card:hover { transform: translateY(-2px); box-shadow: var(--tile-lift); }
}

/* ---------- cards and plan tiles ---------- */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  padding: var(--space-6);
  margin-bottom: var(--space-4);
}
.card > :last-child { margin-bottom: 0; }
.card h2, .card h3 { margin-bottom: var(--space-2); }
.card-muted { background: var(--surface-sunken); border-color: transparent; }

.plans { display: grid; gap: var(--space-5); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(250 * var(--unit))), 1fr)); align-items: stretch; margin: var(--space-7) 0; }
.plan-tile, .card.plan {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  padding: var(--space-7) var(--space-6) var(--space-6);
  margin: 0;
}
.plan-tile.is-featured { border: 2px solid var(--brand); box-shadow: var(--shadow-2); }
.plan-name { font-family: var(--font-display); font-size: var(--step-2); font-weight: 700; margin: 0; }
.plan-note { margin: 0; color: var(--text-muted); font-size: var(--step--1); }
.price, .plan-price { font-family: var(--font-display); font-size: var(--step-4); font-weight: 750; letter-spacing: -0.02em; line-height: 1; margin: 0; font-variant-numeric: tabular-nums; }
.price span, .plan-price span { font-family: var(--font-text); font-size: var(--step--1); font-weight: 400; color: var(--text-muted); letter-spacing: 0; }
.plan-features, .plan ul { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-2); }
.plan-features { flex: 1; align-content: start; }
.plan-features li, .plan ul li { position: relative; padding-left: var(--space-6); }
.plan-features li::before, .plan ul li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0.42em;
  width: calc(11 * var(--unit));
  height: calc(6 * var(--unit));
  border-left: 2px solid var(--brand);
  border-bottom: 2px solid var(--brand);
  transform: rotate(-45deg);
}
.plan-tile > .button, .plan-tile > form { margin-top: auto; }

/* ---------- proof frame: crop marks around a print area (the signature device) ---------- */
.proof-figure { margin: 0; padding: var(--space-5); }
.proof { position: relative; }
.proof::before {
  content: "";
  position: absolute;
  inset: calc(-1 * var(--space-5));
  pointer-events: none;
  --tick: var(--line-strong);
  background:
    linear-gradient(var(--tick), var(--tick)) left var(--space-5) / calc(12 * var(--unit)) 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) var(--space-5) top / 1px calc(12 * var(--unit)) no-repeat,
    linear-gradient(var(--tick), var(--tick)) right var(--space-5) / calc(12 * var(--unit)) 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) calc(100% - var(--space-5)) top / 1px calc(12 * var(--unit)) no-repeat,
    linear-gradient(var(--tick), var(--tick)) left calc(100% - var(--space-5)) / calc(12 * var(--unit)) 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) var(--space-5) bottom / 1px calc(12 * var(--unit)) no-repeat,
    linear-gradient(var(--tick), var(--tick)) right calc(100% - var(--space-5)) / calc(12 * var(--unit)) 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) calc(100% - var(--space-5)) bottom / 1px calc(12 * var(--unit)) no-repeat;
}
.proof-sheet { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-xs); box-shadow: var(--shadow-3); padding: var(--space-6); }
.proof-sheet > :last-child { margin-bottom: 0; }
.proof-caption { margin: var(--space-7) 0 0; font-size: var(--step--1); color: var(--text-muted); }

.code-row { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--space-2) var(--space-4); align-items: center; padding-block: var(--space-4); border-bottom: 1px solid var(--line); }
.code-row:first-child { padding-top: 0; }
.code-row:last-child { border-bottom: 0; padding-bottom: 0; }
.code-slug { font-family: var(--font-mono); font-weight: 600; color: var(--text); min-width: 0; overflow-wrap: anywhere; }
.code-dest { flex-basis: 100%; margin-top: calc(-1 * var(--space-1)); font-size: var(--step--1); color: var(--text-muted); overflow-wrap: anywhere; margin: 0; }

/* ---------- tables (stack into labelled rows on phones) ---------- */
.table-wrap { margin: var(--space-6) 0; overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; font-size: var(--step--1); font-variant-numeric: tabular-nums; }
.table caption { text-align: left; font-weight: 650; padding-bottom: var(--space-3); color: var(--text); }
.table th, .table td { text-align: left; padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--line); vertical-align: top; }
.table thead th { font-weight: 650; color: var(--text-muted); border-bottom: 2px solid var(--line-strong); }
.table tbody th { font-weight: 600; }
@media (width < 600px) {
  .table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .table, .table tbody, .table tr, .table th, .table td { display: block; width: 100%; }
  .table caption { display: block; }
  .table tr { border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); padding: var(--space-2) var(--space-4); margin-bottom: var(--space-3); }
  .table tbody th { padding: var(--space-2) 0; border-bottom: 1px solid var(--line); font-size: var(--step-0); }
  .table td { display: grid; grid-template-columns: minmax(0, 45%) 1fr; gap: var(--space-3); padding: var(--space-2) 0; border-bottom: 0; }
  .table td::before { content: attr(data-label); color: var(--text-muted); font-weight: 600; }
}
/* Settings > Members: keep the per-row actions compact (each form on one line) and right-aligned. */
.member-actions form { display: inline-flex; flex-wrap: nowrap; align-items: center; gap: var(--space-2); vertical-align: top; }
.member-actions select { width: auto; max-width: calc(180 * var(--unit)); min-height: calc(32 * var(--unit)); }
.member-actions .button.small { min-height: calc(32 * var(--unit)); padding-inline: var(--space-3); }
@media (width >= 600px) {
  .table th.member-actions, .table td.member-actions { text-align: right; }
}

/* A quiet destructive button: danger text and a subtle border, never a filled block. */
.button.ghost.danger { background: var(--surface); color: var(--status-danger-text); border-color: var(--line-strong); box-shadow: none; }
.button.ghost.danger:hover { background: color-mix(in srgb, var(--danger-solid) 12%, var(--surface)); border-color: var(--danger-solid); color: var(--status-danger-text); box-shadow: none; transform: none; }

/* ---------- settings screens in the app shell (shared across every settings page) ---------- */
.app-main.settings h1 { font-size: var(--step-4); }
.app-main.settings h2 { font-size: var(--step-1); line-height: var(--leading-snug); font-weight: 650; letter-spacing: -0.005em; }
.app-main.settings h3 { font-size: var(--step-0); }
/* Short values do not stretch the full card width (owner rule). */
.app-main.settings .field { max-width: calc(420 * var(--unit)); }
.app-main.settings .field.field-sm { max-width: calc(320 * var(--unit)); }
.app-main.settings .field.field-wide { max-width: none; }
.app-main.settings select:not([multiple]) { width: fit-content; max-width: 100%; }
/* Invite-style rows sit on one line at desktop: [field][field][button]. */
.app-main.settings .inline-form { display: flex; flex-wrap: wrap; align-items: end; gap: var(--space-3) var(--space-4); }
.app-main.settings .inline-form > .field { margin: 0; }
.app-main.settings .inline-form > .field:first-child { flex: 1 1 calc(300 * var(--unit)); }
.app-main.settings .inline-form > .field:not(:first-child) { flex: 0 0 auto; }
.app-main.settings .inline-form > .button { align-self: end; }

/* ---------- FAQ ---------- */
.faq { border-top: 1px solid var(--line); max-width: var(--measure); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: var(--tap-large);
  padding-block: var(--space-3);
  cursor: pointer;
  list-style: none;
  font-weight: 650;
  font-size: var(--step-1);
  font-family: var(--font-display);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "";
  flex: none;
  width: calc(14 * var(--unit));
  height: calc(14 * var(--unit));
  background:
    linear-gradient(var(--brand), var(--brand)) center / calc(14 * var(--unit)) 2px no-repeat,
    linear-gradient(var(--brand), var(--brand)) center / 2px calc(14 * var(--unit)) no-repeat;
}
.faq details[open] summary::after { background: linear-gradient(var(--brand), var(--brand)) center / calc(14 * var(--unit)) 2px no-repeat; }
.faq-answer { padding-bottom: var(--space-5); }
.faq-answer > :last-child { margin-bottom: 0; }
/* One questions section (views/site/partials/qa.ejs): the buyer questions as open answer cards, then the FAQ. */
.qa-first { margin-bottom: var(--space-7); }
.qa-kicker { font-family: var(--font-text); font-size: var(--step--1); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--brand-tint-text); margin: 0 0 var(--space-3); }
.qa-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); gap: var(--space-4); margin: 0; }
.qa-card { display: grid; align-content: start; gap: var(--space-2); padding: var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); }
.qa-card dt { font-weight: 700; color: var(--text); }
.qa-card dd { margin: 0; font-size: var(--step--1); color: var(--text-muted); }

/* ---------- breadcrumbs ---------- */
.breadcrumbs, .crumbs { font-size: var(--step--1); color: var(--text-muted); margin-bottom: var(--space-5); }
.breadcrumbs ol { display: flex; flex-wrap: wrap; align-items: center; list-style: none; margin: 0; padding: 0; }
.breadcrumbs li { display: inline-flex; align-items: center; }
.breadcrumbs li + li::before { content: "/"; padding-inline: var(--space-2); color: var(--text-muted); }
.breadcrumbs a { color: var(--text-muted); }
.breadcrumbs a:hover { color: var(--link-hover); }
.breadcrumbs [aria-current="page"] { color: var(--text); font-weight: 600; }

/* ---------- steps ---------- */
.steps { list-style: none; padding: 0; margin: var(--space-7) 0; display: grid; gap: var(--space-7); counter-reset: step; }
@media (width >= 760px) { .steps { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); } }
.steps > li { counter-increment: step; display: grid; gap: var(--space-2); align-content: start; }
.steps > li::before {
  content: counter(step);
  display: grid;
  place-items: center;
  width: calc(40 * var(--unit));
  height: calc(40 * var(--unit));
  margin-bottom: var(--space-2);
  border: 2px solid var(--brand);
  border-radius: var(--radius-xs);
  font-family: var(--font-display);
  font-weight: 750;
  font-size: var(--step-1);
  color: var(--brand-tint-text);
  background: var(--brand-tint);
}
.steps h3 { margin: 0; }
.steps p { margin: 0; color: var(--text-muted); }

/* ---------- closing band (an island: same colours in both themes) ---------- */
.band {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  margin-top: var(--space-section);
  background: var(--island-bg);
  color: var(--island-text);
  border-radius: var(--radius-l);
  padding: clamp(var(--space-7), 6vw, calc(72 * var(--unit))) clamp(var(--space-5), 6vw, calc(72 * var(--unit)));
  display: grid;
  gap: var(--space-6);
}
/* The brand mark, large and cropped on the right: confident and solid, never shy (owner 2026-10-14). It sits
   behind the content (z-index -1), decorative. A mask fades its content side to nothing so the mark stays
   bold where it meets the panel's right edge (clear of text) and dissolves well before it reaches the
   headline or the buttons: the text and the buttons read fully in both themes. */
.band-mark {
  position: absolute;
  z-index: -1;
  right: calc(-44 * var(--unit));
  top: 50%;
  transform: translateY(-50%);
  display: block;
  pointer-events: none;
  color: var(--island-text);
  opacity: 0.16;
  -webkit-mask-image: linear-gradient(to right, transparent 0, var(--island-text) 72%);
  mask-image: linear-gradient(to right, transparent 0, var(--island-text) 72%);
}
.band-mark-svg { display: block; width: auto; height: clamp(calc(170 * var(--unit)), 26vw, calc(300 * var(--unit))); }
/* Keep the content and the buttons painting above the mark (the grid keeps its two children). */
.band > :not(.band-mark) { position: relative; z-index: 1; }
/* While the band is a single stacked column (below the wide grid), the text spans the full width, so fade
   the mark further and push more of it off-canvas. */
@media (width < 900px) { .band-mark { opacity: 0.09; right: calc(-72 * var(--unit)); } }
@media (width >= 900px) { .band { grid-template-columns: 1fr auto; align-items: end; } }
.band h2 { color: var(--island-text); margin-bottom: var(--space-3); max-width: 22ch; }
.band p { color: var(--island-muted); margin: 0; max-width: 52ch; }
.band a:not(.button) { color: var(--island-text); }
.band .button { background: var(--island-button-bg); border-color: var(--island-button-bg); color: var(--island-button-text); }
.band .button:hover { background: var(--island-button-bg); border-color: var(--island-button-bg); color: var(--island-button-text); box-shadow: var(--shadow-3); }
.band .button.ghost { background: transparent; color: var(--island-text); border-color: var(--island-line); }
.band .button.ghost:hover { border-color: var(--island-text); background: transparent; color: var(--island-text); }
.band :focus-visible { outline-color: var(--island-text); }

/* ---------- badges for code states (spec 18 UX-031); the dot shape differs too, not only the colour ---------- */
.badge {
  --dot: var(--status-neutral-dot);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: calc(26 * var(--unit));
  padding: 2px var(--space-3) 2px var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--status-neutral-bg);
  color: var(--status-neutral-text);
  font-size: var(--step--1);
  font-weight: 650;
  line-height: 1.2;
  white-space: nowrap;
}
.badge::before { content: ""; flex: none; width: calc(10 * var(--unit)); height: calc(10 * var(--unit)); border-radius: 50%; border: 2px solid var(--dot); }
.badge-active { --dot: var(--status-active-dot); background: var(--status-active-bg); color: var(--status-active-text); }
.badge-active::before { background: var(--dot); }
.badge-trial { --dot: var(--status-trial-dot); background: var(--status-trial-bg); color: var(--status-trial-text); }
.badge-trial::before { background: linear-gradient(90deg, var(--dot) 50%, transparent 50%); }
.badge-danger { --dot: var(--status-danger-dot); background: var(--status-danger-bg); color: var(--status-danger-text); }
.badge-danger::before { border-radius: 2px; background: var(--dot); }
.badge-list { display: flex; flex-wrap: wrap; gap: var(--space-2); list-style: none; padding: 0; margin: 0 0 var(--space-4); }

/* ---------- meter (quota use; the colour follows the low and high thresholds) ---------- */
.meter-field { display: grid; gap: var(--space-2); max-width: calc(420 * var(--unit)); margin-bottom: var(--space-5); }
.meter-label { display: flex; justify-content: space-between; gap: var(--space-3); font-size: var(--step--1); font-weight: 600; }
.meter-label span:last-child { color: var(--text-muted); font-weight: 400; font-variant-numeric: tabular-nums; }
meter.meter { -webkit-appearance: none; appearance: none; display: block; width: 100%; height: calc(10 * var(--unit)); border: 0; border-radius: var(--radius-pill); background: var(--meter-track); overflow: hidden; }
meter.meter::-webkit-meter-bar { background: var(--meter-track); border: 0; border-radius: var(--radius-pill); height: calc(10 * var(--unit)); }
meter.meter::-webkit-meter-optimum-value { background: var(--meter-ok); border-radius: var(--radius-pill); }
meter.meter::-webkit-meter-suboptimum-value { background: var(--meter-warn); border-radius: var(--radius-pill); }
meter.meter::-webkit-meter-even-less-good-value { background: var(--meter-full); border-radius: var(--radius-pill); }
meter.meter::-moz-meter-bar { background: var(--meter-ok); border-radius: var(--radius-pill); }
meter.meter:-moz-meter-sub-optimum::-moz-meter-bar { background: var(--meter-warn); }
meter.meter:-moz-meter-sub-sub-optimum::-moz-meter-bar { background: var(--meter-full); }

/* ---------- forms ---------- */
label { display: grid; gap: var(--space-1); font-weight: 600; }
label.check, label.option { display: flex; gap: var(--space-3); align-items: flex-start; font-weight: 400; }
label.check input, label.option input { margin-top: 0.3em; }
.field { display: grid; gap: var(--space-2); }
/* Add-a-domain: a value like go.yourbrand.com needs about 420px, with the button inline beside it on desktop. */
.domains-add-row { display: grid; gap: var(--space-3); }
@media (width >= 600px) {
  .domains-add-row { grid-template-columns: minmax(0, calc(520 * var(--unit))) auto; align-items: end; }
  .domains-add-row .actions { margin: 0; }
}
.field-hint, .hint { color: var(--text-muted); font-size: var(--step--1); margin: 0; }
.field-error { display: flex; gap: var(--space-2); align-items: baseline; color: var(--status-danger-text); font-size: var(--step--1); font-weight: 600; margin: 0; }
.field-error::before { content: ""; flex: none; width: calc(8 * var(--unit)); height: calc(8 * var(--unit)); border-radius: 2px; background: var(--status-danger-dot); }
input:where([type="email"], [type="password"], [type="text"], [type="search"], [type="url"], [type="tel"], [type="number"], [type="date"]),
input:not([type]),
select,
textarea {
  width: 100%;
  min-height: var(--tap-min);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--line-input);
  border-radius: var(--radius-s);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-weight: 400;
}
textarea { min-height: calc(120 * var(--unit)); resize: vertical; }
input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] { border: 2px solid var(--danger-solid); }
input:focus-visible, select:focus-visible, textarea:focus-visible { outline-offset: 1px; }
input[type="checkbox"], input[type="radio"] { accent-color: var(--brand); width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); flex: none; }
.input-mono { font-family: var(--font-mono); }
/* URL fields read in the UI font, not monospace: a long link shows more of itself and never looks clipped
   in the narrow field (owner pass 2: the editor's Destination). */
.input-url { font-family: var(--font-text); width: 100%; }
fieldset { border: 1px solid var(--line); border-radius: var(--radius-s); padding: var(--space-4); margin: 0; display: grid; gap: var(--space-2); }
legend { font-weight: 650; padding-inline: var(--space-1); }

/* ---------- alerts and banners (.error and .notice are the skeleton's message lines) ---------- */
.alert, .error, .notice {
  --dot: var(--brand);
  display: block;
  padding: var(--space-3) var(--space-4) var(--space-3) var(--space-5);
  border-radius: var(--radius-s);
  border-left: calc(4 * var(--unit)) solid var(--dot);
  background: var(--brand-tint);
  color: var(--text);
  margin: 0 0 var(--space-4);
}
.alert > :last-child { margin-bottom: 0; }
.alert-title { display: block; font-weight: 700; margin-bottom: var(--space-1); }
.alert-success, .notice { --dot: var(--status-active-dot); background: var(--status-active-bg); }
.alert-warning { --dot: var(--status-trial-dot); background: var(--status-trial-bg); }
.alert-danger, .error { --dot: var(--status-danger-dot); background: var(--status-danger-bg); }
.banner { border-radius: 0; border-left: 0; border-bottom: 1px solid var(--line); margin: 0; padding-inline: 0; }
.banner .wrap { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: center; justify-content: space-between; }

/* ---------- tabs ---------- */
.tabs [role="tablist"] { display: flex; gap: var(--space-1); border-bottom: 1px solid var(--line); overflow-x: auto; scrollbar-width: none; }
.tabs [role="tab"] {
  min-height: var(--tap-min);
  padding: 0 var(--space-4);
  border: 0;
  border-bottom: 3px solid transparent;
  background: none;
  color: var(--text-muted);
  font: inherit;
  font-weight: 650;
  cursor: pointer;
  white-space: nowrap;
}
.tabs [role="tab"]:hover { color: var(--text); }
.tabs [role="tab"][aria-selected="true"] { color: var(--text); border-bottom-color: var(--brand); }
.tabs [role="tab"]:focus-visible { outline-offset: -3px; }
.tabs [role="tabpanel"] { padding-top: var(--space-5); }
.tabs [role="tabpanel"][hidden] { display: none; }

/* ---------- toast ---------- */
.toast-region { position: fixed; z-index: 50; left: 50%; bottom: var(--space-6); transform: translateX(-50%); display: grid; gap: var(--space-2); width: min(92vw, calc(440 * var(--unit))); pointer-events: none; }
.toast {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-m);
  background: var(--toast-bg);
  color: var(--toast-text);
  box-shadow: var(--shadow-3);
  font-weight: 600;
  pointer-events: auto;
  animation: toast-in var(--duration-theme) var(--ease-out);
}
.toast::before { content: ""; flex: none; width: calc(10 * var(--unit)); height: calc(10 * var(--unit)); border-radius: 50%; background: var(--brand-fill); }
@keyframes toast-in { from { opacity: 0; transform: translateY(calc(8 * var(--unit))); } to { opacity: 1; transform: none; } }

/* ---------- empty state ---------- */
.empty { display: grid; justify-items: center; text-align: center; gap: var(--space-3); padding: var(--space-7) var(--space-6); border: 1px dashed var(--line-input); border-radius: var(--radius-m); background: var(--surface); max-width: calc(460 * var(--unit)); margin-inline: auto; }
.empty-mark { color: var(--text-muted); width: auto; height: calc(36 * var(--unit)); }
.empty h2, .empty h3 { margin: 0; }
.empty p { color: var(--text-muted); margin: 0; max-width: 44ch; }

/* ---------- loading mark ---------- */
.loading { display: inline-flex; align-items: center; gap: var(--space-3); color: var(--text-muted); font-size: var(--step--1); }
.loading-mark { width: auto; height: calc(32 * var(--unit)); color: var(--brand); }
.loading-eye { transform-box: fill-box; transform-origin: center; animation: eye-scan 1.2s var(--ease-out) infinite; }
@keyframes eye-scan { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(0.35); opacity: 0.4; } }

/* ---------- footer ---------- */
.site-footer { border-top: 1px solid var(--line); background: var(--surface-sunken); padding: var(--space-10) 0 var(--space-8); font-size: var(--step--1); color: var(--text-muted); }
.footer-grid { display: grid; gap: var(--space-7); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(150 * var(--unit))), 1fr)); }
.footer-brand { grid-column: 1 / -1; max-width: 34ch; }
@media (width >= 900px) { .footer-grid { grid-template-columns: 1.6fr repeat(4, 1fr); } .footer-brand { grid-column: auto; } }
.footer-brand p { margin: var(--space-2) 0 0; }
.footer-group h2 { font-family: var(--font-text); font-size: var(--step--1); font-weight: 700; color: var(--text); margin: 0 0 var(--space-3); letter-spacing: 0; }
.footer-group ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-1); }
.footer-group a { display: inline-flex; align-items: center; min-height: calc(32 * var(--unit)); color: var(--text-muted); text-decoration: none; }
.footer-group a:hover { color: var(--link-hover); text-decoration: underline; }
.footer-legal { margin-top: var(--space-9); padding-top: var(--space-5); border-top: 1px solid var(--line); display: grid; gap: var(--space-2); }
.footer-legal p { margin: 0; }
.footer-legal a { color: var(--text-muted); }
.footer-langs ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-4); }
.footer-langs a[aria-current="true"] { color: var(--text); font-weight: 600; }

/* ---------- prose ---------- */
.prose h2 { margin-top: var(--space-9); }
.prose h3 { margin-top: var(--space-7); }
.prose ul, .prose ol { padding-left: var(--space-6); }
.prose li + li { margin-top: var(--space-1); }
.prose table { border-collapse: collapse; width: 100%; font-size: var(--step--1); margin: var(--space-6) 0; display: block; overflow-x: auto; }
.prose td, .prose th { border: 1px solid var(--line); padding: var(--space-2) var(--space-3); text-align: left; }
.prose blockquote { margin: var(--space-6) 0; padding-left: var(--space-5); border-left: 3px solid var(--brand); color: var(--text-muted); }

/* ---------- skeleton helpers kept for existing views ---------- */
.facts { display: grid; grid-template-columns: max-content 1fr; gap: var(--space-2) var(--space-5); margin: 0 0 var(--space-4); }
.facts dt { color: var(--text-muted); }
.facts dd { margin: 0; }
/* Phones: one column, so a long question never widens the page past the screen (the home objection block). */
@media (width < 600px) { .facts { grid-template-columns: minmax(0, 1fr); row-gap: var(--space-1); } .facts dd { margin-bottom: var(--space-3); } }
.oauth { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; margin: var(--space-4) 0; }
.oauth p { width: 100%; margin: 0; }

/* ---------- utilities and the style showcase ---------- */
.muted { color: var(--text-muted); }
.small { font-size: var(--step--1); }
.visually-hidden { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
.swatches { display: grid; gap: var(--space-3); grid-template-columns: repeat(auto-fill, minmax(min(100%, calc(150 * var(--unit))), 1fr)); list-style: none; padding: 0; margin: 0 0 var(--space-6); }
.swatch { border: 1px solid var(--line); border-radius: var(--radius-s); overflow: hidden; background: var(--surface); font-size: var(--step--1); }
.swatch::before { content: ""; display: block; height: calc(56 * var(--unit)); background: var(--swatch); border-bottom: 1px solid var(--line); }
.swatch span { display: block; padding: var(--space-2) var(--space-3); }
.swatch-brand { --swatch: var(--brand); }
.swatch-ink { --swatch: var(--text); }
.swatch-paper { --swatch: var(--bg); }
.swatch-island { --swatch: var(--island-bg); }
.swatch-active { --swatch: var(--status-active-dot); }
.swatch-trial { --swatch: var(--status-trial-dot); }
.swatch-danger { --swatch: var(--status-danger-dot); }
.specimen-display { font-family: var(--font-display); font-size: var(--step-4); font-weight: 750; letter-spacing: -0.025em; line-height: 1.05; margin: 0 0 var(--space-3); }
.specimen-mono { font-family: var(--font-mono); font-size: var(--step-1); margin: 0 0 var(--space-3); }

/* ---------- home page and the generator (src/site/generator, views/site/generator) ----------
   The generator is one sheet: type chips on top, the steps on the left, and on the right the
   press-check table (sunken) with the proof (raised, crop marks) and the print-check line. */
.home-hero { padding-top: 0; }
.home-intro { margin-bottom: var(--space-6); }
.home-intro h1 { max-width: 20ch; margin-bottom: var(--space-3); }
@media (width >= 1100px) {
  .home-intro { display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); column-gap: var(--space-9); align-items: baseline; }
  .home-intro h1 { grid-column: 1 / -1; max-width: none; }
}
.home-tagline { font-family: var(--font-display); font-size: var(--step-2); font-weight: 600; line-height: var(--leading-snug); color: var(--text); margin-bottom: var(--space-3); }
.home-answer { color: var(--text-muted); max-width: 62ch; margin: 0; }
@media (width < 760px) {
  .chip { padding: 0 var(--space-3); }
  .gen-types { padding: var(--space-3) var(--space-4); }
  .home-hero { margin-top: calc(-1 * var(--space-6)); }
  .home-intro { margin-bottom: var(--space-4); }
  .home-intro h1 { font-size: var(--step-4); }
  .home-tagline { font-size: var(--step-1); margin-bottom: var(--space-2); }
  .home-answer { font-size: var(--step--1); line-height: var(--leading-snug); }
}

.gen { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-l); box-shadow: var(--shadow-1); }
.gen-form-error { margin: var(--space-5) var(--space-5) 0; }
.gen-types { position: relative; border: 0; border-bottom: 1px solid var(--line); border-radius: 0; padding: var(--space-4) var(--space-5); margin: 0; display: grid; gap: var(--space-3); }
.chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  flex: none;
  min-height: var(--tap-min);
  padding: 0 var(--space-4);
  border: 1px solid var(--line-input);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}
.chip input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.chip:hover { border-color: var(--brand); }
.chip:has(input:checked) { background: var(--brand-fill); border-color: var(--brand-fill); color: var(--on-brand); }
.chip-more:has(input:checked) { background: var(--brand-tint); border-color: var(--brand); color: var(--brand-tint-text); }
.chip:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
/* The type row (WEB-007): the six top types with their glyphs, then "More" without JS (the other types
   join the row as chips) or "All types" with JS (the type sheet); a type picked there shows as a chip. */
.chip .type-glyph { margin-right: calc(7 * var(--unit)); }
.type-glyph { flex: none; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.type-glyph .glyph-fill { fill: currentColor; stroke: none; }
.chip-all { font: inherit; font-weight: 600; }
.chip-all[aria-expanded="true"] { background: var(--brand-tint); border-color: var(--brand); color: var(--brand-tint-text); }
.chip-all:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
#generator[data-type-sheet] .chip-more { display: none; }
@supports selector(:has(*)) {
  .chip-extra { display: none; }
  .gen-types:has(#gen-more:checked) .chip-extra, .chip-extra:has(input:checked) { display: inline-flex; }
  #generator[data-type-sheet] .chip-extra:not(:has(input:checked)) { display: none; }
}
@media (width < 760px) {
  /* One row that scrolls sideways, never three wrapped rows: the field and Create stay high on the first screen. */
  /* A fieldset grows to its content's min-content width by default: the row must scroll inside it instead. */
  .gen-types { min-inline-size: 0; }
  .gen-chips {
    min-width: 0;
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    scroll-padding-inline: var(--space-4);
    scrollbar-width: none;
    margin: 0 calc(-1 * var(--space-4));
    padding: calc(5 * var(--unit)) var(--space-7) calc(5 * var(--unit)) var(--space-4);
    mask-image: linear-gradient(to right, var(--fixed-white) calc(100% - var(--space-7)), transparent);
  }
  .gen-chips::-webkit-scrollbar { display: none; }
  .gen-chips .chip { scroll-snap-align: start; }
}

.gen-grid { display: grid; }
.gen-main { padding: var(--space-5); min-width: 0; }
.gen-out { background: var(--surface-sunken); border-top: 1px solid var(--line); border-radius: 0 0 var(--radius-l) var(--radius-l); padding: var(--space-6) var(--space-5); min-width: 0; }
@media (width >= 760px) {
  .gen-grid { grid-template-columns: minmax(0, 1fr) minmax(calc(280 * var(--unit)), calc(380 * var(--unit))); }
  .gen-main { padding: var(--space-6); }
  /* Centre the preview group in its panel so a long controls column (long forms stretch the grid row) leaves
     no tall grey void below the sticky preview; short columns centre on nothing and sit as before. */
  .gen-out { border-top: 0; border-left: 1px solid var(--line); border-radius: 0 0 var(--radius-l) 0; padding: var(--space-7) var(--space-6); display: flex; flex-direction: column; justify-content: center; }
  .gen-out-in { position: sticky; top: var(--space-6); }
}
@media (width < 760px) {
  /* The first screen holds the H1, the chip row, the field and Create (WEB-007): a tighter content head. */
  .gen-main { padding-top: var(--space-4); }
  .gen-main > .gen-step:first-child .gen-step-title { margin-bottom: var(--space-3); }
}
.gen-step + .gen-step { margin-top: var(--space-7); padding-top: var(--space-6); border-top: 1px solid var(--line); }
.gen-step-title { font-family: var(--font-text); font-size: var(--step-0); font-weight: 700; letter-spacing: 0; margin-bottom: var(--space-4); }

.gen-panel { display: none; }
.gen-panel.is-current { display: grid; }
@supports selector(:has(*)) {
  .gen-panel.is-current { display: none; }
  .gen:has(input[name="type"][value="url"]:checked) [data-panel="url"],
  .gen:has(input[name="type"][value="vcard"]:checked) [data-panel="vcard"],
  .gen:has(input[name="type"][value="review"]:checked) [data-panel="review"],
  .gen:has(input[name="type"][value="wifi"]:checked) [data-panel="wifi"],
  .gen:has(input[name="type"][value="pdf"]:checked) [data-panel="pdf"],
  .gen:has(input[name="type"][value="instagram"]:checked) [data-panel="instagram"],
  .gen:has(input[name="type"][value="text"]:checked) [data-panel="text"],
  .gen:has(input[name="type"][value="email"]:checked) [data-panel="email"],
  .gen:has(input[name="type"][value="sms"]:checked) [data-panel="sms"],
  .gen:has(input[name="type"][value="phone"]:checked) [data-panel="phone"],
  .gen:has(input[name="type"][value="geo"]:checked) [data-panel="geo"],
  .gen:has(input[name="type"][value="event"]:checked) [data-panel="event"],
  .gen:has(input[name="type"][value="epc"]:checked) [data-panel="epc"],
  .gen:has(input[name="type"][value="app"]:checked) [data-panel="app"] { display: grid; }
}
.gen-panel { gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(200 * var(--unit))), 1fr)); margin-bottom: var(--space-4); }
.gen-panel .is-wide, .gen-panel .is-check, .gen-note { grid-column: 1 / -1; }
/* Multi-field rows share one baseline (UX, owner 2026-10-12): each field fills the row height and its
   control sits at the bottom, so a label that wraps its "(optional)" marker never drops its input below
   the others. A single full-width field has no spare height, so this is a no-op there. */
.gen-panel .field { display: flex; flex-direction: column; gap: var(--space-2); }
.gen-panel .field > :is(input, select, textarea) { margin-top: auto; }
.gen-note { margin: 0; color: var(--text-muted); }
.field-optional { font-weight: 400; color: var(--text-muted); font-size: var(--step--1); }
label > span + .field-optional { margin-left: var(--space-1); }
.field-error[hidden] { display: none; }
.gen-create { width: 100%; }
@media (width >= 760px) { .gen-create { width: auto; } }

.gen-mode { border: 0; padding: 0; margin: var(--space-6) 0 0; display: grid; gap: var(--space-3); }
.gen-mode legend { font-weight: 700; padding: 0; margin-bottom: var(--space-1); }
.gen-mode .field-hint { margin-bottom: var(--space-1); }
@media (width >= 1100px) { .gen-mode { grid-template-columns: 1fr 1fr; } .gen-mode legend, .gen-mode .field-hint { grid-column: 1 / -1; } }
.mode-card {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-1) var(--space-3);
  align-items: start;
  padding: var(--space-4);
  border: 1px solid var(--line-input);
  border-radius: var(--radius-m);
  background: var(--surface);
  font-weight: 400;
  align-content: start;
  cursor: pointer;
}
.mode-card input { margin-top: 0.2em; grid-row: span 2; }
.mode-card:has(input:checked) { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); background: var(--brand-tint); }
.mode-name { font-weight: 700; display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.mode-lines { font-size: var(--step--1); color: var(--text-muted); line-height: var(--leading-snug); }
.mode-card:has(input:checked) .mode-lines { color: var(--text); }
/* Fixed or editable: one segmented control; its explainer lines take turns in one cell (nothing moves). */
#generator .gen-mode[data-mode-seg] { grid-template-columns: none; gap: var(--space-2); margin-top: var(--space-5); }
#generator .gen-mode[data-mode-seg] legend { margin-bottom: var(--space-2); }
.mode-seg { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; padding: 3px; border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface-sunken); }
/* Dark: the sunken track would vanish into the dark sheet, so it rises a step above it with a firmer edge. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .mode-seg { border-color: var(--line-strong); background: color-mix(in srgb, var(--line-strong) 55%, var(--surface)); }
}
:root[data-theme="dark"] .mode-seg { border-color: var(--line-strong); background: color-mix(in srgb, var(--line-strong) 55%, var(--surface)); }
#generator .mode-seg .mode-card { position: relative; display: flex; align-items: center; justify-content: center; min-height: var(--tap-min); padding: var(--space-2) var(--space-3); border: 0; border-radius: calc(var(--radius-m) - 3px); background: transparent; box-shadow: none; color: var(--text); text-align: center; }
#generator .mode-seg .mode-card input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
#generator .mode-seg .mode-name { justify-content: center; gap: var(--space-1) var(--space-2); font-size: var(--step--1); line-height: var(--leading-snug); }
#generator .mode-seg .mode-card:hover { color: var(--text); background: color-mix(in srgb, var(--surface) 55%, transparent); }
#generator .mode-seg .mode-card:has(input:checked) { color: var(--brand-tint-text); background: var(--surface); box-shadow: inset 0 0 0 1.5px var(--brand), var(--shadow-1); }
#generator .mode-seg .mode-card:has(input:checked) .mode-name::before { content: ""; flex: none; width: calc(9 * var(--unit)); height: calc(5 * var(--unit)); border: solid currentColor; border-width: 0 0 2px 2px; transform: rotate(-45deg) translateY(-2px); }
#generator .mode-seg .mode-card:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: 2px; }
.mode-explain { display: grid; }
.mode-explain > * { grid-area: 1 / 1; margin: 0; font-size: var(--step--1); line-height: var(--leading-snug); color: var(--text-muted); }
@supports selector(:has(*)) {
  .mode-explain > * { visibility: hidden; }
  .gen-mode:not(:has(input:checked)) .mode-help,
  .gen-mode:has(input[value="fixed"]:checked) [data-explain="fixed"],
  .gen-mode:has(input[value="editable"]:checked) [data-explain="editable"] { visibility: visible; }
  #generator .gen-mode:has(.mode-card:hover, input:focus-visible) .mode-explain > * { visibility: hidden; }
  #generator .gen-mode:has([data-mode-card="fixed"]:hover, input[value="fixed"]:focus-visible) [data-explain="fixed"],
  #generator .gen-mode:has([data-mode-card="editable"]:hover, input[value="editable"]:focus-visible) [data-explain="editable"] { visibility: visible; color: var(--text); }
}
/* Touch: no hover, and a tap is an input, so only the line in use takes room. */
@media (hover: none) {
  @supports selector(:has(*)) {
    .mode-explain > * { display: none; }
    .gen-mode:not(:has(input:checked)) .mode-help,
    .gen-mode:has(input[value="fixed"]:checked) [data-explain="fixed"],
    .gen-mode:has(input[value="editable"]:checked) [data-explain="editable"] { display: block; }
    #generator .gen-mode:has(input:focus-visible) .mode-explain > * { display: none; }
    #generator .gen-mode:has(input[value="fixed"]:focus-visible) [data-explain="fixed"],
    #generator .gen-mode:has(input[value="editable"]:focus-visible) [data-explain="editable"] { display: block; }
  }
}
@supports not selector(:has(*)) {
  .mode-explain { gap: var(--space-2); }
  .mode-explain > * { grid-area: auto; }
}

/* The design panel (step 3; views/site/generator/design.ejs, client/generator/): a builder head with
   "Surprise me", a segmented tab strip, then tiles that are proof chips: small sheets of the visitor's
   own paper (their background colour) on one 10-column grid, soft on the panel, lifted on hover, ringed
   in brand green with a check mark when chosen. Style and glyph tiles take one column, template and
   frame tiles two (the same rhythm in every tab). Narrow panels turn each row into a sideways rail.
   Without JS the tabs give way to headings and the tiles to radio buttons. */
.gen-design {
  --cols: 10;
  --tile-gap: calc(10 * var(--unit));
  container-type: inline-size;
}

/* The head: the step title on the left, "Surprise me" on the right. */
.gen-design-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2) var(--space-3); min-height: calc(36 * var(--unit)); margin-bottom: var(--space-3); }
.gen-design-head .gen-step-title { margin: 0; }
/* Quick path (WEB-001a): with JS the panel opens Quick (one line, the default design is ready) and
   "Customise" opens the tabs; html[data-design="full"] is set by /js/theme.js before the first paint for a
   visitor who chose Customise, so nothing moves. Without JS there is no button and every panel shows. */
.gen-design-head .gen-surprise { margin-left: auto; }
.gen-customise, .gen-quick-line { display: none; }
.js .gen-design[data-quick] .gen-customise { display: inline-flex; }
.gen-customise-glyph { flex: none; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; }
.js .gen-customise[aria-expanded="true"] { background: var(--brand-tint); color: var(--brand-tint-text); border-color: var(--brand); }
.js:not([data-design="full"]) .gen-design[data-quick] .gen-quick-line { display: block; margin: 0; color: var(--text-muted); font-size: var(--step--1); }
.js:not([data-design="full"]) .gen-design[data-quick] .gen-tabs { display: none; }
.gen-surprise {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-min);
  padding: 0 var(--space-4) 0 var(--space-3);
  border: 1px solid var(--line-input);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: var(--step--1);
  font-weight: 650;
  white-space: nowrap;
  cursor: pointer;
}
.gen-surprise[hidden] { display: none; }
.gen-surprise:hover { border-color: var(--brand); background: var(--brand-tint); color: var(--brand-tint-text); }
.gen-surprise-die { flex: none; }
.gen-surprise-die rect { fill: none; stroke: currentColor; stroke-width: 1.5; }
.gen-surprise-die circle { fill: currentColor; }

/* The tab strip: one segmented control; the open tab is a raised sheet. */
.gen-tabs .gen-tablist {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(max-content, 1fr);
  gap: 2px;
  padding: var(--space-1);
  border: 0;
  border-radius: var(--radius-m);
  background: var(--surface-sunken);
}
.gen-tabs .gen-tablist [role="tab"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--tap-min);
  padding: 0 var(--space-3);
  border: 0;
  border-radius: calc(var(--radius-m) - 3px);
  color: var(--text-muted);
}
.gen-tabs .gen-tablist [role="tab"]:hover { color: var(--text); background: color-mix(in srgb, var(--surface) 55%, transparent); }
.gen-tabs .gen-tablist [role="tab"][aria-selected="true"] { color: var(--text); background: var(--surface); box-shadow: 0 0 0 1px var(--line), var(--shadow-1); }
.gen-tabs .gen-tablist [role="tab"]:focus-visible { outline-offset: -2px; }
.gen-tab-glyph { flex: none; fill: none; stroke: currentColor; stroke-width: 1.5; }
.gen-tab-colours { flex: none; }
.gen-tab-colours circle { stroke: var(--line-strong); stroke-width: 1; }
.gen-tabs [role="tabpanel"] { padding-top: var(--space-5); }
.gen-tabpanel-title { display: none; }
/* Before /js/ui.js has hidden the other panels, only the open one shows (no jump when it runs). */
@media (scripting: enabled) {
  .gen-tabs:not(:has(.gen-tabpanel[hidden])) .gen-tabpanel:not([data-default]) { display: none; }
  .gen-tile-grid:not(.is-open) [data-extra] { display: none; }
}

/* Rows of tiles. */
.gen-tiles { border: 0; padding: 0; margin: 0; min-width: 0; }
.gen-tiles + .gen-tiles, .gen-cta + .gen-tiles, .gen-tiles + .gen-cta, .gen-dropzone-row + .gen-tiles { margin-top: var(--space-6); }
.gen-tiles legend { padding: 0; margin-bottom: var(--space-3); font-weight: 700; }
.gen-tiles-value { margin-left: var(--space-2); font-weight: 400; font-size: var(--step--1); color: var(--text-muted); }
.gen-tiles[data-inactive] .tile { opacity: 0.5; }
.gen-tile-grid { display: grid; grid-template-columns: repeat(var(--cols), minmax(0, 1fr)); gap: var(--tile-gap); padding: calc(6 * var(--unit)); margin: calc(-6 * var(--unit)); }
.gen-tiles.is-large .tile { grid-column: span 2; }
.tile { position: relative; display: block; aspect-ratio: 1; min-width: 0; border-radius: var(--radius-m); cursor: pointer; }
.tile[hidden] { display: none; }
.tile input { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.tile-art { position: relative; display: grid; place-items: center; width: 100%; height: 100%; overflow: hidden; border-radius: inherit; background: var(--surface); box-shadow: var(--tile-rest); }
.tile-art svg, .tile-art img { display: block; width: 100%; height: 100%; }
.tile-art img { object-fit: contain; padding: 12%; }
/* The static tile picture (static-tiles.ts) fills the box like the painted svg does, no extra padding. */
.tile-art img.tile-img { padding: 0; object-fit: contain; }
/* Whole-code tiles sit on their own paper with an even margin. */
.gen-tiles.is-large .tile-art { padding: 9%; }
.gen-tiles.is-large .tile-art svg, .gen-tiles.is-large .tile-art img.tile-img { width: 100%; height: 100%; }
/* The chosen tile: a 2 px brand ring with a gap, plus a check mark (shape, not colour alone). */
.tile::before { content: ""; position: absolute; z-index: 1; inset: 0; border-radius: var(--radius-m); box-shadow: inset 0 0 0 1.5px var(--brand); opacity: 0; pointer-events: none; }
.tile:has(input:checked)::before { opacity: 1; }
.tile:has(input:checked) .tile-art::after { content: ""; position: absolute; z-index: 1; right: calc(4 * var(--unit)); bottom: calc(4 * var(--unit)); width: calc(16 * var(--unit)); height: calc(16 * var(--unit)); border-radius: 50%; background: var(--brand-fill); box-shadow: 0 0 0 2px var(--surface); }
.tile:has(input:checked) .tile-art::before { content: ""; position: absolute; z-index: 2; right: calc(9 * var(--unit)); bottom: calc(10 * var(--unit)); width: calc(6 * var(--unit)); height: 3px; border: solid var(--on-brand); border-width: 0 0 2px 2px; transform: rotate(-45deg); }
.tile:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: calc(6 * var(--unit)); }
.tile-name { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.gen-tiles-more { justify-self: start; width: auto; margin-top: var(--space-4); }
/* The outer-shape outline toggle sits its own target distance below the shape tiles (target-size, WCAG 2.5.8). */
.gen-outline { margin-top: var(--target-min); min-height: var(--target-min); align-items: center; }
.gen-outline input { margin-top: 0; }
/* The sticker sheet block (DES-032) in the download area: spaced controls, the crop toggle a full target. */
.gen-sheet { margin-top: var(--space-5); padding-top: var(--space-4); border-top: 1px solid var(--line); }
.gen-sheet-title { margin: 0 0 var(--space-2); font-size: var(--step-0); }
.gen-sheet-preset { margin-top: var(--space-3); }
.gen-sheet-crop { margin: var(--target-min) 0; min-height: var(--target-min); align-items: center; }
.gen-sheet-crop input { margin-top: 0; }
.gen-proof.is-previewing .proof-sheet { outline: 1px dashed var(--brand); outline-offset: calc(5 * var(--unit)); }
/* A peek is not the checked code: the stamp steps back. */
.gen-proof.is-previewing ~ .gen-check { opacity: 0.4; }
/* Narrow panels (phones, a narrow column): each row is a rail that scrolls sideways. */
@container (width < 600px) {
  .gen-tile-grid { --tile: calc(56 * var(--unit)); grid-auto-flow: column; grid-template-columns: none; grid-auto-columns: var(--tile); overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity; scroll-padding-inline: var(--space-2); scrollbar-width: none; padding: var(--space-2); margin: calc(-1 * var(--space-2)); }
  .gen-tiles.is-large .gen-tile-grid { grid-auto-columns: calc(2 * var(--tile) + var(--tile-gap)); }
  .gen-tiles.is-large .tile { grid-column: auto; }
  .tile { scroll-snap-align: start; }
  .tile:has(input:focus-visible) { outline-offset: 3px; }
  .gen-tabs .gen-tablist { grid-auto-columns: max-content; overflow-x: auto; scrollbar-width: none; }
}

.gen-colours { display: grid; gap: var(--space-5); }
.gen-colour { border: 0; padding: 0; margin: 0; min-width: 0; }
.gen-colour legend { font-weight: 700; padding: 0; margin-bottom: var(--space-2); }
.gen-colour-row { display: grid; gap: var(--space-2) var(--space-5); align-items: start; }
.gen-hex label { font-size: var(--step--1); }
.gen-hex .field-hint { margin-bottom: 0; }
@media (width >= 1100px) { .gen-colour-row { grid-template-columns: auto minmax(10rem, 1fr); } }
.swatch-row { display: flex; flex-wrap: wrap; gap: var(--space-1); }
.swatch-pick { position: relative; display: inline-grid; place-items: center; width: var(--tap-min); height: var(--tap-min); border: 2px solid transparent; border-radius: var(--radius-m); cursor: pointer; }
.swatch-pick input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.swatch-pick svg { width: calc(32 * var(--unit)); height: calc(32 * var(--unit)); }
.swatch-pick svg rect { stroke: var(--line-strong); stroke-width: 1; }
.swatch-pick:has(input:checked), .swatch-custom[data-on] { border-color: var(--text); }
.swatch-pick:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: 1px; }
/* Too little contrast against the other colour: struck through, and named so in its label. */
.swatch-pick[data-low]::after { content: ""; position: absolute; width: 2px; height: calc(36 * var(--unit)); border-radius: 1px; background: var(--status-danger-dot); transform: rotate(45deg); pointer-events: none; }
.swatch-custom { background: var(--hue-wheel); background-clip: content-box; padding: 2px; }
.swatch-custom svg { width: calc(28 * var(--unit)); height: calc(28 * var(--unit)); }
.swatch-custom svg rect { stroke: var(--surface); stroke-width: 2; }
.swatch-plus { fill: none; stroke: var(--fixed-white); stroke-width: 2.5; stroke-linecap: round; mix-blend-mode: difference; }
.gen-contrast { margin: var(--space-4) 0 0; font-size: var(--step--1); color: var(--text-muted); }
.gen-contrast:empty { display: none; }
.gen-contrast[data-level="low"] { color: var(--status-trial-text); }
.gen-contrast[data-level="bad"] { color: var(--status-danger-text); font-weight: 650; }
/* Frame tab: the call to action with its suggestion chips and a counter. */
.gen-cta { margin-top: var(--space-6); max-width: 34rem; }
.gen-cta .field-hint { display: flex; justify-content: space-between; gap: var(--space-3); }
.gen-cta-count { flex: none; font-variant-numeric: tabular-nums; }
.gen-cta-chips { margin-top: var(--space-3); }
.gen-cta-chips[hidden], .gen-cta-chips [hidden] { display: none; }
.chip-small { min-height: calc(34 * var(--unit)); padding: 0 var(--space-3); font: inherit; font-size: var(--step--1); font-weight: 600; }
.gen-icon-note { margin-top: var(--space-2); }
.gen-icon-note[hidden] { display: none; }

/* Logo tab: the drop zone (a real upload button, WCAG 2.5.7), quick picks, then size, shape, clear area. */
.gen-logo { display: grid; gap: var(--space-6); }
.dropzone { display: grid; justify-items: center; gap: var(--space-2); padding: var(--space-6) var(--space-5); border: 1.5px dashed var(--line-input); border-radius: var(--radius-l); background: var(--surface-sunken); text-align: center; }
.dropzone[hidden] { display: none; }
.dropzone[data-drag] { border-color: var(--brand); background: var(--brand-tint); }
.dropzone-glyph { fill: none; stroke: var(--brand); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.dropzone-title { margin: 0; font-weight: 700; }
.dropzone-title[hidden] { display: none; }
.dropzone .field-hint { margin: 0; max-width: 36rem; }
.dropzone:has(input:focus-visible) label { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
/* PDF type: a styled drop zone (UX v4) in place of the raw file input. Drag-and-drop, the chosen file's
   name and size, and a Replace link. The input is visually hidden but keyboard reachable through the label. */
.gen-pdf .field-label { display: block; margin-bottom: var(--space-2); font-weight: 650; }
.gen-dropzone { display: grid; justify-items: center; gap: var(--space-2); padding: var(--space-5); border: 1.5px dashed var(--line-input); border-radius: var(--radius-m); background: var(--surface-sunken); text-align: center; transition: border-color 120ms ease, background-color 120ms ease; }
.gen-dropzone[data-drag] { border-color: var(--brand); background: var(--brand-tint); }
.gen-dropzone[hidden] { display: none; }
.gen-dropzone:has(input:focus-visible) .gen-dropzone-choose { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
.gen-dropzone-drop { margin: 0; font-size: var(--step--1); color: var(--text-muted); }
.gen-file-chosen { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); border: 1px solid color-mix(in srgb, var(--brand) 40%, var(--line)); border-radius: var(--radius-m); background: var(--brand-tint); }
.gen-file-chosen[hidden] { display: none; }
.gen-file-icon { flex: none; fill: none; stroke: var(--brand-tint-text); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.gen-file-meta { display: grid; min-width: 0; line-height: 1.3; }
.gen-file-meta strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gen-file-size { font-size: var(--step--2); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.gen-file-replace { margin-left: auto; flex: none; min-height: var(--tap-min); }
.gen-logo-controls { display: grid; gap: var(--space-5); }
.gen-logo-controls[hidden] { display: none; }
.gen-logo-size { max-width: 30rem; }
.gen-logo-size label { display: flex; justify-content: space-between; align-items: baseline; }
.gen-logo-size-out { font-weight: 400; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.gen-logo-size input[type="range"] { width: 100%; accent-color: var(--brand); min-height: calc(32 * var(--unit)); }
.gen-logo-size .field-hint { margin-bottom: 0; }
.gen-logo-remove { justify-self: start; }
.gen-logo-remove[hidden] { display: none; }
.gen-logo-status { margin: 0; font-size: var(--step--1); }
.gen-logo-status:empty { display: none; }
.gen-logo-text[hidden] { display: none; }
.gen-logo-text { max-width: 30rem; }
.gen-logo-text-row { display: flex; gap: var(--space-2); align-items: center; }
.gen-logo-text-row .button { white-space: nowrap; }
.gen-logo-text-row input { flex: 1 1 auto; min-width: 0; }

/* Motion (the brief's spec): only transform, opacity and clip-path; hover motion on fine pointers only. */
@media (prefers-reduced-motion: no-preference) {
  .gen-tabs[data-anim] .gen-tabpanel:not([hidden]) { animation: gen-panel-in var(--dur-swap) var(--ease-out); }
  .tile::before { transition: opacity var(--dur-hover) var(--ease-out); }
  .tile-art { transition: transform var(--dur-hover) var(--ease-out), box-shadow var(--dur-hover) var(--ease-out); }
  .tile-art::after { transition: opacity var(--dur-hover) var(--ease-out); }
  .tile:active .tile-art { transform: scale(0.97); transition-duration: var(--dur-press); }
  .gen-surprise.is-rolling .gen-surprise-die { animation: gen-roll 300ms var(--ease-out); }
}
@media (hover: hover) and (pointer: fine) {
  .tile:hover .tile-art { box-shadow: var(--tile-lift); }
}
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .tile:hover .tile-art { transform: translateY(-2px); }
  .tile:hover:active .tile-art { transform: translateY(-1px) scale(0.97); }
}
@keyframes gen-panel-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes gen-roll { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* Without JS: headings instead of tabs, every panel in turn, the tiles as a list of radio buttons. */
@media (scripting: none) {
  .gen-tabs .gen-tablist { display: none; }
  .gen-tabpanel-title { display: block; font-family: var(--font-text); font-size: var(--step-0); margin: 0 0 var(--space-3); }
  .gen-tabs [role="tabpanel"] + [role="tabpanel"] { margin-top: var(--space-4); }
  .gen-tile-grid { grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); gap: var(--space-1) var(--space-3); }
  .gen-tiles.is-large .tile { grid-column: auto; }
  .tile { display: flex; align-items: center; gap: var(--space-2); aspect-ratio: auto; min-height: calc(32 * var(--unit)); }
  .tile input { position: static; width: auto; height: auto; opacity: 1; }
  .tile::before, .gen-tiles-value, .gen-tiles-more, .swatch-custom { display: none; }
  /* The static picture (static-tiles.ts) shows as a thumbnail beside the labelled radio, so a no-JS or
     scripting-off visitor still sees every tile, not just its name. */
  .tile-art { flex: none; width: calc(44 * var(--unit)); height: calc(44 * var(--unit)); }
  .gen-tiles.is-large .tile-art { padding: 0; }
  .tile-name { position: static; width: auto; height: auto; overflow: visible; clip-path: none; white-space: normal; }
}

.gen-proof { margin: 0 auto; padding: var(--space-5); max-width: calc(340 * var(--unit)); }
.gen-paper { padding: var(--space-4); display: grid; place-items: center; }
.gen-code { display: block; width: 100%; height: auto; max-width: calc(280 * var(--unit)); }
.gen-proof.is-sample .gen-code { opacity: 0.32; }
/* The create flow and the type pages open on a live, lively example in the form's design: full strength,
   labelled by its line (owner UX 2026-10-12, no dim grey placeholder). */
.create .gen-proof.is-sample .gen-code, .xp-hero .gen-proof.is-sample .gen-code { opacity: 1; }
.gen-line { margin: var(--space-6) 0 0; font-size: var(--step--1); font-weight: 600; color: var(--text); text-align: center; overflow-wrap: anywhere; }
.gen-proof.is-sample .gen-line { font-weight: 400; color: var(--text-muted); }
.gen-check {
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
  margin: var(--space-4) 0 var(--space-1);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-m);
  background: var(--status-neutral-bg);
  color: var(--status-neutral-text);
  font-size: var(--step--1);
  font-weight: 650;
  line-height: var(--leading-snug);
}
.gen-check:empty { display: none; }
.gen-check::before { content: ""; flex: none; width: calc(10 * var(--unit)); height: calc(10 * var(--unit)); border-radius: 50%; border: 2px solid var(--status-neutral-dot); transform: translateY(1px); }
.gen-check[data-verdict="green"] { background: var(--status-active-bg); color: var(--status-active-text); }
.gen-check[data-verdict="green"]::before { width: calc(11 * var(--unit)); height: calc(6 * var(--unit)); border-radius: 0; border-width: 0 0 2px 2px; border-color: var(--status-active-dot); transform: rotate(-45deg) translateY(-2px); }
.gen-check[data-verdict="amber"] { background: var(--status-trial-bg); color: var(--status-trial-text); }
.gen-check[data-verdict="amber"]::before { border-color: var(--status-trial-dot); background: linear-gradient(90deg, var(--status-trial-dot) 50%, transparent 50%); }
.gen-check[data-verdict="red"] { background: var(--status-danger-bg); color: var(--status-danger-text); }
.gen-check[data-verdict="red"]::before { border-radius: 2px; border-color: var(--status-danger-dot); background: var(--status-danger-dot); }
.gen-rule { margin: 0; font-size: var(--step--1); color: var(--text-muted); }
/* "How big should it be?": its own small block under the rule line, the distance and its button on one line. */
.gen-size-calc { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--space-2); align-items: end; margin-top: var(--space-5); }
.gen-size-calc > .field-hint { grid-column: 1 / -1; margin: 0 0 var(--space-2); }
.gen-size-calc .field { margin: 0; min-width: 0; }
.gen-size-calc > .button { min-height: var(--tap-min); white-space: nowrap; }
/* Inner experience pages: tidy the scan-size block so the label never wraps against the button
   (owner UX v4). Title on its own row, then the label above its input, with the button aligned to the
   input's baseline on the right. */
.xp-hero .gen-size-calc { grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--space-3); row-gap: var(--space-2); align-items: end; }
.xp-hero .gen-size-calc > .field { grid-column: 1; margin: 0; }
.xp-hero .gen-size-calc > .field > label { white-space: nowrap; }
.xp-hero .gen-size-calc > .field > input { min-height: var(--tap-min); width: 100%; }
.xp-hero .gen-size-calc > .button { grid-column: 2; align-self: end; }
.gen-red { margin-top: var(--space-4); }
.gen-red[hidden] { display: none; }
.gen-red p { margin-bottom: var(--space-3); }

.gen-download, .gen-editable { display: grid; gap: var(--space-3); margin-top: var(--space-6); }
.gen-formats { border: 0; padding: 0; margin: 0; display: grid; gap: var(--space-2); grid-template-columns: 1fr 1fr; }
.gen-formats legend { font-weight: 700; padding: 0; margin-bottom: var(--space-2); grid-column: 1 / -1; }
.gen-formats .option { align-items: center; min-height: var(--tap-min); padding: var(--space-2) var(--space-3); border: 1px solid var(--line-input); border-radius: var(--radius-s); background: var(--surface); font-size: var(--step--1); cursor: pointer; }
.gen-formats .option input { margin-top: 0; }
.gen-formats .option:has(input:checked) { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); background: var(--brand-tint); }
.gen-status { margin: 0; font-size: var(--step--1); color: var(--text-muted); }
.gen-status:empty { display: none; }
.gen-status[data-tone="error"] { color: var(--status-danger-text); font-weight: 650; }
.gen-editable h3 { margin: 0; font-size: var(--step-1); }
.gen-editable p { margin: 0; color: var(--text-muted); }
.gen-done { margin-top: var(--space-5); }
/* The Free account prompt (owner 2026-10-14): an inline, friendly card shown when a vector or print format
   is chosen without an account; never a modal. The chosen format and design carry through sign-up. */
.gen-free-account { display: grid; gap: var(--space-3); margin-top: var(--space-4); padding: var(--space-4); border: 1px solid var(--brand); border-radius: var(--radius-m); background: var(--brand-tint); }
.gen-free-account-title { margin: 0; color: var(--brand-tint-text); }
.gen-free-account p { margin: 0; }
/* "E-mail me the print files": an offer after a fixed download; on a phone the first format action, with the direct download second (UX-011). */
.gen-mail { display: grid; gap: var(--space-3); margin-top: var(--space-5); padding: var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); }
.gen-mail[hidden] { display: none; }
.gen-mail-title { margin: 0; font-weight: 700; }
.gen-mail .field-hint { margin: 0; }
.gen-mail .button { justify-self: start; }
.gen-test { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-3); }
.gen-test[hidden], .gen-test [hidden] { display: none; }
.gen-test .button { min-height: var(--tap-min); }
.gen-mail.is-primary { margin-top: 0; border-color: var(--brand); }
.gen-mail.is-primary .button { background: var(--brand-fill); border-color: var(--brand-fill); color: var(--on-brand); justify-self: stretch; }
.gen-mail-status { margin: 0; font-size: var(--step--1); color: var(--text-muted); }
.gen-mail-status:empty { display: none; }
.gen-mail-status[data-tone="error"] { color: var(--status-danger-text); font-weight: 650; }
.gen-download.has-mail-first [data-download-button] { background: var(--surface); border-color: var(--brand); color: var(--brand-tint-text); }
.gen-done[hidden] { display: none; }
.gen-done p { margin-bottom: var(--space-2); }
.linklike { justify-self: start; min-height: var(--tap-min); padding: 0; border: 0; background: none; color: var(--link); font: inherit; text-decoration: underline; text-underline-offset: 0.18em; cursor: pointer; text-align: left; }
.linklike:hover { color: var(--link-hover); }
@supports selector(:has(*)) {
  .gen-size { display: none; }
  .gen:has(input[name="format"][value="png"]:checked) .gen-size { display: grid; }
  .gen-editable { display: none; }
  .gen:has(input[name="mode"][value="editable"]:checked) .gen-editable { display: grid; }
  .gen:has(input[name="mode"][value="editable"]:checked) .gen-download { display: none; }
}

/* ---- The proof sheet, the proof pass and the type sheet (the design brief, sections 6, 9 and 10) ----
   Motion tokens (--dur-*, --ease-in-out) come from scripts/brand/tokens.mjs; only transform, opacity
   and clip-path move, and the scan line is the one motion over 300 ms. The proof is paper, white in both themes. The pass plays only after a real decode check
   (client/generator/proof.ts), so nothing here runs on a timer. */
.gen-paper { background: var(--fixed-white); }
.gen-proof .proof { isolation: isolate; }
/* The previous render, laid over the new one while it fades out (the crossfade). */
.proof-ghost { position: absolute; inset: 0 0 auto; z-index: 1; pointer-events: none; animation: gen-fade-out var(--dur-swap) var(--ease-out) forwards; }
.proof-ghost.was-sample .gen-code { opacity: 0.32; }
/* The scan line: a 2 px brand line with a faint wash behind it, top to bottom once. */
.proof-scan { position: absolute; inset: 0; z-index: 2; overflow: hidden; pointer-events: none; border-radius: var(--radius-xs); }
.proof-scan::before { content: ""; position: absolute; inset: 0; opacity: 0; border-bottom: 2px solid var(--brand); background: linear-gradient(to bottom, transparent 60%, color-mix(in srgb, var(--brand) 16%, transparent)); transform: translateY(-100%); }
.proof-scan.is-sweeping::before { animation: gen-sweep var(--dur-sweep) var(--ease-in-out); }
/* The stamp lands as the line leaves the code; a red result shakes once instead. */
.gen-check.is-stamping { animation: gen-stamp var(--dur-stamp) var(--ease-out) calc(var(--dur-sweep) - 60ms) both; }
.gen-check.is-shaking { animation: gen-shake var(--dur-swap) var(--ease-out); }
/* Checking: the last stamp stays (its text unchanged, so nothing is announced) with a plain ring. */
.gen-check[data-checking]::before { width: calc(10 * var(--unit)); height: calc(10 * var(--unit)); border-radius: 50%; border: 2px solid var(--status-neutral-dot); background: none; transform: translateY(1px); }
.gen-draft { display: flex; gap: var(--space-2); align-items: center; margin: var(--space-2) 0 var(--space-1); font-size: var(--step--1); color: var(--text-muted); }
.gen-draft:empty { display: none; }
.gen-draft::before { content: ""; flex: none; width: calc(7 * var(--unit)); height: calc(7 * var(--unit)); border-radius: 50%; background: var(--brand-fill); }
.gen-draft.is-new { animation: gen-fade-in var(--dur-stamp) var(--ease-out); }
.gen-policy { margin: var(--space-4) 0 0; font-size: var(--step--1); }
.gen-policy a { display: inline-flex; align-items: center; min-height: var(--target-min); }
/* The fields of a type fade in when the type changes (from the first switch on; never on page load). */
.gen[data-swap] .gen-panel { animation: gen-fade-in var(--dur-swap) var(--ease-out); }

/* "All types": a panel under the chip row on wide screens, a bottom sheet on phones. */
.type-sheet {
  position: absolute;
  z-index: 30;
  top: calc(100% - var(--space-2));
  left: var(--space-5);
  right: auto;
  width: min(calc(700 * var(--unit)), calc(100% - 2 * var(--space-5)));
  max-height: min(calc(100vh - calc(160 * var(--unit))), calc(480 * var(--unit)));
  margin: 0;
  padding: 0;
  overflow: auto;
  overscroll-behavior: contain;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-l);
  background: var(--surface-raised);
  color: var(--text);
  box-shadow: var(--shadow-3);
}
.type-sheet[open] { animation: gen-sheet-in var(--dur-sheet) var(--ease-out); }
.type-sheet::backdrop { background: var(--overlay); }
.type-sheet-head { position: sticky; top: 0; z-index: 1; display: flex; align-items: center; gap: var(--space-3); padding: var(--space-4) var(--space-5) var(--space-3); background: var(--surface-raised); }
.type-sheet-grab { display: none; }
.type-sheet-title { margin: 0; font-size: var(--step-1); }
.type-sheet-close { display: grid; place-items: center; flex: none; width: var(--tap-min); height: var(--tap-min); margin-left: auto; padding: 0; border: 1px solid var(--line); border-radius: var(--radius-pill); background: var(--surface); color: var(--text); cursor: pointer; }
.type-sheet-close svg { fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; }
.type-sheet-search { margin: 0; padding: 0 var(--space-5) var(--space-4); }
.type-sheet-body { display: grid; gap: var(--space-5); padding: 0 var(--space-5) var(--space-5); }
.type-group[hidden] { display: none; }
.type-group-title { margin: 0 0 var(--space-2); font-family: var(--font-text); font-size: var(--step--1); font-weight: 700; color: var(--text-muted); letter-spacing: 0; }
.type-group-note { margin: 0 0 var(--space-2); font-size: var(--step--2); color: var(--text-muted); }
.type-card-hosted { color: inherit; text-decoration: none; }
.type-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(calc(120 * var(--unit)), 1fr)); gap: var(--space-2); }
.type-card {
  display: grid;
  align-content: start;
  justify-items: start;
  gap: 2px;
  min-height: calc(96 * var(--unit));
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.type-card[hidden] { display: none; }
.type-card .type-glyph { width: calc(20 * var(--unit)); height: calc(20 * var(--unit)); margin-bottom: var(--space-2); color: var(--brand); }
.type-card-name { font-weight: 700; line-height: var(--leading-snug); }
.type-card-line { font-size: var(--step--2); line-height: var(--leading-snug); color: var(--text-muted); }
.type-card[aria-pressed="true"] { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); background: var(--brand-tint); }
.type-card[aria-pressed="true"] .type-card-line { color: var(--brand-tint-text); }
.type-card:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: 2px; }
.type-sheet-empty { margin: 0; color: var(--text-muted); }
.type-sheet-empty:empty { display: none; }
@media (hover: hover) and (pointer: fine) {
  .type-card:hover { border-color: var(--brand); }
}
@media (width < 760px) {
  .type-sheet { position: fixed; inset: auto 0 0; width: 100%; max-width: none; max-height: 85dvh; border-bottom: 0; border-radius: var(--radius-l) var(--radius-l) 0 0; padding-bottom: env(safe-area-inset-bottom); }
  .type-sheet[open] { animation-name: gen-sheet-up; }
  .type-sheet-head { padding-top: var(--space-6); }
  .type-sheet-grab { display: block; position: absolute; top: var(--space-2); left: 50%; width: calc(36 * var(--unit)); height: calc(4 * var(--unit)); border-radius: var(--radius-pill); background: var(--line-strong); transform: translateX(-50%); }
}
@media (prefers-reduced-motion: no-preference) {
  .chip, .type-card { transition: transform var(--dur-press) var(--ease-out), border-color var(--dur-hover) var(--ease-out); }
  .chip:active, .type-card:active { transform: scale(0.97); }
}
@media (prefers-reduced-motion: reduce) {
  /* Fewer and gentler (the brief, section 10): no movement, only short fades that carry meaning. These
     beat the global rule below on specificity; the crossfade and the scan line stay off. */
  .gen-check.is-fading, .gen-bar-dot.is-stamping { animation: gen-fade-in var(--dur-calm) linear both !important; }
  .type-sheet[open] { animation: gen-fade-in var(--dur-calm) linear !important; }
}
@keyframes gen-fade-in { from { opacity: 0; } }
@keyframes gen-fade-out { to { opacity: 0; } }
@keyframes gen-sweep { 0% { opacity: 1; transform: translateY(-100%); } 82% { opacity: 1; } 100% { opacity: 0; transform: translateY(0); } }
@keyframes gen-stamp { from { opacity: 0; transform: scale(0.96); } }
@keyframes gen-shake { 25% { transform: translateX(-2px); } 75% { transform: translateX(2px); } }
@keyframes gen-sheet-in { from { opacity: 0; transform: translateY(calc(8 * var(--unit))); } }
@keyframes gen-sheet-up { from { transform: translateY(100%); } }

/* The mobile sheet (WEB-007): preview, mode and Download stay in reach after input. */
.gen-bar { display: none; }
@media (width < 760px) {
  /* WCAG 2.4.11: with the sticky bar on screen, focused controls scroll clear of it. */
  html:has(.gen-bar:not([hidden])) { scroll-padding-bottom: calc(var(--bar-height) + var(--space-6)); }
  .gen-bar:not([hidden]) {
    position: fixed;
    z-index: 40;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--gutter) calc(var(--space-2) + env(safe-area-inset-bottom));
    background: var(--surface-raised);
    border-top: 1px solid var(--line-strong);
    box-shadow: var(--shadow-3);
  }
  body.gen-bar-on { padding-bottom: calc(var(--tap-large) + var(--space-6)); }
}
.gen-bar-thumb { position: relative; flex: none; display: grid; place-items: center; width: var(--tap-large); height: var(--tap-large); padding: var(--space-1); border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--fixed-white); cursor: pointer; }
.gen-bar-code { display: grid; width: 100%; height: 100%; }
.gen-bar-code svg { width: 100%; height: 100%; }
/* The stamp on the mini proof: a check (passed), a bar (warning) or a cross (failed); shape, not colour alone. */
.gen-bar-dot { display: none; position: absolute; top: calc(-6 * var(--unit)); right: calc(-6 * var(--unit)); width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); border: 2px solid var(--surface-raised); border-radius: 50%; }
.gen-bar-dot[data-verdict] { display: block; }
.gen-bar-dot::after { content: ""; position: absolute; }
.gen-bar-dot[data-verdict="green"] { background: var(--status-active-dot); }
.gen-bar-dot[data-verdict="green"]::after { left: 3px; top: 3px; width: calc(7 * var(--unit)); height: calc(4 * var(--unit)); border: solid var(--surface-raised); border-width: 0 0 2px 2px; transform: rotate(-45deg); }
.gen-bar-dot[data-verdict="amber"] { background: var(--status-trial-dot); }
.gen-bar-dot[data-verdict="amber"]::after { left: 3px; right: 3px; top: calc(6 * var(--unit)); height: 2px; background: var(--surface-raised); }
.gen-bar-dot[data-verdict="red"] { background: var(--status-danger-dot); }
.gen-bar-dot[data-verdict="red"]::after { inset: 2px; background: linear-gradient(45deg, transparent 42%, var(--surface-raised) 42% 58%, transparent 58%), linear-gradient(-45deg, transparent 42%, var(--surface-raised) 42% 58%, transparent 58%); }
.gen-bar-dot.is-stamping { animation: gen-stamp var(--dur-stamp) var(--ease-out) both; }
.gen-bar-mode { display: flex; border: 1px solid var(--line-input); border-radius: var(--radius-pill); overflow: hidden; }
.gen-bar-toggle { min-height: var(--tap-min); padding: 0 var(--space-3); border: 0; background: var(--surface); color: var(--text); font: inherit; font-size: var(--step--1); font-weight: 650; cursor: pointer; }
.gen-bar-toggle + .gen-bar-toggle { border-left: 1px solid var(--line-input); }
.gen-bar-toggle[aria-pressed="true"] { background: var(--brand-fill); color: var(--on-brand); }
.gen-bar-toggle:focus-visible { outline-offset: -3px; }
.gen-bar-go { margin-left: auto; }

/* Home sections after the hero. */
.three-lines { list-style: none; padding: 0; margin: 0; border-top: 1px solid var(--line-strong); max-width: 52rem; }
.three-lines li { padding-block: var(--space-4); border-bottom: 1px solid var(--line); font-family: var(--font-display); font-size: var(--step-2); font-weight: 600; line-height: var(--leading-snug); }
.pillars { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-7); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(240 * var(--unit))), 1fr)); }
.pillar { border-top: 3px solid var(--brand); padding-top: var(--space-4); }
.pillar h3 { margin-bottom: var(--space-2); }
.pillar p { margin: 0; color: var(--text-muted); }
.proof-lines { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-3); font-size: var(--step-1); }
.price-row { list-style: none; padding: 0; margin: 0 0 var(--space-5); display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(160 * var(--unit))), 1fr)); }
.price-cell { border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); padding: var(--space-5); display: grid; gap: var(--space-2); align-content: start; }
.price-name { font-family: var(--font-text); font-size: var(--step-0); font-weight: 700; letter-spacing: 0; margin: 0; }
.price-amount { font-family: var(--font-display); font-size: var(--step-3); font-weight: 750; line-height: 1; margin: 0; font-variant-numeric: tabular-nums; }
.price-amount span { font-family: var(--font-text); font-size: var(--step--1); font-weight: 400; color: var(--text-muted); }
.price-note { margin: 0; font-size: var(--step--1); color: var(--text-muted); }

/* ==================== home:start ====================
   The home page as a live surface (views/home.ejs, client/home/). Scoped to the home's own section
   classes, because the shared section classes (.home-hero, .pillars, .steps, .facts...) also dress the
   type, landing and tool pages. One idea runs through it: the generator is a sheet lying on a press
   desk; the visitor's code then shows up printed (card, tent, sticker, sign); every later section
   behaves differently (a toggle card, a strip, a ledger, a receipt, a rate card, a two-column sheet,
   a close you can type into). */

/* ---------- hero: short head, a benefit row, the sheet on its desk ---------- */
.home-live .home-intro { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-2); margin-bottom: var(--space-7); }
.home-live .home-intro h1 { font-size: var(--step-5); letter-spacing: -0.035em; font-weight: 650; max-width: 18ch; margin: 0; text-wrap: balance; }
.home-live .home-tagline { font-size: var(--step-1); color: var(--text-muted); margin: 0; }
.home-benefits-row { display: flex; flex-wrap: wrap; align-items: center; column-gap: var(--space-6); row-gap: var(--space-2); margin-top: var(--space-2); }
.home-benefits { display: flex; flex-wrap: wrap; column-gap: var(--space-5); row-gap: var(--space-1); margin: 0; padding: 0; list-style: none; }
.home-benefit { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--step--1); font-weight: 600; color: var(--text); }
.home-benefit svg { flex: none; width: calc(20 * var(--unit)); height: calc(20 * var(--unit)); padding: 3px; border-radius: 50%; background: var(--brand-tint); stroke: var(--brand-tint-text); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; fill: none; }
.home-trial { white-space: nowrap; font-size: var(--step--1); font-weight: 650; line-height: var(--leading-snug); }
@media (width >= 1100px) {
  .home-trial { margin-left: auto; }
}

/* The desk: the generator is the top sheet of a small stack. */
.home-desk { position: relative; isolation: isolate; }
.home-desk::before, .home-desk::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: auto var(--space-5) calc(-1 * var(--space-2)) var(--space-5);
  height: var(--space-10);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 0 0 var(--radius-l) var(--radius-l);
  box-shadow: var(--shadow-1);
}
.home-desk::after { inset: auto var(--space-9) calc(-1 * var(--space-4)) var(--space-9); background: var(--surface-sunken); }
.home-live .gen { box-shadow: var(--sheet-shadow); }

/* The proof on a light table: press green behind white paper, both themes. */
.home-live .gen-proof { background: radial-gradient(70% 60% at 50% 42%, var(--neon-glow), transparent 72%), var(--surface-sunken); border-radius: var(--radius-m); padding: var(--space-6) var(--space-6) var(--space-5); max-width: calc(360 * var(--unit)); }
.home-live .gen-proof .proof::before { --tick: var(--brand); }
.home-live .gen-proof .proof-sheet { border-color: transparent; box-shadow: var(--paper-lift), 0 0 0 1px var(--line); }
.home-live .gen-line { color: var(--text); margin-top: var(--space-5); }
.home-live .gen-proof.is-sample .gen-line { color: var(--text-muted); }
/* The example code is a real design (HOME_SAMPLE_DESIGN), shown at full strength, labelled by its line. */
.home-live .gen-proof.is-sample .gen-code, .home-live .proof-ghost.was-sample .gen-code { opacity: 1; }

@media (width < 760px) {
  .home-live .home-intro { margin-bottom: var(--space-4); gap: var(--space-1); }
  .home-live .home-tagline { font-size: var(--step-0); }
  .home-benefits { column-gap: var(--space-4); }
  .home-trial { white-space: normal; text-wrap: pretty; }
  .home-desk::before, .home-desk::after { display: none; }
  .home-live .gen-proof { padding: var(--space-5) var(--space-5) var(--space-4); }
}
/* Phones: the proof is below the first screen, so a small printed copy of it sits beside the benefits
   (stacked into a column there), on the same press green as the proof. Wider screens show the proof itself. */
.home-mini { display: none; }
@media (width < 760px) {
  .home-live .home-intro { grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--space-4); align-items: center; }
  .home-live .home-intro > h1 { grid-column: 1 / -1; }
  /* The tagline runs the full width so it is never squeezed into a narrow column beside the mini code;
     the mini code sits beside the stacked benefits only, where short lines leave it room. */
  .home-live .home-tagline { grid-column: 1 / -1; grid-row: 2; }
  .home-live .home-benefits-row { grid-column: 1; grid-row: 3; flex-direction: column; align-items: flex-start; row-gap: var(--space-3); margin-top: var(--space-1); }
  .home-live .home-benefits { flex-direction: column; row-gap: var(--space-2); }
  .home-mini { display: block; grid-column: 2; grid-row: 3; align-self: center; width: min(calc(200 * var(--unit)), 42vw); padding: var(--space-3); margin: var(--space-2) var(--space-1) var(--space-3) 0; border-radius: var(--radius-m); background: var(--neon); box-shadow: var(--shadow-2), 0 calc(16 * var(--unit)) calc(40 * var(--unit)) -16px var(--neon-glow); transform: rotate(2deg); }
  .home-mini-paper { aspect-ratio: 1; padding: var(--space-1); border-radius: var(--radius-xs); background: var(--fixed-white); box-shadow: var(--shadow-1); overflow: hidden; }
  .home-mini .print-svg { width: 100%; height: 100%; }
}

/* ---------- hero: the proof is the hero (client/generator/hero.ts). Wide: controls left, the press
   table with a large square proof and its stamp right, from the sheet's top edge. ---------- */
.home-live .gen-proof { position: relative; }
/* The small round stop control of every loop (direction.md 6): 36 px, with a 44 px touch target on coarse
   pointers (the ring grows invisibly around it); one look for the hero's designs and the story. */
.gen-cycle, .loop-stop { position: relative; display: inline-grid; place-items: center; flex: none; width: calc(45 * var(--unit)); height: calc(45 * var(--unit)); padding: 0; border: 1px solid var(--line-strong); border-radius: 50%; background: var(--surface); color: var(--text); font: inherit; cursor: pointer; box-shadow: var(--shadow-1); transition: background-color var(--dur-hover) var(--ease-out), border-color var(--dur-hover) var(--ease-out); }
.gen-cycle svg, .loop-stop svg { flex: none; width: calc(20 * var(--unit)); height: calc(20 * var(--unit)); fill: currentColor; }
.gen-cycle:hover, .loop-stop:hover { border-color: var(--brand); background: var(--brand-tint); }
.gen-cycle:focus-visible, .loop-stop:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: 2px; }
@media (pointer: coarse) {
  .gen-cycle::before, .loop-stop::before { content: ""; position: absolute; inset: calc(-5 * var(--unit)); border-radius: 50%; }
  .gen-use-look::before { content: ""; position: absolute; inset: calc(-7 * var(--unit)) calc(-4 * var(--unit)); border-radius: var(--radius-pill); }
}
.gen-cycle { position: absolute; top: var(--space-2); right: var(--space-2); z-index: 3; }
.gen-cycle [data-cycle-label] { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.gen-cycle[hidden], .gen-use-look[hidden] { display: none; }
.gen-use-look { position: absolute; top: var(--space-2); left: var(--space-3); z-index: 3; display: inline-flex; align-items: center; min-height: calc(32 * var(--unit)); padding: 0 var(--space-3); border: 0; border-radius: var(--radius-pill); background: var(--neon); color: var(--neon-ink); font: inherit; font-size: var(--step--2); font-weight: 700; cursor: pointer; box-shadow: var(--shadow-1); }
.gen-use-look:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: 2px; }
.gen-proof.is-look .proof { cursor: pointer; }
/* Narrow proofs: the Stop button keeps its words for assistive technology and shows only its icon, so "Use this design" fits beside it. */
@media (width < 600px) {
  .gen-use-look { min-height: calc(40 * var(--unit)); }
}
.gen-cycle .is-play, .gen-cycle[data-paused] .is-hold { display: none; }
.gen-cycle[data-paused] .is-play { display: inline; }
.home-live .gen-paper { aspect-ratio: 1; }
/* Reserved lines: nothing under the proof jumps (CLS 0). */
.home-live .gen-check { min-height: calc(1lh + 2 * var(--space-3)); }
.home-live .gen-check:empty { display: flex; visibility: hidden; }
.home-live .gen-draft { min-height: 1lh; }
.home-live .gen-draft:empty { display: flex; visibility: hidden; }
.home-live .gen-paper > .gen-code, .home-live .proof-ghost > .gen-code { width: 100%; height: 100%; max-width: none; }
@media (width >= 760px) {
  .home-live .gen-main > .gen-step:first-child { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--space-3); align-items: end; }
  .home-live .gen-main > .gen-step:first-child > * { grid-column: 1 / -1; }
  .home-live .gen-main > .gen-step:first-child > .gen-panel { grid-column: 1; margin-bottom: 0; }
  .home-live .gen-create { justify-self: start; margin-top: var(--space-4); }
  .home-live .gen:has(input[name="type"]:is([value="url"], [value="review"], [value="instagram"]):checked) .gen-create { grid-column: 2; margin-top: 0; min-height: calc(60 * var(--unit)); }
  .home-live :is([data-panel="url"], [data-panel="review"], [data-panel="instagram"]) input { min-height: calc(60 * var(--unit)); padding-inline: var(--space-4); font-size: var(--step-1); }
  .home-live .gen-main > .gen-step:first-child .gen-step-title { margin-bottom: var(--space-3); }
}
@media (width >= 1100px) {
  .home-live .gen { display: grid; grid-template-columns: minmax(0, 1fr) minmax(calc(400 * var(--unit)), 31rem); grid-template-areas: "err out" "types out" "main out"; grid-template-rows: auto auto 1fr; }
  .home-live .gen-grid { display: contents; }
  .home-live .gen-form-error { grid-area: err; }
  .home-live .gen-types { grid-area: types; border-bottom: 0; padding: var(--space-6) var(--space-7) 0; }
  .home-live .gen-chips { gap: calc(6 * var(--unit)); }
  .home-live .gen-chips .chip { min-height: var(--tap-min); padding: 0 var(--space-3); font-size: var(--step--1); }
  .home-live .gen-chips .chip .type-glyph { margin-right: calc(5 * var(--unit)); }
  .home-live .gen-main { grid-area: main; padding: var(--space-5) var(--space-7) var(--space-7); }
  .home-live .gen-main > .gen-step:first-child > .gen-step-title { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .home-live :is([data-panel="url"], [data-panel="review"], [data-panel="instagram"]) .field { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: var(--space-3); align-items: baseline; }
  .home-live :is([data-panel="url"], [data-panel="review"], [data-panel="instagram"]) .field > * { grid-column: 1 / -1; }
  .home-live :is([data-panel="url"], [data-panel="instagram"]) .field > label { grid-column: 1; }
  .home-live :is([data-panel="url"], [data-panel="instagram"]) .field > .field-hint { grid-column: 2; justify-self: end; text-align: right; }
  .home-live .gen-create { padding-inline: var(--space-6); font-size: var(--step-0); }
  .home-live .gen-out { grid-area: out; display: block; border-top: 0; border-left: 1px solid var(--line); border-radius: 0 var(--radius-l) var(--radius-l) 0; padding: 0 0 var(--space-7); }
  .home-live .gen-out-in { top: var(--space-4); }
  .home-live .gen-out-in > :not(.gen-proof) { margin-inline: var(--space-6); }
  .home-live .gen-proof { max-width: none; margin: 0; padding: var(--space-8) var(--space-8) var(--space-5); border-radius: 0 var(--radius-l) 0 0; box-shadow: none; }
  .home-live .gen-line { margin-top: var(--space-4); }
  .home-live .gen-check { margin-top: var(--space-5); font-weight: 700; }
  /* The download column packs tight so the two columns end close together: formats as small pills three across, the size question on one line. */
  .home-live .gen-formats { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: calc(6 * var(--unit)); }
  .home-live .gen-formats .option { min-height: var(--tap-min); padding-block: var(--space-1); font-size: var(--step--1); }
  .home-live .gen-size-calc { margin-top: var(--space-4); grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; column-gap: var(--space-3); }
  .home-live .gen-size-calc > .field-hint { grid-column: auto; margin: 0; font-weight: 650; color: var(--text); }
  .home-live .gen-size-calc .field > label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .home-live .gen-size-calc .field input { min-height: var(--tap-min); }
  .home-live .gen-check { margin-top: var(--space-4); }
  .home-live .gen-proof { padding-top: var(--space-7); }
  .js:not([data-design="full"]) .home-live .gen-design[data-quick] .gen-tiles.is-large .gen-tile-grid { gap: var(--space-4); }
  .js:not([data-design="full"]) .home-live .gen-design[data-quick] .gen-tpl-lib { margin-top: var(--space-5); }
}
@media (width < 760px) {
  .home-live .gen-proof { max-width: calc(420 * var(--unit)); }
}
/* Wide hero, Quick state: the template looks sit under Design (one click applies a look, hover previews
   it), so the controls column carries something to pick beside the tall preview column. The tab strip
   stays behind "Customise". */
@media (width >= 1100px) {
  .js:not([data-design="full"]) .home-live .gen-design[data-quick] .gen-tabs { display: block; margin-top: var(--space-5); }
  .js:not([data-design="full"]) .home-live .gen-design[data-quick] .gen-tablist { display: none; }
  .js:not([data-design="full"]) .home-live .gen-design[data-quick] .gen-tabpanel:not([data-default]) { display: none; }
  .js:not([data-design="full"]) .home-live .gen-design[data-quick] .gen-tabpanel[data-default] { padding-top: 0; }
  /* Three even rows of five looks (fifteen templates up front, owner 2026-10-14), never a sideways rail here. */
  .js:not([data-design="full"]) .home-live .gen-design[data-quick] .gen-tiles.is-large .gen-tile-grid { grid-auto-flow: row; grid-template-columns: repeat(5, minmax(0, 1fr)); grid-auto-columns: auto; overflow: visible; padding: calc(6 * var(--unit)); margin: calc(-6 * var(--unit)); }
  .js:not([data-design="full"]) .home-live .gen-design[data-quick] .gen-tiles.is-large .tile { grid-column: auto; }
  .js:not([data-design="full"]) .home-live .gen-design[data-quick] .gen-tpl-lib { margin-top: var(--space-4); }
  /* Balance the two columns (owner UX 2026-10-12): the controls column fills to the height of the taller
     preview column so no empty white area sits under "Browse all". The design section grows to the bottom
     and its two tight, square rows of looks stay under the heading, with "Browse all" pinned to the foot of
     the column, level with the preview column. No layout shift: heights settle at first layout. */
  .home-live .gen-main { display: flex; flex-direction: column; }
  .js:not([data-design="full"]) .home-live .gen-design[data-quick] { flex: 1 1 auto; display: flex; flex-direction: column; }
  .js:not([data-design="full"]) .home-live .gen-design[data-quick] .gen-tabs { flex: 1 1 auto; display: flex; flex-direction: column; }
  .js:not([data-design="full"]) .home-live .gen-design[data-quick] .gen-tabpanel[data-default] { flex: 1 1 auto; display: flex; flex-direction: column; }
  .js:not([data-design="full"]) .home-live .gen-design[data-quick] .gen-tpl-lib { margin-top: auto; padding-top: var(--space-5); }
}
/* Inner experience pages (type, use case, industry, guide): the generator sits beside the page's answer,
   not in the home desk, so the Quick design panel left a tall white void under the controls column (owner
   UX v4 2026-10-14: measured ~380-494 px beside the preview column). The home fills that space with the
   template looks, but those run the design painter as they appear (lazy-browser contract): a type page
   must not pull the later chunk on load. So here the Quick design panel itself becomes a framed "design is
   ready" card that grows to the foot of the column, level with the preview, with the look preview and the
   Customise action centred in it. The tabs stay hidden, so no tile is ever in view and nothing loads early. */
@media (width >= 760px) {
  .xp-hero .gen-main { display: flex; flex-direction: column; }
  .js:not([data-design="full"]) .xp-hero .gen-design[data-quick] { flex: 1 1 auto; display: flex; flex-direction: column; }
  .js:not([data-design="full"]) .xp-hero .gen-design[data-quick] .gen-design-ready { display: flex; }
  /* The card carries its own line; the standalone quick line would duplicate it here. */
  .js:not([data-design="full"]) .xp-hero .gen-design[data-quick] .gen-quick-line { display: none; }
}
/* The quick-state "design is ready" card, shown only on the inner pages (a data-design-ready block the
   template renders). It carries a static look preview; never a template tile, so the design painter stays
   lazy. It grows to the foot of the controls column so no white void sits beside the preview. */
.gen-design-ready { display: none; container-type: size; flex: 1 1 auto; min-height: calc(500 * var(--unit)); flex-direction: column; align-items: center; justify-content: center; gap: var(--space-5); margin-top: var(--space-4); padding: var(--space-6); text-align: center; border: 1.5px dashed var(--line-input); border-radius: var(--radius-l); background: radial-gradient(90% 70% at 50% 16%, color-mix(in srgb, var(--brand) 12%, transparent), transparent 72%), var(--surface-sunken); }
.js[data-design="full"] .gen-design-ready, .gen-design:not([data-quick]) .gen-design-ready { display: none !important; }
/* The code is the hero of the card: the proof grows to fill the panel (a square sized to the card's own
   width and height via container units), so a tall card never leaves a ring of grey around a stamp. The
   floor keeps it substantial on the shortest cards; the cap by block size leaves room for the ready line. */
.gen-design-ready .gen-ready-art { height: max(calc(200 * var(--unit)), min(72%, 88cqi)); width: auto; max-width: 100%; aspect-ratio: 1; flex-shrink: 0; padding: var(--space-4); border-radius: var(--radius-m); background: var(--fixed-white); box-shadow: var(--paper-lift); }
.gen-design-ready .gen-ready-art svg, .gen-design-ready .gen-ready-art img { width: 100%; height: 100%; display: block; }
.gen-design-ready .gen-ready-text { margin: 0; max-width: 34ch; color: var(--text-muted); font-size: var(--step--1); }

/* ---------- the print act: the visitor's code on four printed things ----------
   Each thing prints the code's square (no frame) and its own call to action, in units of its own width
   (cqi), so the paper scales as one piece. A rail on phones; from 900 px a mat of neon-tinted paper with
   the things laid out on a grid (card over sign, tent over sticker): nothing overlaps at any width. */
.print-act { --p: 0; margin-top: var(--space-section); }
.print-stage { display: grid; gap: var(--space-7); }
.print-copy h2 { margin-bottom: var(--space-3); }
.print-copy p { color: var(--text-muted); max-width: 40ch; }
.print-status { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.print-whose { display: inline-flex; align-items: center; min-height: calc(28 * var(--unit)); padding: 0 var(--space-3); border-radius: var(--radius-pill); border: 1px solid var(--line-strong); color: var(--text); font-size: var(--step--1); font-weight: 650; }
.print-check { font-size: var(--step--1); color: var(--status-active-text); font-weight: 600; }
.print-check:empty { display: none; }
.print-back { font-weight: 600; }

.print-desk { list-style: none; margin: 0; padding: 0; }
.print-item { margin: 0; min-width: 0; container-type: inline-size; }
.print-obj { position: relative; background: var(--fixed-white); color: var(--paper-ink); box-shadow: var(--paper-shadow); }
.print-obj::after { content: ""; position: absolute; inset: 0; border-radius: inherit; box-shadow: var(--paper-lift); opacity: 0; pointer-events: none; }
.print-code { display: block; aspect-ratio: 1; }
.print-svg { display: block; width: 100%; height: auto; }
.print-cap { margin: var(--space-3) 0 0; font-size: var(--step--1); line-height: 1.3; color: var(--text-muted); }
.print-cap strong { color: var(--text); font-weight: 650; margin-right: var(--space-1); }
.print-cap span { white-space: nowrap; }
.print-cta { margin: 0; font-family: var(--font-display); font-weight: 650; line-height: 1.05; letter-spacing: -0.02em; color: var(--paper-ink); text-wrap: balance; }
.print-line { margin: 0; line-height: 1.25; color: var(--paper-ink); opacity: 0.66; text-wrap: balance; }

/* Business card, 85 x 55: name and role on the left, the code and "Save my contact" on the right. */
.print-card .print-obj { aspect-ratio: 85 / 55; border-radius: var(--radius-xs); display: grid; grid-template-columns: minmax(0, 1fr) 34cqi; align-items: center; gap: 6cqi; padding: 0 7cqi 0 8cqi; overflow: hidden; }
.print-card-text { display: grid; gap: 1.6cqi; align-content: center; min-width: 0; }
.print-mark { display: block; width: 9cqi; height: 1.8cqi; border-radius: var(--radius-pill); background: var(--neon); margin-bottom: 2.4cqi; }
.print-name { font-family: var(--font-display); font-weight: 650; font-size: 6.4cqi; line-height: 1.05; letter-spacing: -0.02em; }
.print-org { font-size: 3.6cqi; line-height: 1.3; opacity: 0.66; }
.print-url { margin-top: 3cqi; font-family: var(--font-mono); font-size: 3.4cqi; }
.print-card-code { display: grid; gap: 2cqi; justify-items: center; }
.print-card-code .print-code { width: 100%; }
.print-mini-cta { font-size: 3.2cqi; font-weight: 650; line-height: 1.1; text-align: center; white-space: nowrap; }

/* Table tent, 127 x 178, with its fold: the menu call on top, the code, one line under it. */
.print-tent .print-obj { aspect-ratio: 127 / 178; border-radius: 2px; display: grid; grid-template-rows: auto auto auto; align-content: center; justify-items: center; gap: 5cqi; padding: 15cqi 12cqi 9cqi; text-align: center; }
.print-fold { position: absolute; inset: 0 0 auto; height: 8cqi; background: linear-gradient(var(--neon), var(--neon)) 0 0 / 100% 100% no-repeat; }
.print-tent .print-cta { font-size: 9cqi; }
.print-tent .print-code { width: 72cqi; }
.print-tent .print-line { font-size: 5cqi; }

/* Square sticker, 50 x 50 mm, rounded corners: neon paper, the code on a white square, "Scan me". */
.print-sticker .print-obj { aspect-ratio: 1; border-radius: 14cqi; background: var(--neon); color: var(--neon-ink); display: grid; grid-template-rows: minmax(0, 1fr) auto; justify-items: center; align-items: center; gap: 3cqi; padding: 9cqi 9cqi 7cqi; }
.print-sticker .print-code { height: 100%; width: auto; max-width: 100%; padding: 4cqi; border-radius: 7cqi; background: var(--fixed-white); }
.print-sticker .print-svg { height: 100%; width: auto; }
.print-sticker .print-cta { font-size: 10cqi; color: var(--neon-ink); }

/* Sign rider, 610 x 152, on two posts: a "For sale" tag, the listing call, the code. */
.print-sign .print-obj { aspect-ratio: 610 / 152; border-radius: var(--radius-xs); border: 1.4cqi solid var(--paper-ink); display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 4cqi; padding: 0 2.6cqi 0 5cqi; }
.print-sign-text { display: grid; gap: 1.2cqi; justify-items: start; align-content: center; min-width: 0; }
.print-tag { display: inline-block; padding: 0.5cqi 1.6cqi; border-radius: var(--radius-pill); background: var(--neon); color: var(--neon-ink); font-size: 2.3cqi; font-weight: 700; letter-spacing: 0.02em; }
.print-sign .print-cta { font-size: 5cqi; }
.print-sign .print-line { font-size: 2.5cqi; }
.print-sign .print-code { width: 18.5cqi; }
.print-posts { display: block; height: var(--space-8); margin-inline: 18%; background: linear-gradient(90deg, var(--proof-mark) 0 calc(8 * var(--unit)), transparent calc(8 * var(--unit)) calc(100% - calc(8 * var(--unit))), var(--proof-mark) calc(100% - calc(8 * var(--unit)))); opacity: 0.8; }

/* Phones: a sideways rail of the four things, bottoms aligned. */
@media (width < 900px) {
  .print-desk { display: flex; align-items: end; gap: var(--space-6); overflow-x: auto; scroll-snap-type: x mandatory; overscroll-behavior-x: contain; padding: var(--space-6) var(--gutter) var(--space-6); margin-inline: calc(-1 * var(--gutter)); scroll-padding-inline: var(--gutter); background: radial-gradient(color-mix(in srgb, var(--brand) 8%, transparent) 1px, transparent 1.6px) 0 0 / calc(22 * var(--unit)) calc(22 * var(--unit)), radial-gradient(70% 60% at 50% 50%, var(--neon-glow), transparent 75%), linear-gradient(150deg, color-mix(in srgb, var(--surface-raised) 52%, var(--neon-tint)), var(--neon-tint)); }
  .print-item { flex: none; scroll-snap-align: start; width: calc(260 * var(--unit)); }
  .print-tent { width: calc(176 * var(--unit)); }
  .print-sticker { width: calc(170 * var(--unit)); }
  .print-sign { width: calc(320 * var(--unit)); }
}

@media (width >= 900px) {
  .print-stage { grid-template-columns: minmax(0, calc(280 * var(--unit))) minmax(0, 1fr); gap: var(--space-8); align-items: center; }
  /* The mat: neon-tinted paper with a soft glow; the things sit on two columns, card over sign, tent over sticker. */
  .print-desk {
    position: relative;
    isolation: isolate;
    display: grid;
    grid-template-columns: minmax(0, 1.62fr) minmax(0, 1fr);
    grid-template-rows: auto auto;
    column-gap: 7%;
    row-gap: var(--space-7);
    align-items: end;
    padding: var(--space-8) 6% var(--space-7);
    border-radius: var(--radius-l);
    /* A calm mat: a faint code-module dot grid over a soft glow, the flat green cooled toward the raised
       surface so it reads richer than a single green wash (owner 2026-10-14). Tokens only, both themes. */
    background:
      radial-gradient(color-mix(in srgb, var(--brand) 8%, transparent) 1px, transparent 1.6px) 0 0 / calc(22 * var(--unit)) calc(22 * var(--unit)),
      radial-gradient(60% 55% at 45% 45%, var(--neon-glow), transparent 72%),
      linear-gradient(150deg, color-mix(in srgb, var(--surface-raised) 52%, var(--neon-tint)), var(--neon-tint));
    box-shadow: inset 0 0 0 1px var(--line);
    perspective: calc(1400 * var(--unit));
  }
  .print-card { grid-column: 1; grid-row: 1; width: 86%; justify-self: start; }
  .print-tent { grid-column: 2; grid-row: 1; width: 74%; justify-self: center; }
  .print-sign { grid-column: 1; grid-row: 2; width: 100%; }
  .print-sticker { grid-column: 2; grid-row: 2; width: 66%; justify-self: center; align-self: end; }
  /* Each thing lies on the mat with its own tilt and a slight lean into the perspective; the lit one rises. */
  .print-obj { transform: translateY(var(--lift, 0px)) rotate(var(--tilt, 0deg)) rotateX(var(--lean, 3deg)) scale(var(--grow, 1)); transform-origin: 50% 80%; }
  .print-card .print-obj { --tilt: -2.5deg; }
  .print-tent .print-obj { --tilt: 1.5deg; --lean: 5deg; }
  .print-sticker .print-obj { --tilt: 5deg; }
  .print-sign .print-obj { --tilt: -0.8deg; --lean: 2deg; }
  .print-obj { transition: transform var(--dur-sheet) var(--ease-out); }
  .print-obj::after { transition: opacity var(--dur-sheet) var(--ease-out); }
  .print-act[data-active="0"] .print-card .print-obj,
  .print-act[data-active="1"] .print-tent .print-obj,
  .print-act[data-active="2"] .print-sticker .print-obj,
  .print-act[data-active="3"] .print-sign .print-obj { --lift: calc(-10 * var(--unit)); --grow: 1.03; --lean: 0deg; }
  .print-act[data-active="0"] .print-card .print-obj::after,
  .print-act[data-active="1"] .print-tent .print-obj::after,
  .print-act[data-active="2"] .print-sticker .print-obj::after,
  .print-act[data-active="3"] .print-sign .print-obj::after { opacity: 1; }
}
/* WEB-010c: the things settle into place as the act enters (home.js arms them only when the act starts
   below the first screen), then one at a time lights up in a loop. Transform and opacity only (CLS 0). */
@media (prefers-reduced-motion: no-preference) {
  .print-item { transition: transform 520ms var(--ease-out); }
  .print-item:nth-child(2) { transition-delay: 60ms; }
  .print-item:nth-child(3) { transition-delay: 120ms; }
  .print-item:nth-child(4) { transition-delay: 180ms; }
  .print-act[data-armed]:not([data-in]) .print-item { transform: translateX(calc(48 * var(--unit))); }
  .print-act[data-active] .print-obj { transition: transform var(--dur-sheet) var(--ease-out), box-shadow var(--dur-sheet) var(--ease-out); }
  .print-cap { transition: color var(--dur-sheet) var(--ease-out); }
}
/* Wide: each thing drifts up into its place with the scroll (--p, client/home/main.ts), a little turned. */
@media (width >= 900px) and (prefers-reduced-motion: no-preference) {
  .print-act[data-armed]:not([data-in]) { --q: calc(1 - var(--p, 0)); }
  .print-act[data-armed]:not([data-in]) .print-item { transition: transform 120ms linear; }
  .print-act[data-armed]:not([data-in]) .print-card { transform: translate(calc(var(--q) * 6%), calc(var(--q) * 22%)) rotate(calc(var(--q) * 5deg)); }
  .print-act[data-armed]:not([data-in]) .print-tent { transform: translate(calc(var(--q) * -8%), calc(var(--q) * 16%)) rotate(calc(var(--q) * -4deg)); }
  .print-act[data-armed]:not([data-in]) .print-sticker { transform: translate(calc(var(--q) * -14%), calc(var(--q) * 30%)) rotate(calc(var(--q) * -9deg)); }
  .print-act[data-armed]:not([data-in]) .print-sign { transform: translate(calc(var(--q) * 4%), calc(var(--q) * 26%)) rotate(calc(var(--q) * 2deg)); }
}
/* The highlighted thing on the rail (phones): lifted, with its name in the brand colour. */
@media (width < 900px) {
  .print-act[data-active="0"] .print-card .print-obj,
  .print-act[data-active="1"] .print-tent .print-obj,
  .print-act[data-active="2"] .print-sticker .print-obj,
  .print-act[data-active="3"] .print-sign .print-obj { transform: translateY(calc(-6 * var(--unit))); box-shadow: var(--paper-lift); }
}
.print-act[data-active="0"] .print-card .print-cap strong,
.print-act[data-active="1"] .print-tent .print-cap strong,
.print-act[data-active="2"] .print-sticker .print-cap strong,
.print-act[data-active="3"] .print-sign .print-cap strong { color: var(--brand-tint-text); }

/* ---------- the fixed vs editable story (WEB-010b): flyer, account, phone; home.js plays the steps ---------- */
.home-story .story-head { margin-bottom: var(--space-6); }
.story-head-row { display: flex; align-items: center; gap: var(--space-4); }
.story-head-row h2 { margin: 0; }
.loop-stop[hidden] { display: none; }
.loop-stop .is-play, .loop-stop[aria-pressed="true"] .is-hold { display: none; }
.loop-stop[aria-pressed="true"] .is-play { display: inline; }
.home-story .story-head p { color: var(--text-muted); max-width: 46ch; }
/* The stage: flyer, account, phone on a neon-tinted table. Every beat changes one thing, and each change
   is a crossfade (opacity and transform only); the lit part of the stage wears the one soft glow. */
/* Hero 3 stage: the same faint code-module motif over the glow, cooled toward the sunken surface so the
   panel reads richer than a single green wash (owner 2026-10-14). Tokens only, calm in both themes. */
.story-stage { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-5); align-items: center; padding: var(--space-6); border-radius: var(--radius-l); background: radial-gradient(color-mix(in srgb, var(--brand) 8%, transparent) 1px, transparent 1.6px) 0 0 / calc(22 * var(--unit)) calc(22 * var(--unit)), radial-gradient(50% 70% at 18% 50%, var(--neon-glow), transparent 70%), linear-gradient(135deg, var(--neon-tint), var(--surface-sunken) 70%); box-shadow: inset 0 0 0 1px var(--line); }
.story-flyer, .story-phone { margin: 0; display: grid; justify-items: center; gap: var(--space-3); }
.story-flyer figcaption, .story-phone figcaption, .story-app-label { font-size: var(--step--2); font-weight: 650; color: var(--text-muted); margin: 0; }
.story-paper { position: relative; display: grid; justify-items: center; gap: var(--space-2); width: min(100%, calc(200 * var(--unit))); padding: var(--space-5) var(--space-4) var(--space-4); background: var(--fixed-white); color: var(--paper-ink); border-radius: var(--radius-xs); box-shadow: var(--paper-shadow); transform: rotate(-2deg); }
.story-paper::after, .story-app::after, .story-screen::after { content: ""; position: absolute; inset: 0; border-radius: inherit; box-shadow: 0 0 0 calc(3 * var(--unit)) var(--neon), 0 0 calc(36 * var(--unit)) var(--neon-glow); opacity: 0; pointer-events: none; }
.story-paper-title { font-family: var(--font-display); font-weight: 650; font-size: var(--step-1); line-height: 1.1; }
.story-paper-bar { display: block; width: 70%; height: calc(6 * var(--unit)); border-radius: 2px; background: var(--neon); }
.story-code { position: relative; display: block; width: 78%; overflow: hidden; }
.story-code .demo-svg { display: block; width: 100%; height: auto; }
.story-scan { position: absolute; inset: 0; pointer-events: none; }
.story-scan::before { content: ""; position: absolute; inset: 0; opacity: 0; border-bottom: 2px solid var(--neon); background: linear-gradient(to bottom, transparent 55%, var(--neon-glow)); transform: translateY(-100%); }
.story-short { font-size: var(--step--2); color: var(--paper-ink); overflow-wrap: anywhere; text-align: center; }
.story-app { position: relative; grid-column: 1 / -1; grid-row: 2; display: grid; gap: var(--space-3); justify-items: start; padding: var(--space-5); border-radius: var(--radius-l); background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow-2); }
.story-link { position: relative; display: grid; margin: 0; padding: var(--space-3); width: 100%; border: 1px solid var(--line-input); border-radius: var(--radius-m); background: var(--surface-sunken); font-size: var(--step--1); overflow: hidden; }
.story-link > span, .story-screen > * { grid-area: 1 / 1; }
.story-link > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.story-change[hidden] { display: none; }
.story-phone { grid-column: 2; grid-row: 1; }
.story-screen { position: relative; display: grid; width: min(100%, calc(150 * var(--unit))); aspect-ratio: 9 / 17; padding: calc(10 * var(--unit)) calc(7 * var(--unit)); border-radius: calc(26 * var(--unit)); background: var(--device-bezel); box-shadow: var(--paper-lift); }
.story-screen > * { border-radius: calc(18 * var(--unit)); overflow: hidden; }
/* A white sheet under the layers, so a crossfade never shows the bezel through. */
.story-screen::before { content: ""; grid-area: 1 / 1; border-radius: calc(18 * var(--unit)); background: var(--fixed-white); }
/* The camera, up and about to scan: a viewfinder with a soft neon line. */
.story-cam { position: relative; display: grid; place-items: center; background: radial-gradient(80% 60% at 50% 45%, var(--neon-tint), var(--surface-sunken)); }
.story-finder { position: relative; width: 62%; aspect-ratio: 1; background:
  linear-gradient(var(--neon), var(--neon)) 0 0 / 22% 3px no-repeat, linear-gradient(var(--neon), var(--neon)) 0 0 / 3px 22% no-repeat,
  linear-gradient(var(--neon), var(--neon)) 100% 0 / 22% 3px no-repeat, linear-gradient(var(--neon), var(--neon)) 100% 0 / 3px 22% no-repeat,
  linear-gradient(var(--neon), var(--neon)) 0 100% / 22% 3px no-repeat, linear-gradient(var(--neon), var(--neon)) 0 100% / 3px 22% no-repeat,
  linear-gradient(var(--neon), var(--neon)) 100% 100% / 22% 3px no-repeat, linear-gradient(var(--neon), var(--neon)) 100% 100% / 3px 22% no-repeat; }
.story-finder::after { content: ""; position: absolute; inset: 10% 10% 14%; background: linear-gradient(var(--neon), var(--neon)) 0 0 / 100% 2px no-repeat, linear-gradient(var(--neon-glow), transparent) 0 0 / 100% calc(14 * var(--unit)) no-repeat; }
.story-page { display: grid; align-content: start; gap: var(--space-2); padding: var(--space-3); color: var(--paper-ink); }
.story-page.story-old { background: linear-gradient(170deg, color-mix(in srgb, var(--meter-warn) 40%, var(--fixed-white)), var(--fixed-white) 65%); }
.story-page.story-new { background: linear-gradient(170deg, color-mix(in srgb, var(--neon) 70%, var(--fixed-white)), var(--fixed-white) 65%); }
.story-page strong { font-family: var(--font-display); font-size: var(--step-1); line-height: 1.1; }
.story-page-url { font-size: calc(10 * var(--unit)); opacity: 0.75; overflow-wrap: anywhere; }
.story-lines { display: block; height: calc(64 * var(--unit)); background: repeating-linear-gradient(to bottom, color-mix(in srgb, var(--paper-ink) 18%, transparent) 0 calc(6 * var(--unit)), transparent calc(6 * var(--unit)) calc(16 * var(--unit))); }
/* What shows: the account's link (data-dest) and the phone (data-page: its camera or one of the pages).
   Hidden layers stay in the grid cell, so nothing moves (CLS 0). */
.story-link > span, .story-screen > * { opacity: 0; visibility: hidden; }
.home-story[data-dest="old"] .story-link .story-old, .home-story[data-dest="new"] .story-link .story-new,
.home-story[data-page="cam"] .story-cam, .home-story[data-page="old"] .story-page.story-old, .home-story[data-page="new"] .story-page.story-new { opacity: 1; visibility: visible; }
.story-steps { list-style: none; margin: var(--space-5) 0 0; padding: 0; display: grid; gap: var(--space-3); }
.story-step { display: flex; align-items: flex-start; gap: var(--space-3); width: 100%; height: 100%; min-height: var(--tap-min); padding: var(--space-3) var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); color: var(--text); font: inherit; font-weight: 600; text-align: left; cursor: pointer; }
.story-step:hover { border-color: var(--brand); }
.story-step:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
.story-num { flex: none; display: grid; place-items: center; width: calc(26 * var(--unit)); height: calc(26 * var(--unit)); border-radius: 50%; background: var(--surface-sunken); font-size: var(--step--1); font-weight: 750; }
.home-story[data-step="1"] [data-story-step="1"], .home-story[data-step="2"] [data-story-step="2"], .home-story[data-step="3"] [data-story-step="3"], .home-story[data-step="4"] [data-story-step="4"] { border-color: var(--brand); background: var(--brand-tint); color: var(--brand-tint-text); }
.home-story[data-step="1"] [data-story-step="1"] .story-num, .home-story[data-step="2"] [data-story-step="2"] .story-num, .home-story[data-step="3"] [data-story-step="3"] .story-num, .home-story[data-step="4"] [data-story-step="4"] .story-num { background: var(--neon); color: var(--neon-ink); }
.story-modes { list-style: none; margin: var(--space-6) 0 0; padding: 0; display: grid; gap: var(--space-4); }
.story-mode { padding: var(--space-4) 0 0; border-top: 2px solid var(--line-strong); font-size: var(--step-0); line-height: var(--leading-snug); }
.story-mode.is-editable { border-top-color: var(--brand); }
.story-mode strong { display: block; font-family: var(--font-display); font-size: var(--step-1); margin-bottom: var(--space-1); }
@media (width >= 760px) {
  .story-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .story-modes { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-7); }
}
@media (width >= 1100px) { .story-steps { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (width >= 900px) {
  .story-stage { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr) minmax(0, 1fr); padding: var(--space-8); gap: var(--space-7); }
  .story-app { grid-column: 2; grid-row: 1; }
  .story-phone { grid-column: 3; }
}
/* The loop's motion: soft crossfades both ways (600 ms, the story beat), a lift and glow on the part that
   acts, the scan line (data-on: only while the story is on screen) on beats 2 and 4, the new link wiping in like typing on beat 3. */
@media (prefers-reduced-motion: no-preference) {
  .home-story[data-loop] .story-link > span, .home-story[data-loop] .story-screen > * { transition: opacity 600ms var(--ease-in-out), transform 600ms var(--ease-in-out), visibility 0s linear 600ms; }
  .home-story[data-loop][data-dest="old"] .story-link .story-old, .home-story[data-loop][data-dest="new"] .story-link .story-new,
  .home-story[data-loop][data-page="cam"] .story-cam, .home-story[data-loop][data-page="old"] .story-page.story-old, .home-story[data-loop][data-page="new"] .story-page.story-new { transition-delay: 0s; }
  .story-screen > * { transform: scale(0.97); }
  .home-story[data-page="cam"] .story-cam, .home-story[data-page="old"] .story-page.story-old, .home-story[data-page="new"] .story-page.story-new { transform: none; }
  .story-link > span { transform: translateY(40%); }
  .home-story[data-dest="old"] .story-link .story-old, .home-story[data-dest="new"] .story-link .story-new { transform: none; }
  .home-story[data-loop][data-step="3"] .story-link > span { transition-duration: 380ms, 380ms, 0s; }
  .home-story[data-loop][data-step="3"][data-dest="old"] .story-link .story-old, .home-story[data-loop][data-step="3"][data-dest="new"] .story-link .story-new { animation: story-type 900ms steps(14, end) 200ms both; }
  .story-paper { transition: transform 600ms var(--ease-out), box-shadow 600ms var(--ease-out); }
  .story-paper::after, .story-app::after, .story-screen::after { transition: opacity 600ms var(--ease-in-out); }
  .home-story[data-on][data-step="1"] .story-paper { transform: rotate(-2deg) translateY(calc(-6 * var(--unit))); box-shadow: var(--paper-lift); }
  .home-story[data-on][data-step="1"] .story-paper::after, .home-story[data-on][data-step="3"] .story-app::after,
  .home-story[data-on][data-step="2"] .story-screen::after, .home-story[data-on][data-step="4"] .story-screen::after { opacity: 0.85; }
  .home-story[data-on][data-step="2"] .story-scan::before, .home-story[data-on][data-step="4"] .story-scan::before { animation: gen-sweep 900ms var(--ease-in-out); }
  .home-story[data-on][data-page="cam"] .story-finder::after { animation: story-finder 1100ms var(--ease-in-out) 2 alternate; }
  .story-step { transition: background-color var(--dur-hover) var(--ease-out), border-color var(--dur-hover) var(--ease-out), color var(--dur-hover) var(--ease-out); }
}
@keyframes story-type { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes story-finder { from { transform: translateY(0); } to { transform: translateY(100%); } }

/* ---------- how it works: a quiet strip ---------- */
.home-jobs .section-head { margin-bottom: var(--space-4); }
.jobs { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(240 * var(--unit))), 1fr)); }
.job { display: grid; gap: var(--space-2); padding: var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-l); background: var(--surface); transition: border-color var(--dur-hover) var(--ease-out), box-shadow var(--dur-hover) var(--ease-out), transform var(--dur-hover) var(--ease-out); }
.job:hover { border-color: var(--brand); box-shadow: var(--shadow-2); }
@media (prefers-reduced-motion: no-preference) { .job:hover { transform: translateY(-2px); } }
.job a { display: grid; grid-template-columns: calc(56 * var(--unit)) minmax(0, 1fr); column-gap: var(--space-4); align-items: center; min-height: var(--target-min); font-weight: 700; color: var(--text); text-decoration: none; }
.job a:hover .job-title { text-decoration: underline; text-underline-offset: 3px; }
.job a:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); border-radius: var(--radius-s); }
.job-thumb { display: grid; place-items: center; aspect-ratio: 1; border-radius: var(--radius-m); background: var(--neon-tint); }
.job-paper { display: block; width: 68%; padding: calc(3 * var(--unit)); border-radius: 2px; background: var(--fixed-white); box-shadow: var(--paper-shadow); transform: rotate(-4deg); }
.job-paper .print-svg { display: block; width: 100%; height: auto; }
.job-title { font-family: var(--font-display); font-size: var(--step-0); line-height: var(--leading-snug); }
.job p { margin: 0; padding-left: calc(56 * var(--unit) + var(--space-4)); font-size: var(--step--1); color: var(--text-muted); }
/* Home: the six jobs as an even grid (three by two wide, two by three on tablets), never an orphan. */
@media (width >= 760px) { .home-jobs .jobs { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (width >= 1100px) { .home-jobs .jobs { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.home-how .section-head { margin-bottom: var(--space-4); }
.home-how .section-head h2 { font-size: var(--step-2); }
.home-how .steps { margin: 0; gap: 0; padding: var(--space-3); background: var(--surface-sunken); border-radius: var(--radius-m); }
.home-how .steps > li { grid-template-columns: auto 1fr; gap: 0 var(--space-3); padding: var(--space-3) var(--space-4); align-items: start; }
.home-how .steps > li::before { grid-row: span 2; width: calc(32 * var(--unit)); height: calc(32 * var(--unit)); margin: 0; font-size: var(--step-0); }
.home-how .steps h3 { font-size: var(--step-0); }
.home-how .steps p { font-size: var(--step--1); }
@media (width >= 760px) { .home-how .steps > li + li { border-left: 1px solid var(--line); } }
@media (width < 760px) { .home-how .steps > li + li { border-top: 1px solid var(--line); } }

/* ---------- what you get: four quiet cards, 4 / 2 / 1 columns, never an orphan ---------- */
.home-pillars .section-head { margin-bottom: var(--space-5); }
.home-pillars .pillars { display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr); }
.home-pillars .pillar { display: grid; grid-template-rows: auto auto 1fr; align-content: start; border: 1px solid var(--line); border-top: 1px solid var(--line); border-radius: var(--radius-l); background: var(--surface); padding: var(--space-3) var(--space-3) var(--space-5); }
.home-pillars .pillar h3 { margin: var(--space-4) var(--space-3) var(--space-1); font-size: var(--step-1); }
.home-pillars .pillar p { margin: 0 var(--space-3); font-size: var(--step--1); line-height: var(--leading-snug); max-width: 34ch; }
/* The small picture on each tile: a neon-tinted panel, the same height on every tile. */
.pillar-art { position: relative; display: grid; place-items: center; place-content: center; grid-auto-flow: column; gap: var(--space-4); height: calc(124 * var(--unit)); border-radius: var(--radius-m); background: radial-gradient(70% 80% at 50% 60%, var(--neon-glow), transparent 75%), var(--neon-tint); overflow: hidden; }
.pa-paper { position: relative; display: grid; place-items: center; width: calc(72 * var(--unit)); aspect-ratio: 1; padding: calc(8 * var(--unit)); border-radius: var(--radius-xs); background: var(--fixed-white); box-shadow: var(--paper-shadow); transform: rotate(-4deg); }
.pa-paper svg { display: block; width: 100%; height: 100%; fill: var(--paper-ink); }
.is-brand .pa-paper svg { fill: var(--brand); }
.pa-logo { position: absolute; width: calc(16 * var(--unit)); aspect-ratio: 1; border-radius: var(--radius-xs); background: var(--neon); box-shadow: 0 0 0 calc(3 * var(--unit)) var(--fixed-white); }
.pa-swatches { display: grid; gap: var(--space-2); }
.pa-swatches span { display: block; width: calc(20 * var(--unit)); aspect-ratio: 1; border-radius: 50%; box-shadow: 0 0 0 1px var(--line), var(--shadow-1); }
.pa-swatches span:nth-child(1) { background: var(--neon); }
.pa-swatches span:nth-child(2) { background: var(--brand); }
.pa-swatches span:nth-child(3) { background: var(--paper-ink); }
.pa-url { display: inline-flex; align-items: center; gap: var(--space-2); max-width: 96%; padding: var(--space-2) var(--space-3); border-radius: var(--radius-pill); background: var(--surface); box-shadow: var(--shadow-2), inset 0 0 0 1px var(--line); font-size: var(--step--1); font-weight: 650; color: var(--text); white-space: nowrap; overflow: hidden; }
.pa-url .mono { overflow: hidden; text-overflow: ellipsis; }
.pa-link { display: none; width: calc(28 * var(--unit)); height: calc(28 * var(--unit)); fill: none; stroke: var(--brand); stroke-width: 1.8; stroke-linecap: round; }
.pa-dot { flex: none; width: calc(10 * var(--unit)); aspect-ratio: 1; border-radius: 50%; background: var(--neon); box-shadow: 0 0 calc(10 * var(--unit)) var(--neon-glow); }
.pa-paper.is-print { transform: rotate(3deg); }
.pa-check { position: absolute; right: calc(50% - calc(58 * var(--unit))); bottom: calc(18 * var(--unit)); display: grid; place-items: center; width: calc(34 * var(--unit)); aspect-ratio: 1; border-radius: 50%; background: var(--neon); color: var(--neon-ink); box-shadow: 0 0 0 calc(3 * var(--unit)) var(--surface), 0 0 calc(18 * var(--unit)) var(--neon-glow); }
.pa-check svg { width: 60%; height: 60%; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.pa-seg { display: inline-flex; gap: 2px; padding: 3px; border-radius: var(--radius-pill); background: var(--surface); box-shadow: var(--shadow-2), inset 0 0 0 1px var(--line); font-size: var(--step--2); font-weight: 650; color: var(--text-muted); }
.pa-seg span { padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill); white-space: nowrap; }
.pa-seg .is-on { background: var(--neon); color: var(--neon-ink); }
/* Phones: each tile is a row, the picture a small square beside its title and line. */
@media (width < 600px) {
  .home-pillars .pillar { grid-template-columns: calc(104 * var(--unit)) minmax(0, 1fr); grid-template-rows: auto 1fr; column-gap: var(--space-2); padding: var(--space-3); align-items: start; }
  .home-pillars .pillar-art { grid-row: 1 / span 2; height: auto; aspect-ratio: 1; gap: var(--space-2); }
  .home-pillars .pillar h3 { margin: var(--space-2) var(--space-2) var(--space-1); font-size: var(--step-0); }
  .home-pillars .pillar p { margin: 0 var(--space-2); }
  .home-pillars .pa-paper { width: calc(52 * var(--unit)); padding: calc(5 * var(--unit)); }
  .home-pillars .pa-swatches span { width: calc(14 * var(--unit)); }
  .home-pillars .pa-url { padding: var(--space-2); }
  .home-pillars .pa-url .mono, .home-pillars .pa-dot { display: none; }
  .home-pillars .pa-link { display: block; }
  .home-pillars .pa-check { right: calc(50% - calc(42 * var(--unit))); bottom: calc(12 * var(--unit)); width: calc(26 * var(--unit)); }
  .home-pillars .pa-seg { flex-direction: column; border-radius: var(--radius-m); }
  .home-pillars .pa-seg span { padding: 1px var(--space-2); text-align: center; }
}
@media (width >= 600px) { .home-pillars .pillars { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (width >= 1100px) { .home-pillars .pillars { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* ---------- proof: a receipt ---------- */
.home-proof { padding-block: var(--space-6); border-block: 1px solid var(--line); }
.home-proof .proof-lines { gap: var(--space-5) var(--space-7); grid-template-columns: minmax(0, 1fr); }
.home-proof .proof-lines li { display: grid; gap: var(--space-1); align-content: start; }
.home-proof .proof-lines strong { font-family: var(--font-display); font-size: var(--step-3); font-weight: 650; letter-spacing: -0.02em; line-height: var(--leading-tight); }
.home-proof .proof-lines span { color: var(--text-muted); font-size: var(--step-0); }
.home-proof .proof-lines a { font-size: var(--step--1); font-weight: 650; justify-self: start; }
@media (width >= 760px) { .home-proof .proof-lines { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* ---------- pricing: five plan cells, Pro highlighted, then the one-time passes (owner 2026-10-14) ---------- */
.home-pricing .price-row { gap: var(--space-3); grid-template-columns: minmax(0, 1fr); margin-bottom: var(--space-4); }
.home-pricing .price-cell { position: relative; display: grid; grid-template-rows: auto auto 1fr; gap: var(--space-1); padding: var(--space-5) var(--space-4); border-radius: var(--radius-l); }
.home-pricing .price-cell.is-pick { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand), var(--shadow-2); background: linear-gradient(180deg, var(--neon-tint), var(--surface) calc(160 * var(--unit))); }
.home-pricing .price-cell .price-name { font-size: var(--step-0); font-weight: 650; }
.home-pricing .price-cell .price-amount { font-size: var(--step-3); font-weight: 650; letter-spacing: -0.02em; }
.home-pricing .price-cell .price-amount span { font-size: var(--step--2); font-weight: 400; color: var(--text-muted); margin-left: var(--space-1); }
.home-pricing .price-note { font-size: var(--step--2); color: var(--text-muted); line-height: 1.4; }
.price-pick { position: absolute; top: calc(-1 * var(--space-3)); left: var(--space-4); margin: 0; padding: 0 var(--space-3); min-height: calc(26 * var(--unit)); display: inline-flex; align-items: center; border-radius: var(--radius-pill); background: var(--neon); color: var(--neon-ink); font-size: var(--step--2); font-weight: 700; }
/* The two one-time passes, side by side under the plan cells. */
.pass-teaser-row { list-style: none; margin: 0 0 var(--space-4); padding: 0; display: grid; gap: var(--space-3); grid-template-columns: minmax(0, 1fr); }
.pass-teaser { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-2); padding: var(--space-3) var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-m); font-size: var(--step--1); background: var(--surface); }
.pass-teaser strong { color: var(--text); font-weight: 650; }
.pass-teaser span { color: var(--text-muted); font-size: var(--step--2); }
.price-line { margin: 0; font-size: var(--step--1); color: var(--text-muted); }
.price-line strong { color: var(--text); font-weight: 650; }
@media (width >= 600px) { .pass-teaser-row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (width >= 760px) { .home-pricing .price-row { grid-template-columns: repeat(5, minmax(0, 1fr)); } }

/* Questions: the open cards and the accordion share one width and one left edge. */
.home-faq .faq { max-width: none; }

/* ---------- the close: a field, not a slogan ---------- */
.band[data-close] { align-items: center; }
.close-form { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
.close-form input[type="text"] { flex: 1 1 12rem; min-height: var(--tap-large); background: var(--fixed-white); color: var(--paper-ink); border-color: var(--island-line); }
.close-form input::placeholder { color: var(--island-muted); }
.close-secondary { flex-basis: 100%; font-weight: 600; }
@media (width >= 900px) { .band[data-close] { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); } }
/* Sections below the fold reveal once as they enter (data-reveal, client/home/main.ts): a slide only, never a
   fade, so their text keeps full contrast while it waits (axe, screen readers, crawlers, full-page captures). */
@media (prefers-reduced-motion: no-preference) {
  [data-reveal="armed"] { transform: translateY(calc(18 * var(--unit))); }
  [data-reveal="in"] { transform: none; transition: transform 520ms var(--ease-out); }
}
/* ==================== home:end ==================== */

/* ---------- motion ---------- */
.theme-switching, .theme-switching *, .theme-switching *::before, .theme-switching *::after {
  transition: background-color var(--duration-theme) var(--ease-out), color var(--duration-theme) var(--ease-out), border-color var(--duration-theme) var(--ease-out) !important;
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
  .loading-eye { animation: none; }
  .theme-switching, .theme-switching *, .theme-switching *::before, .theme-switching *::after { transition: none !important; }
}
.gen [hidden] { display: none !important; }

/* ==================== app:start ====================
   The signed-in app (src/app-ui, views/app): shell, Home, library, create flow, editor.
   Tokens only (no colour literals). The idea: the app is the press room behind the generator.
   The left rail is the sheet margin, the current item carries a registration mark, recent codes sit
   on a contact sheet, and the editor keeps the proof with crop marks beside every tab. */

/* ---------- shell ---------- */
.app-body { min-height: 100vh; }
.app-header { position: sticky; top: 0; z-index: 25; background: var(--bg); border-bottom: 1px solid var(--line); }
.app-bar { display: flex; align-items: center; gap: var(--space-3); min-height: var(--bar-height); padding-inline: var(--gutter); }
.app-brand { flex: none; }
.app-switch { position: relative; min-width: 0; }
.app-switch-current { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--tap-min); max-width: 32ch; margin: 0; padding: 0 var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--surface); font-weight: 650; cursor: pointer; list-style: none; }
.app-switch-current::-webkit-details-marker { display: none; }
.app-switch-current.is-static { cursor: default; border-color: transparent; background: transparent; }
.app-switch-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.app-switch > summary::after { content: ""; flex: none; width: calc(7 * var(--unit)); height: calc(7 * var(--unit)); border-right: 2px solid var(--text-muted); border-bottom: 2px solid var(--text-muted); transform: rotate(45deg) translateY(-2px); }
.app-tools { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; }
.app-header .bell { position: relative; display: inline-grid; place-items: center; width: var(--tap-min); height: var(--tap-min); border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--surface); color: var(--text); }
.app-header .bell:hover { background: var(--surface-sunken); }
.app-header .bell-count { position: absolute; top: calc(-6 * var(--unit)); right: calc(-6 * var(--unit)); min-width: calc(20 * var(--unit)); height: calc(20 * var(--unit)); padding: 0 var(--space-1); border-radius: var(--radius-pill); background: var(--brand-fill); color: var(--on-brand); font-size: var(--step--2); font-weight: 700; line-height: calc(20 * var(--unit)); text-align: center; }
.app-account { position: relative; }
.app-account > summary { list-style: none; }
.app-account > summary::-webkit-details-marker { display: none; }
.app-pop { position: absolute; z-index: 40; top: calc(100% + var(--space-2)); left: 0; min-width: calc(240 * var(--unit)); padding: var(--space-2); background: var(--surface-raised); border: 1px solid var(--line-strong); border-radius: var(--radius-m); box-shadow: var(--shadow-3); }
.app-pop-end { left: auto; right: 0; }
.app-pop-title { margin: var(--space-2) var(--space-3); font-weight: 650; overflow-wrap: anywhere; }
.app-pop-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-1); }
.app-pop-item { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: var(--space-3); min-height: var(--tap-min); padding: 0 var(--space-3); border: 0; border-radius: var(--radius-s); background: none; color: var(--text); font: inherit; text-align: left; text-decoration: none; cursor: pointer; }
.app-pop-item:hover { background: var(--surface-sunken); color: var(--text); }
.app-pop-item[aria-current="true"] { font-weight: 700; }
.app-pop-item[aria-current="true"]::after { content: ""; width: calc(10 * var(--unit)); height: calc(10 * var(--unit)); border-radius: 50%; background: var(--brand-fill); }
.app-nav-toggle { display: none; }

/* App density (agent-rails style): layout-only locals scoped to the signed-in shell so the marketing
   site, which never carries .app-body, is untouched. Chrome inside the app sizes to these for a tighter
   feel (both are colourless; tests/design/tokens.test.ts whitelists them). */
.app-body {
  --app-nav-item-h: calc(36 * var(--unit));  /* ~29px: compact nav row */
  --app-panel-pad: var(--space-5);           /* panel card padding, tightened on wider screens below */
}
@media (width >= 600px) { .app-body { --app-panel-pad: var(--space-4); } }

.app-frame { display: grid; grid-template-columns: calc(232 * var(--unit)) minmax(0, 1fr); min-height: calc(100vh - var(--bar-height)); }
.app-nav { position: sticky; top: var(--bar-height); align-self: start; max-height: calc(100vh - var(--bar-height)); overflow-y: auto; background: var(--surface-sunken); border-right: 1px solid var(--line); padding: var(--space-4) var(--space-3); }
/* Grouped sections: a small muted label over a compact list, with clear air between groups. */
.app-nav-group + .app-nav-group { margin-top: var(--space-4); }
.app-nav-label { margin: 0 0 var(--space-1); padding: 0 var(--space-3); font-size: var(--step--2); font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-muted); }
.app-nav-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.app-nav-list a { display: flex; align-items: center; gap: var(--space-2); min-height: var(--app-nav-item-h); padding: 0 var(--space-3); border-radius: var(--radius-s); color: var(--text-muted); font-size: var(--step--1); font-weight: 600; text-decoration: none; }
.app-nav-list a:hover { background: var(--surface); color: var(--text); }
.app-nav-ico { display: inline-flex; flex: none; color: var(--text-muted); }
.app-nav-ico .nav-icon { width: calc(22 * var(--unit)); height: calc(22 * var(--unit)); }
.app-nav-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The current item: a tinted pill in the brand, no marker glyph. */
.app-nav-list a[aria-current="page"] { background: var(--brand-tint); color: var(--brand-tint-text); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--brand) 28%, transparent); }
.app-nav-list a[aria-current="page"] .app-nav-ico { color: var(--brand); }
/* Billing status pill: a trial countdown, a payment problem, or a near-limit mark. */
.app-nav-badge { margin-left: auto; flex: none; display: inline-grid; place-items: center; min-width: calc(22 * var(--unit)); height: calc(22 * var(--unit)); padding: 0 var(--space-1); border-radius: var(--radius-pill); font-size: var(--step--2); font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1; }
.app-nav-badge.is-info { background: var(--brand-tint); color: var(--brand-tint-text); }
.app-nav-badge.is-warn { background: var(--status-trial-bg); color: var(--status-trial-text); }
.app-nav-badge.is-danger { background: var(--danger-solid); color: var(--fixed-white); }
.app-nav-note { margin: var(--space-4) var(--space-3) 0; color: var(--text-muted); }
.app-main { min-width: 0; padding: var(--space-7) var(--gutter) var(--space-section); }
.app-main > :first-child { margin-top: 0; }
@media (width < 900px) {
  .app-frame { grid-template-columns: minmax(0, 1fr); }
  .app-nav { position: static; max-height: none; overflow: visible; border-right: 0; border-bottom: 1px solid var(--line); padding: var(--space-2) var(--gutter); display: flex; gap: var(--space-4); overflow-x: auto; scrollbar-width: thin; }
  .app-nav-group { display: flex; align-items: center; gap: var(--space-1); }
  .app-nav-group + .app-nav-group { margin-top: 0; }
  .app-nav-label { display: none; }
  .app-nav-list { grid-auto-flow: column; grid-auto-columns: max-content; }
}
@media (width >= 900px) {
  /* The nav column's fill and its divider run the full page height (SnapRender look). They are painted on
     the grid, not on the sticky nav, so the nav inside can stay just as tall as its links while the colour
     still reaches the bottom of a tall page. */
  .app-frame { background: linear-gradient(to right, var(--surface-sunken) 0 calc(232 * var(--unit) - 1px), var(--line) calc(232 * var(--unit) - 1px) calc(232 * var(--unit)), transparent calc(232 * var(--unit))); }
  .app-nav { background: transparent; border-right: 0; }
}
@media (width < 760px) {
  .app-bar { gap: var(--space-2); }
  .app-switch-current { max-width: 40vw; }
  .js .app-nav-toggle { display: inline-grid; }
  .js .app-nav { display: none; }
  .js .app-nav[data-open] { display: flex; flex-direction: column; gap: var(--space-4); position: fixed; inset: var(--bar-height) 0 0 0; z-index: 30; overflow-y: auto; padding: var(--space-5) var(--gutter); background: var(--bg); }
  .js .app-nav[data-open] .app-nav-group { flex-direction: column; align-items: stretch; gap: 2px; }
  .js .app-nav[data-open] .app-nav-label { display: block; }
  .js .app-nav[data-open] .app-nav-list { grid-auto-flow: row; }
  .js .app-nav[data-open] .app-nav-list a { min-height: var(--tap-large); font-size: var(--step-0); }
  .app-main { padding-top: var(--space-6); }
}

/* ---------- page heads and shared bits ---------- */
.app-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3) var(--space-5); margin-bottom: var(--space-6); }
.app-head h1 { font-size: var(--step-4); margin: 0; min-width: 0; overflow-wrap: anywhere; }
.section-bar { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-2) var(--space-4); margin-bottom: var(--space-4); }
.section-bar h2, .home-side h2 { font-size: var(--step-1); font-family: var(--font-text); font-weight: 700; letter-spacing: 0; margin: 0; }
.alert-action { margin: calc(-1 * var(--space-2)) 0 var(--space-4) var(--space-5); font-weight: 650; }
.label-line { font-weight: 700; margin: 0 0 var(--space-2); }
.read-value { margin: 0 0 var(--space-3); overflow-wrap: anywhere; white-space: pre-wrap; }
.busy[hidden] { display: none; }
.inline-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3); margin-bottom: var(--space-4); }
.inline-form .field { flex: 1 1 calc(220 * var(--unit)); }
.inline-fields { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(160 * var(--unit))), 1fr)); }
.field-narrow { max-width: calc(140 * var(--unit)); }

/* Mode badge: a filled square for fixed, a ring for editable (shape as well as colour). */
.mode-badge { display: inline-flex; align-items: center; gap: var(--space-2); min-height: calc(26 * var(--unit)); padding: 2px var(--space-3) 2px var(--space-2); border: 1px solid var(--line-strong); border-radius: var(--radius-pill); background: var(--surface); color: var(--text); font-size: var(--step--1); font-weight: 650; line-height: 1.2; white-space: nowrap; }
.mode-badge::before { content: ""; flex: none; width: calc(10 * var(--unit)); height: calc(10 * var(--unit)); }
.mode-fixed::before { background: var(--text); border-radius: 2px; }
.mode-editable::before { border: 2px solid var(--brand); border-radius: 50%; }
/* Compact variant for dense lists (the library's one-line status): a smaller pill, same shapes. */
.badge.is-compact, .mode-badge.is-compact { min-height: calc(22 * var(--unit)); padding: 1px var(--space-2); gap: var(--space-1); font-size: var(--step--2); font-weight: 600; }
.badge.is-compact::before, .mode-badge.is-compact::before { width: calc(8 * var(--unit)); height: calc(8 * var(--unit)); }

.type-icon { display: inline-grid; place-items: center; width: calc(28 * var(--unit)); height: calc(28 * var(--unit)); border-radius: var(--radius-s); background: var(--surface-sunken); color: var(--text-muted); flex: none; }

/* Plan locks (UX-028): one quiet row per panel for free and trial; a closed label for payers. */
.lock-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3); margin: 0 0 var(--space-5); padding: var(--space-3) var(--space-4); border: 1px dashed var(--line-input); border-radius: var(--radius-m); background: var(--surface); }
.lock-row-text { margin: 0; font-size: var(--step--1); }
.lock-label { margin: 0 0 var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--surface-sunken); }
.lock-label summary { display: flex; align-items: center; gap: var(--space-2); min-height: var(--tap-min); padding: 0 var(--space-4); color: var(--text-muted); font-weight: 600; cursor: pointer; list-style: none; }
.lock-label summary::-webkit-details-marker { display: none; }
.lock-icon { flex: none; width: calc(12 * var(--unit)); height: calc(10 * var(--unit)); margin-top: var(--space-1); border: 2px solid var(--text-muted); border-radius: 2px; position: relative; }
.lock-icon::before { content: ""; position: absolute; left: 1px; bottom: 100%; width: calc(6 * var(--unit)); height: calc(6 * var(--unit)); border: 2px solid var(--text-muted); border-bottom: 0; border-radius: var(--radius-xs) var(--radius-xs) 0 0; }
.lock-label-text { margin: 0; padding: 0 var(--space-4) var(--space-3); color: var(--text-muted); font-size: var(--step--1); }

/* Confirmation with Undo: stays until the page changes. */
.flash { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); margin: 0 0 var(--space-5); padding: var(--space-3) var(--space-4); border-radius: var(--radius-m); background: var(--toast-bg); color: var(--toast-text); box-shadow: var(--shadow-2); }
.flash-text { margin: 0; font-weight: 650; flex: 1 1 calc(260 * var(--unit)); }
.flash-live .flash-text::before { content: ""; display: inline-block; width: calc(10 * var(--unit)); height: calc(10 * var(--unit)); margin-right: var(--space-2); border-radius: 50%; background: var(--brand-fill); vertical-align: 0.05em; }
.flash-undo { margin: 0; }
.flash .button.ghost { color: var(--toast-text); border-color: var(--toast-text); background: transparent; }
.flash .button.ghost:hover { background: var(--toast-text); color: var(--toast-bg); }
.flash :focus-visible { outline-color: var(--toast-text); }
/* UX-024: the toast slides in once; with reduced motion it simply appears. */
@media (prefers-reduced-motion: no-preference) {
  .flash { animation: flash-in 260ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }
  @keyframes flash-in { from { opacity: 0; transform: translateY(calc(-6 * var(--unit))); } to { opacity: 1; transform: none; } }
}

/* Code previews: a plain soft frame (the contact-sheet crop marks read as artefacts on a card). */
.code-thumb { position: relative; display: grid; place-items: center; padding: var(--space-1); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-s); }
.code-list.is-grid .code-thumb { padding: var(--space-2); }
/* Small crop marks around thumbnails: the proof frame at contact-sheet scale (home recent codes). */
.contact-proof {
  --tick: var(--line-strong);
  position: relative;
  display: grid;
  place-items: center;
  padding: var(--space-2);
  background:
    linear-gradient(var(--tick), var(--tick)) left calc(4 * var(--unit)) top 0 / 1px calc(6 * var(--unit)) no-repeat,
    linear-gradient(var(--tick), var(--tick)) left 0 top calc(4 * var(--unit)) / calc(6 * var(--unit)) 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) right calc(4 * var(--unit)) top 0 / 1px calc(6 * var(--unit)) no-repeat,
    linear-gradient(var(--tick), var(--tick)) right 0 top calc(4 * var(--unit)) / calc(6 * var(--unit)) 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) left calc(4 * var(--unit)) bottom 0 / 1px calc(6 * var(--unit)) no-repeat,
    linear-gradient(var(--tick), var(--tick)) left 0 bottom calc(4 * var(--unit)) / calc(6 * var(--unit)) 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) right calc(4 * var(--unit)) bottom 0 / 1px calc(6 * var(--unit)) no-repeat,
    linear-gradient(var(--tick), var(--tick)) right 0 bottom calc(4 * var(--unit)) / calc(6 * var(--unit)) 1px no-repeat;
}
.code-thumb-svg { display: block; width: 100%; height: auto; border-radius: var(--radius-xs); box-shadow: var(--shadow-1); }

/* ---------- home ---------- */
.home-grid { display: grid; gap: var(--space-8); }
@media (width >= 1100px) { .home-grid { grid-template-columns: minmax(0, 1fr) calc(340 * var(--unit)); align-items: start; } }
.contact-sheet { list-style: none; margin: 0; padding: var(--space-5); display: grid; gap: var(--space-5); grid-template-columns: repeat(auto-fill, minmax(min(100%, calc(150 * var(--unit))), 1fr)); background: var(--surface-sunken); border-radius: var(--radius-m); }
.contact { display: grid; gap: var(--space-2); align-content: start; min-width: 0; }
.contact-link { display: grid; gap: var(--space-2); color: var(--text); text-decoration: none; }
.contact-link:hover .contact-name { text-decoration: underline; }
.contact-proof { aspect-ratio: 1; padding: var(--space-3); background-color: var(--surface); border-radius: var(--radius-xs); }
.contact-name { font-weight: 650; overflow-wrap: anywhere; line-height: var(--leading-snug); }
.contact-meta { display: flex; flex-wrap: wrap; gap: var(--space-1); }
.home-side { display: grid; gap: var(--space-7); }
.home-side section { padding-top: var(--space-4); border-top: 2px solid var(--text); }
.week-total { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-2); margin: var(--space-3) 0; }
.week-number { font-family: var(--font-display); font-size: var(--step-3); font-weight: 750; font-variant-numeric: tabular-nums; }
.week-bars, .day-bars { list-style: none; margin: 0; padding: 0; display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: var(--space-1); align-items: end; height: calc(96 * var(--unit)); }
.day-bars { height: calc(120 * var(--unit)); margin-bottom: var(--space-5); }
.week-bars li, .day-bars li { display: flex; align-items: flex-end; height: 100%; }
.week-bar { display: block; width: 100%; min-height: 2px; border-radius: var(--radius-xs) var(--radius-xs) 0 0; background: var(--brand); }
.week-day { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
[data-h="0"] .week-bar { height: 2px; background: var(--line-strong); }
[data-h="1"] .week-bar { height: 10%; }
[data-h="2"] .week-bar { height: 20%; }
[data-h="3"] .week-bar { height: 30%; }
[data-h="4"] .week-bar { height: 40%; }
[data-h="5"] .week-bar { height: 50%; }
[data-h="6"] .week-bar { height: 60%; }
[data-h="7"] .week-bar { height: 70%; }
[data-h="8"] .week-bar { height: 80%; }
[data-h="9"] .week-bar { height: 90%; }
[data-h="10"] .week-bar { height: 100%; }
.checklist { list-style: none; margin: var(--space-3) 0 0; padding: 0; display: grid; gap: var(--space-1); }
.checklist li { position: relative; display: flex; align-items: center; min-height: var(--tap-min); padding-left: var(--space-7); }
.checklist li::before { content: ""; position: absolute; left: 0; top: 50%; width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); margin-top: calc(-9 * var(--unit)); border: 2px solid var(--line-input); border-radius: var(--radius-xs); }
.checklist li.is-done { color: var(--text-muted); }
.checklist li.is-done::before { border-color: var(--brand-fill); background: var(--brand-fill); }
.checklist li.is-done::after { content: ""; position: absolute; left: calc(5 * var(--unit)); top: 50%; width: calc(8 * var(--unit)); height: calc(4 * var(--unit)); margin-top: calc(-1 * var(--space-1)); border-left: 2px solid var(--on-brand); border-bottom: 2px solid var(--on-brand); transform: rotate(-45deg); }
.plan-line { margin: var(--space-3) 0; font-size: var(--step-1); }

/* ---------- library ---------- */
.meters { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-8); margin-bottom: var(--space-5); }
.meters .meter-field { flex: 1 1 calc(260 * var(--unit)); margin: 0; }
.meter-text { margin: 0; }
.meter-label-text { font-weight: 600; margin-right: var(--space-2); }
.meter-label span:last-child, .meter-text { font-variant-numeric: tabular-nums; }

/* Shared filter card (the inbox, help, tracker and 404 search forms; the library's toolbar overrides it
   below with .lib-bar, and analytics with .ana-filters). */
.filters { display: grid; gap: var(--space-3) var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(150 * var(--unit))), 1fr)); align-items: end; margin-bottom: var(--space-7); padding: var(--space-4) var(--space-5); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-m); }
.filters-search { grid-column: 1 / -1; }
@media (width >= 900px) { .filters-search { grid-column: span 2; } }
.filters-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }

/* One compact toolbar: a content-sized search, a Filters popover, then the count and view toggle (agent-rails
   style; the popover reuses the analytics ana-pop pattern). The selects live in the popover, so even a phone
   shows the codes on the first screen rather than a wall of controls. */
.lib-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); margin-bottom: var(--space-4); }
/* The search and the Filters button are one non-wrapping group that grows to push the count/toggle to the
   right on a single row; at phone widths the whole toolbar wraps so the count and toggle drop to a line of
   their own. */
.lib-bar { flex: 1 1 calc(300 * var(--unit)); min-width: 0; display: flex; flex-wrap: nowrap; align-items: center; gap: var(--space-2) var(--space-3); margin: 0; padding: 0; border: 0; background: none; }
.lib-search { margin: 0; flex: 1 1 auto; min-width: 0; max-width: calc(360 * var(--unit)); }
.lib-search > input { width: 100%; min-height: calc(44 * var(--unit)); }
.lib-toolbar-end { flex: none; display: flex; align-items: center; gap: var(--space-3) var(--space-4); }
.lib-count { margin: 0; white-space: nowrap; }
.lib-pop { position: relative; margin: 0; flex: none; }
.lib-pop > summary { list-style: none; display: inline-flex; align-items: center; gap: var(--space-2); min-height: calc(44 * var(--unit)); padding: var(--space-2) var(--space-3); border: 1px solid var(--line-input); border-radius: var(--radius-s); background: var(--surface); color: var(--text); font: inherit; font-weight: 650; font-size: var(--step--1); white-space: nowrap; cursor: pointer; }
.lib-pop > summary::-webkit-details-marker { display: none; }
.lib-pop > summary::before { content: ""; width: calc(15 * var(--unit)); height: calc(13 * var(--unit)); background: currentColor; -webkit-mask: no-repeat center / contain url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 14"><path d="M1 2h14M4 7h8M6 12h4" stroke="black" stroke-width="2" stroke-linecap="round"/></svg>'); mask: no-repeat center / contain url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 14"><path d="M1 2h14M4 7h8M6 12h4" stroke="black" stroke-width="2" stroke-linecap="round"/></svg>'); }
.lib-pop > summary:hover { border-color: var(--text-muted); }
.lib-pop[open] > summary { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand); }
.lib-pop-count { display: inline-grid; place-items: center; min-width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); padding: 0 calc(5 * var(--unit)); border-radius: var(--radius-pill); background: var(--brand-fill); color: var(--on-brand); font-size: var(--step--2); font-weight: 700; line-height: 1; }
.lib-pop-count[hidden] { display: none; }
.lib-pop-panel { position: absolute; z-index: 20; inset-inline-start: 0; inset-block-start: calc(100% + var(--space-2)); width: min(calc(360 * var(--unit)), calc(100vw - var(--space-6))); max-height: min(80vh, calc(640 * var(--unit))); overflow: auto; display: grid; gap: var(--space-3); padding: var(--space-4); background: var(--surface-raised); border: 1px solid var(--line); border-radius: var(--radius-m); box-shadow: var(--shadow-3); }
.lib-pop-panel .field { margin: 0; gap: var(--space-1); }
.lib-pop-panel .field > label { font-size: var(--step--1); font-weight: 650; color: var(--text-muted); }
.lib-pop-panel select { width: 100%; min-height: calc(45 * var(--unit)); }
.lib-pop-foot { display: flex; align-items: stretch; justify-content: space-between; gap: var(--space-3); margin-top: var(--space-1); padding-top: var(--space-3); border-top: 1px solid var(--line); }
.lib-pop-foot .button { min-height: calc(45 * var(--unit)); }
.lib-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-4); }
.lib-chip { display: inline-flex; align-items: center; gap: var(--space-1); min-height: calc(32 * var(--unit)); padding: 0 var(--space-1) 0 var(--space-3); border-radius: var(--radius-pill); background: var(--surface-sunken); color: var(--text); font-size: var(--step--1); text-decoration: none; }
.lib-chip:hover { background: var(--brand-tint); }
.lib-chip-text { max-width: calc(170 * var(--unit)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lib-chip-x { display: inline-grid; place-items: center; width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); border-radius: 50%; color: var(--text-muted); font-size: var(--step-0); line-height: 1; }
.lib-chip:hover .lib-chip-x { color: var(--text); }

.library { display: grid; gap: var(--space-6); }
@media (width >= 900px) { .library { grid-template-columns: calc(220 * var(--unit)) minmax(0, 1fr); align-items: start; } }
@media (width < 900px) { .library-side { order: 2; } .library-main { order: 1; } }
.library-side { display: grid; gap: var(--space-3); align-content: start; }
.side-title { font-family: var(--font-text); font-size: var(--step-0); font-weight: 700; letter-spacing: 0; margin: var(--space-3) 0 0; }
.folder-tree { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-1); }
.folder-tree li { display: flex; align-items: center; gap: var(--space-2); min-height: var(--tap-min); }
.folder-tree a { flex: 1 1 auto; min-width: 0; display: inline-flex; align-items: center; min-height: var(--tap-min); text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.folder-tree a:hover { text-decoration: underline; }
.folder-tree a[aria-current="true"] { font-weight: 700; }
.folder-count { flex: none; }
.folder-del { margin: 0; flex: none; }
.folder-del-btn { display: inline-grid; place-items: center; width: calc(32 * var(--unit)); height: calc(32 * var(--unit)); border: 0; border-radius: var(--radius-pill); background: none; color: var(--text-muted); font: inherit; font-size: var(--step-0); line-height: 1; cursor: pointer; opacity: 0; transition: opacity var(--dur-hover) var(--ease-out); }
.folder-tree li:hover .folder-del-btn, .folder-tree li:focus-within .folder-del-btn { opacity: 1; }
.folder-del-btn:hover { color: var(--danger-solid); background: var(--surface-sunken); }
.folder-tree .depth-1 > a { padding-left: var(--space-4); }
.folder-tree .depth-2 > a { padding-left: var(--space-7); }
.folder-tree .depth-3 > a { padding-left: var(--space-9); }
.folder-tree .depth-4 > a { padding-left: var(--space-10); }
.side-add { list-style: none; display: inline-flex; align-items: center; gap: var(--space-1); width: max-content; min-height: calc(40 * var(--unit)); padding: 0; border: 0; background: none; color: var(--link); font-weight: 650; font-size: var(--step--1); cursor: pointer; }
.side-add::-webkit-details-marker { display: none; }
.side-add-plus { font-weight: 700; font-size: var(--step-1); line-height: 1; }
.side-add:hover { text-decoration: underline; }
.side-form[open] .side-add { margin-bottom: var(--space-2); }
.side-form form { margin-top: var(--space-2); }
.tag-cloud { list-style: none; margin: 0 0 var(--space-3); padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-2); }
.tag { display: inline-flex; align-items: center; gap: var(--space-1); min-height: calc(26 * var(--unit)); padding: 0 var(--space-3); border-radius: var(--radius-pill); background: var(--surface-sunken); color: var(--text); font-size: var(--step--1); text-decoration: none; }
a.tag { min-height: calc(30 * var(--unit)); }
a.tag:hover { background: var(--brand-tint); }
a.tag[aria-current="true"] { background: var(--brand-tint); color: var(--brand-tint-text); font-weight: 650; }
.tag-remove { display: inline-grid; place-items: center; width: calc(28 * var(--unit)); height: calc(28 * var(--unit)); margin-right: calc(-1 * var(--space-2)); border: 0; background: none; color: var(--text-muted); font: inherit; font-size: var(--step-1); cursor: pointer; }
.tag-remove:hover { color: var(--text); }
.view-toggle { display: inline-flex; gap: var(--space-1); margin: 0; padding: var(--space-1); border-radius: var(--radius-pill); background: var(--surface-sunken); }
.view-toggle a { padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill); color: var(--text-muted); text-decoration: none; }
.view-toggle a[aria-current="true"] { font-weight: 700; color: var(--text); background: var(--surface); box-shadow: var(--shadow-1); }
.bulk-all { min-height: var(--tap-min); align-items: center; }

/* WSP-001..003: the library feels light: a sticky bulk bar that lights up with a selection, one-click
   actions, a star per code, the owner and print record on every row and tile, keyboard focus rows. */
.bulk-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); margin-bottom: var(--space-4); padding: var(--space-3) var(--space-4); border-radius: var(--radius-m); background: var(--surface-sunken); position: sticky; top: var(--space-2); z-index: 2; transition: background-color var(--dur-hover) var(--ease-out), box-shadow var(--dur-hover) var(--ease-out); }
.bulk-bar .field { flex: 1 1 calc(180 * var(--unit)); }
.bulk-bar.has-selection { background: var(--brand-tint); box-shadow: var(--shadow-1); }
.bulk-count { margin: 0; font-weight: 700; color: var(--brand-tint-text); }
.bulk-buttons, .bulk-with { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-2) var(--space-3); }
.bulk-with { flex: 1 1 100%; }
.bulk-bar .bulk-with .field { flex: 1 1 calc(220 * var(--unit)); margin: 0; }
.inline-pair { display: flex; gap: var(--space-2); align-items: stretch; }
.inline-pair > select, .inline-pair > input { flex: 1 1 auto; min-width: 0; }
.bulk-keys { flex: 1 1 100%; margin: 0; }
@media (hover: none) { .bulk-keys { display: none; } }
.bulk-confirm { display: grid; gap: var(--space-3); margin-bottom: var(--space-4); }
.bulk-confirm-list { margin: 0; padding-left: var(--space-5); font-size: var(--step--1); }

/* The list: a larger crisp preview, two aligned text lines (name + destination, then badges + meta), and a
   right-hand scans column that lines up with its header. The checkbox and star appear on hover, focus or
   once a selection is active (Gmail/Linear style). */
.code-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
.code-item { position: relative; display: grid; grid-template-columns: auto calc(72 * var(--unit)) minmax(0, 1fr); grid-template-areas: "sel thumb main" "sel thumb line2" "sel thumb scans"; gap: var(--space-1) var(--space-4); align-items: start; padding: var(--space-3) var(--space-2); border-bottom: 1px solid var(--line); transition: background-color var(--dur-hover) var(--ease-out); }
@media (width >= 1100px) {
  .code-item { grid-template-columns: auto calc(72 * var(--unit)) minmax(0, 1fr) auto; grid-template-areas: "sel thumb main scans" "sel thumb line2 scans"; }
}
.code-select { grid-area: sel; display: grid; place-items: center; width: calc(32 * var(--unit)); min-height: var(--tap-min); opacity: 0; transition: opacity var(--dur-hover) var(--ease-out); }
.code-item:hover .code-select, .code-item:focus-within .code-select, .code-item.is-selected .code-select, [data-bulk].has-selection .code-select { opacity: 1; }
.code-thumb { grid-area: thumb; align-self: start; width: calc(72 * var(--unit)); height: calc(72 * var(--unit)); }
.code-main { grid-area: main; min-width: 0; }
.code-title { display: flex; align-items: center; gap: var(--space-1) var(--space-2); margin: 0; min-width: 0; }
.code-name { min-width: 0; max-width: 100%; font-weight: 700; color: var(--text); text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.code-name:hover { text-decoration: underline; color: var(--link-hover); }
.code-title .type-icon { flex: none; width: calc(24 * var(--unit)); height: calc(24 * var(--unit)); }
.code-item-dest { flex: 1 1 calc(120 * var(--unit)); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--step--1); color: var(--text-muted); }
.code-where { margin: var(--space-1) 0 0; }
.code-item-slug { font-family: var(--font-mono); font-size: var(--step--2); color: var(--text-muted); }
.code-list:not(.is-grid) .code-where { display: none; }
.code-star { flex: none; display: inline-grid; place-items: center; width: calc(30 * var(--unit)); height: calc(30 * var(--unit)); border: 0; border-radius: var(--radius-pill); background: none; color: var(--text-muted); font-size: var(--step-1); line-height: 1; cursor: pointer; opacity: 0; transition: color var(--dur-hover) var(--ease-out), opacity var(--dur-hover) var(--ease-out); }
.code-item:hover .code-star, .code-item:focus-within .code-star, .code-star:focus-visible, .code-star[aria-pressed="true"] { opacity: 1; }
/* Touch has no hover to reveal them, so the select box and the star stay visible and tappable on phones
   (owner: bulk select and starring must work on a phone). */
@media (hover: none) {
  .code-select, .code-star { opacity: 1; }
}
.code-star:hover { color: var(--brand); }
.code-star[aria-pressed="true"] { color: var(--brand); }
.code-line2 { grid-area: line2; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3); min-width: 0; }
.code-badges { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.code-tags { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); margin: 0; }
.code-folder { font-size: var(--step--1); color: var(--text-muted); }
.code-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3); margin: 0; }
.code-scans { grid-area: scans; align-self: start; display: flex; justify-content: flex-end; gap: var(--space-5); margin: 0; font-size: var(--step--1); }
.code-scans div { display: grid; justify-items: end; min-width: calc(50 * var(--unit)); text-align: right; }
.code-scans dt { font-size: var(--step--1); color: var(--text-muted); }
.code-scans dd { margin: 0; font-weight: 500; font-variant-numeric: tabular-nums; font-size: var(--step-0); }
.code-scans dd.code-untracked { font-weight: 400; font-size: var(--step--1); color: var(--text-muted); }
/* The grid tile shows the scan total on the muted meta line instead of the three-column table. */
.code-scans-sum { font-variant-numeric: tabular-nums; }
.code-list:not(.is-grid) .code-scans-sum { display: none; }
.code-item.is-selected { background: var(--brand-tint); }
.code-item.is-focused { box-shadow: inset var(--focus-width) 0 0 var(--focus); }

/* Phones: rebuild the list row for a narrow screen. The select box sits on the thumbnail (no dead left
   gutter), the name gets up to two lines, the destination drops onto its own line, the star pins to the
   row's top right, and the per-period scans become one compact left-aligned line instead of a right-hand
   float (owner pass 2: no truncation to a few characters, no stray floating numbers). */
@media (width < 760px) {
  .code-list:not(.is-grid) .code-item {
    grid-template-columns: calc(56 * var(--unit)) minmax(0, 1fr);
    grid-template-areas: "thumb main" "thumb line2" "scans scans";
    gap: var(--space-1) var(--space-3);
    padding: var(--space-4) var(--space-2);
  }
  .code-list:not(.is-grid) .code-thumb { width: calc(56 * var(--unit)); height: calc(56 * var(--unit)); }
  .code-list:not(.is-grid) .code-select {
    position: absolute; inset-block-start: var(--space-3); inset-inline-start: var(--space-1); z-index: 1;
    width: auto; min-height: 0; padding: 2px; border-radius: var(--radius-s);
    background: var(--surface); box-shadow: var(--shadow-1);
  }
  .code-list:not(.is-grid) .code-main { padding-inline-end: calc(34 * var(--unit)); }
  .code-list:not(.is-grid) .code-title { flex-wrap: wrap; align-items: baseline; row-gap: var(--space-1); }
  .code-list:not(.is-grid) .code-name {
    flex: 1 1 100%; max-width: 100%; white-space: normal; overflow: hidden;
    display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical;
    line-height: var(--leading-snug); padding-block: 3px;
  }
  .code-list:not(.is-grid) .code-title .type-icon { order: 1; }
  .code-list:not(.is-grid) .code-item-dest { flex: 1 1 100%; order: 2; }
  .code-list:not(.is-grid) .code-star { position: absolute; inset-block-start: var(--space-2); inset-inline-end: 0; opacity: 1; }
  .code-list:not(.is-grid) .code-scans {
    grid-area: scans; justify-content: flex-start; flex-wrap: wrap; gap: var(--space-1) var(--space-4);
    margin-top: var(--space-2); font-size: var(--step--1);
  }
  .code-list:not(.is-grid) .code-scans div { display: inline-flex; align-items: baseline; gap: var(--space-1); min-width: 0; text-align: left; }
  .code-list:not(.is-grid) .code-scans dt { font-size: var(--step--1); color: var(--text-muted); }
  .code-list:not(.is-grid) .code-scans dd { font-size: var(--step--1); font-weight: 650; }
}

/* Grid: content-sized tiles (no stretched empty band), a big crisp preview with the star overlaid top-right
   and the checkbox top-left, then name, badges and meta; the card lifts gently on hover or focus. */
.code-list.is-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); border-top: 0; align-items: start; }
@media (width >= 900px) { .code-list.is-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-4); } }
@media (width >= 1100px) { .code-list.is-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.code-list.is-grid .code-item { grid-template-columns: minmax(0, 1fr); grid-template-areas: "thumb" "main" "line2"; gap: var(--space-2); padding: var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); }
.code-list.is-grid .code-item:hover, .code-list.is-grid .code-item:focus-within { border-color: var(--line-strong); box-shadow: var(--shadow-1); }
.code-list.is-grid .code-thumb { grid-area: thumb; width: 100%; height: auto; aspect-ratio: 1; }
.code-list.is-grid .code-select { position: absolute; inset-block-start: var(--space-3); inset-inline-start: var(--space-3); z-index: 1; width: auto; min-height: 0; padding: var(--space-1); border-radius: var(--radius-s); background: var(--surface); box-shadow: var(--shadow-1); }
.code-list.is-grid .code-star { position: absolute; inset-block-start: var(--space-3); inset-inline-end: var(--space-3); z-index: 1; background: var(--surface); box-shadow: var(--shadow-1); }
/* Name line: the type icon sits inline before the name; the destination drops to its own line under it. */
.code-list.is-grid .code-title { flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-2); }
.code-list.is-grid .code-name { flex: 1 1 auto; min-width: 0; white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; }
.code-list.is-grid .code-title .type-icon { order: -1; }
.code-list.is-grid .code-item-dest { flex: 1 1 100%; order: 1; }
.code-list.is-grid .code-line2 { flex-direction: column; align-items: flex-start; gap: var(--space-1); }
.code-list.is-grid .code-scans { display: none; }
.code-list.is-grid .code-print-none { display: none; }
.code-list.is-grid .code-item.is-selected { background: var(--brand-tint); border-color: var(--brand); }
.code-list.is-grid .code-item.is-focused { box-shadow: 0 0 0 var(--focus-width) var(--focus); }

.saved-list { list-style: none; margin: 0 0 var(--space-5); padding: 0; display: grid; gap: var(--space-1); }
.saved-list a { display: inline-flex; align-items: center; gap: var(--space-1); min-height: calc(32 * var(--unit)); text-decoration: none; }
.saved-list a:hover { text-decoration: underline; }
.saved-list a[aria-current="true"] { font-weight: 700; color: var(--text); }
.saved-remove { display: inline-grid; place-items: center; width: calc(28 * var(--unit)); height: calc(28 * var(--unit)); border: 0; background: none; color: var(--text-muted); font: inherit; cursor: pointer; }
.saved-remove:hover { color: var(--text); }
.saved-item { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.side-save { display: grid; gap: var(--space-1); margin: 0 0 var(--space-5); font-size: var(--step--1); }
@media (prefers-reduced-motion: reduce) { .bulk-bar, .code-item, .code-star, .code-select, .folder-del-btn { transition: none; } }
.pager { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: center; justify-content: space-between; margin-top: var(--space-5); }

/* ---------- branding (Settings > Branding): pickers beside the live system page ---------- */
.brand-layout { display: grid; gap: var(--space-5); align-items: start; --cols: 8; --tile-gap: calc(8 * var(--unit)); }
@media (width >= 900px) { .brand-layout:has(.brand-preview-card) { grid-template-columns: calc(320 * var(--unit)) minmax(0, 1fr); } .brand-preview-card { position: sticky; top: var(--space-5); } }
.brand-form .gen-colour legend, .brand-kits legend { font-weight: 700; padding: 0; margin-bottom: var(--space-2); }
.brand-accent { display: grid; gap: var(--space-3); }
.brand-accent .field { margin: 0; max-width: 20rem; }
.brand-kits { border: 0; padding: 0; margin: 0; min-width: 0; }
.brand-kit-grid { display: grid; gap: var(--space-2); grid-template-columns: repeat(auto-fill, minmax(min(100%, calc(200 * var(--unit))), 1fr)); }
.brand-preview-logo img { max-width: 100%; height: calc(40 * var(--unit)); width: auto; }
.brand-preview [hidden] { display: none; }
@media (width < 760px) { .brand-layout { --cols: 5; } }

/* ---------- create ---------- */
.create .gen-types { border-radius: var(--radius-l) var(--radius-l) 0 0; }
/* One guided sequence: each step heading carries its number (data-step-n; not a CSS counter, since the
   design panel is a size container and would scope it), which turns into a brand check once the step is
   done (client/app/main.ts sets data-done); the number is decoration, the heading names the step. */
.create [data-step] .gen-step-title { display: flex; align-items: center; gap: var(--space-3); }
.create [data-step] .gen-step-title::before {
  content: "1" / "";
  flex: none;
  display: inline-grid;
  place-items: center;
  width: calc(26 * var(--unit));
  height: calc(26 * var(--unit));
  border: 1.5px solid var(--line-strong);
  border-radius: 50%;
  color: var(--text-muted);
  font-size: var(--step--1);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.create [data-step-n="2"] .gen-step-title::before { content: "2" / ""; }
.create [data-step-n="3"] .gen-step-title::before { content: "3" / ""; }
.create [data-step-n="4"] .gen-step-title::before { content: "4" / ""; }
.create [data-step][data-done] .gen-step-title::before { content: "\2713" / ""; border-color: var(--brand-fill); background: var(--brand-fill); color: var(--on-brand); }
.create-step, .create-step + .gen-step { margin-top: var(--space-7); padding-top: var(--space-6); border-top: 1px solid var(--line); }
.create .gen-mode { margin-top: 0; }
.quick-logo-own { margin: 0; }
.create-details { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(220 * var(--unit))), 1fr)); }
.preview-empty { margin: 0; padding: var(--space-8) var(--space-4); text-align: center; }
.create .gen-out .meter-field { margin: var(--space-5) 0 var(--space-4); }
.create .gen-out .button { margin-top: var(--space-4); }

/* ---------- editor ---------- */
.editor-head h1 { font-size: var(--step-3); }
.editor-badges { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: 0; }
.editor-grid { display: grid; gap: var(--space-7); }
@media (width >= 900px) { .editor-grid { grid-template-columns: minmax(0, 1fr) calc(340 * var(--unit)); align-items: start; } }
.editor-tabs { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-2) var(--space-5); border-bottom: 1px solid var(--line); margin-bottom: var(--space-6); }
.tab-links { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-1); }
.tab-links a { display: inline-flex; align-items: center; min-height: var(--tap-min); padding: 0 var(--space-4); border-bottom: 3px solid transparent; color: var(--text-muted); font-weight: 650; text-decoration: none; }
.tab-links a:hover { color: var(--text); }
.tab-links a[aria-current="page"] { color: var(--text); border-bottom-color: var(--brand); }
.advanced { display: flex; flex-wrap: wrap; align-items: flex-end; }
.advanced > summary { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--tap-min); padding: 0 var(--space-3); color: var(--link); font-weight: 650; cursor: pointer; list-style: none; }
.advanced > summary::-webkit-details-marker { display: none; }
.advanced > summary::before { content: ""; width: calc(7 * var(--unit)); height: calc(7 * var(--unit)); border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(-45deg); }
.advanced[open] > summary::before { transform: rotate(45deg); }
.advanced[open] { flex: 1 1 auto; }
.advanced[open] .tab-links { padding-left: var(--space-3); border-left: 1px solid var(--line); }
.editor-panel > h2 { font-size: var(--step-2); }
.panel-block { margin-bottom: var(--space-7); }
.panel-block + .panel-block { padding-top: var(--space-6); border-top: 1px solid var(--line); }
.panel-block h3 { font-size: var(--step-1); }
.state-actions form { margin: 0; }
.editor-side-in { display: grid; gap: var(--space-3); padding: var(--space-5); background: var(--surface-sunken); border-radius: var(--radius-m); }
@media (width >= 900px) { .editor-side-in { position: sticky; top: calc(var(--bar-height) + var(--space-5)); } }
.editor-proof { padding-top: var(--space-6); }
.short-link-label { margin: 0; }
.short-link-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0; }
.short-link-row code { font-size: var(--step--1); }
.editor-download { display: grid; gap: var(--space-3); margin-top: var(--space-3); }
.design-form { display: grid; gap: var(--space-5); }
.stat-row { display: flex; flex-wrap: wrap; gap: var(--space-8); margin: 0 0 var(--space-6); }
.stat-row div { display: grid; gap: var(--space-1); }
.stat-row dt { color: var(--text-muted); font-size: var(--step--1); }
.stat-row dd { margin: 0; font-family: var(--font-display); font-size: var(--step-3); font-weight: 750; font-variant-numeric: tabular-nums; }
.rule-list { margin: 0 0 var(--space-5); padding-left: var(--space-6); display: grid; gap: var(--space-4); }
.rule-item { padding-left: var(--space-2); }
.rule-when { margin: 0; font-weight: 650; }
.rule-url { margin: var(--space-1) 0 var(--space-2); font-size: var(--step--1); color: var(--text-muted); overflow-wrap: anywhere; }
.rule-default { margin: 0 0 var(--space-6); padding: var(--space-3) var(--space-4); border-left: 3px solid var(--line-strong); background: var(--surface); overflow-wrap: anywhere; }
.rule-time { gap: var(--space-3); }
.day-picks { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); }
.day-picks .check { min-height: var(--tap-min); align-items: center; }
.history { list-style: none; margin: 0; padding: 0 0 0 var(--space-5); border-left: 2px solid var(--line-strong); display: grid; gap: var(--space-5); }
.history-item { position: relative; }
.history-item::before { content: ""; position: absolute; left: calc(-1 * var(--space-5) - calc(7 * var(--unit))); top: 0.45em; width: calc(12 * var(--unit)); height: calc(12 * var(--unit)); border-radius: 50%; border: 2px solid var(--line-strong); background: var(--bg); }
.history-item:first-child::before { border-color: var(--brand-fill); background: var(--brand-fill); }
.history-head { margin: 0; }
.history-what { margin: var(--space-1) 0; }
.history-dest { margin: 0 0 var(--space-2); overflow-wrap: anywhere; color: var(--text-muted); }
.history-item form { margin: 0; }
.stepup { padding-top: var(--space-6); }
.app-error { padding-top: var(--space-6); }
[data-bulk-for][hidden], .button[hidden] { display: none; }
.app-main input[type="datetime-local"], .app-main input[type="time"] { width: 100%; min-height: var(--tap-min); padding: var(--space-2) var(--space-3); border: 1px solid var(--line-input); border-radius: var(--radius-s); background: var(--surface); color: var(--text); font: inherit; }
.lock-name { display: inline-block; }
.lock-name::first-letter { text-transform: uppercase; }
.editor-download .button.large { font-size: var(--step-0); padding-inline: var(--space-4); }
@media (width < 760px) {
  .app-brand .logo-word { display: none; }
  .app-switch-current { max-width: 34vw; padding-inline: var(--space-2); }
  .app-tools { gap: var(--space-1); }
  .filters { grid-template-columns: repeat(2, minmax(0, 1fr)); padding: var(--space-4); }
  .filters-actions { grid-column: 1 / -1; }
}
/* A link standing alone in a small paragraph keeps a 24 px target (2.5.8, UX-020). */
p.small > a:only-child { display: inline-block; min-block-size: var(--target-min); line-height: var(--target-min); }
/* ==================== app:end ==================== */
/* ==================== analytics:start ==================== */
/* Scan analytics (views/analytics, src/scans/charts.ts). Marks take the brand colour; grids, ticks and
   tracks are one step off the surface; the heatmap is one hue in five steps. Both themes follow the tokens. */
/* One tidy filter card: a flex bar of the period, group-by and code, a "Filters" popover for the rest,
   and the apply/clear actions pushed to the end. It wraps cleanly with no overlap at every width. */
.ana-filters { display: block; margin-bottom: var(--space-4); padding: var(--space-3) var(--space-4); }
.ana-bar { display: flex; flex-wrap: wrap; align-items: end; gap: var(--space-3); }
.ana-field { margin: 0; gap: var(--space-1); min-width: 0; }
.ana-field > label { font-size: var(--step--1); font-weight: 650; color: var(--text-muted); }
.ana-field > select, .ana-field > input { min-height: calc(36 * var(--unit)); }
.ana-bar > .ana-field > select { width: auto; min-width: calc(128 * var(--unit)); max-width: calc(220 * var(--unit)); }
.ana-filters input[type="date"] { min-height: calc(36 * var(--unit)); padding: var(--space-2) var(--space-3); border: 1px solid var(--line-input); border-radius: var(--radius-s); background: var(--surface); color: var(--text); font: inherit; }
.ana-filters input[name="country"] { width: calc(88 * var(--unit)); min-height: calc(36 * var(--unit)); padding: var(--space-2) var(--space-3); border: 1px solid var(--line-input); border-radius: var(--radius-s); background: var(--surface); color: var(--text); font: inherit; text-transform: uppercase; }
.ana-pop { position: relative; align-self: end; margin: 0; }
/* The trigger is a control the same height and weight as the selects beside it, with the count badge. */
.ana-pop > summary { list-style: none; display: inline-flex; align-items: center; gap: var(--space-2); min-height: calc(36 * var(--unit)); padding: var(--space-2) var(--space-3); border: 1px solid var(--line-input); border-radius: var(--radius-s); background: var(--surface); color: var(--text); font: inherit; font-weight: 650; font-size: var(--step--1); white-space: nowrap; cursor: pointer; }
.ana-pop > summary::-webkit-details-marker { display: none; }
.ana-pop > summary:hover { border-color: var(--text-muted); }
.ana-pop[open] > summary { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand); }
.ana-pop-count { display: inline-grid; place-items: center; min-width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); padding: 0 calc(5 * var(--unit)); border-radius: var(--radius-pill); background: var(--brand-fill); color: var(--on-brand); font-size: var(--step--2); font-weight: 700; line-height: 1; }
.ana-pop-count[hidden] { display: none; }
/* Wide enough to hold two date inputs side by side; everything, including the footer, sits inside it. */
.ana-pop-panel { position: absolute; z-index: 20; inset-inline-start: 0; inset-block-start: calc(100% + var(--space-2)); width: min(calc(360 * var(--unit)), calc(100vw - var(--space-6))); max-height: min(80vh, calc(640 * var(--unit))); overflow: auto; display: grid; gap: var(--space-3); padding: var(--space-4); background: var(--surface-raised); border: 1px solid var(--line); border-radius: var(--radius-m); box-shadow: var(--shadow-3); }
.ana-pop-panel .ana-field > select, .ana-pop-panel .ana-field > input { width: 100%; max-width: none; min-width: 0; }
.ana-pop-panel input[name="country"] { width: calc(96 * var(--unit)); }
.ana-pop-range { border: 0; padding: 0; margin: 0; min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-2) var(--space-3); }
.ana-pop-range legend { grid-column: 1 / -1; padding: 0; margin-bottom: var(--space-1); font-size: var(--step--1); font-weight: 650; }
.ana-pop-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-top: var(--space-1); padding-top: var(--space-3); border-top: 1px solid var(--line); }
.ana-actions { margin-inline-start: auto; align-self: end; }
.ana-clear { display: inline-flex; align-items: center; min-height: calc(36 * var(--unit)); color: var(--link); }
.ana-check { display: flex; align-items: center; gap: var(--space-2); min-height: var(--tap-min); font-size: var(--step--1); }
@media (width < 760px) {
  /* A tidy grid: the period and group-by share a row, the code select spans the next (so it is never an
     odd width), then the full-height Filters trigger and Apply sit on one row. The extra filters open as a
     bottom sheet (owner pass 2). */
  .ana-bar { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); align-items: end; }
  .ana-bar > .ana-field { min-width: 0; }
  .ana-bar > .ana-field > select { width: 100%; min-width: 0; max-width: none; }
  .ana-field-code { grid-column: 1 / -1; }
  .ana-pop { position: static; }
  .ana-pop > summary { width: 100%; justify-content: center; min-height: var(--tap-min); }
  .ana-actions { margin-inline-start: 0; display: flex; align-items: center; gap: var(--space-3); }
  .ana-actions > .button { flex: 1; }
  /* The Filters popover opens as a bottom sheet: full width, pinned to the bottom, its footer in reach. */
  .ana-pop[open] > .ana-pop-panel {
    position: fixed; inset: auto 0 0 0; width: 100%; max-width: none; max-height: 85vh; margin: 0;
    border-radius: var(--radius-l) var(--radius-l) 0 0; box-shadow: var(--shadow-3); z-index: 60;
  }
  .ana-pop[open] > .ana-pop-panel .ana-pop-foot { position: sticky; bottom: 0; margin: 0; padding-block: var(--space-3); background: var(--surface-raised); }
}
.ana-tz-save { margin: 0 0 var(--space-4); }
.ana-none { max-width: var(--measure); padding: var(--space-5) 0; color: var(--text-muted); }
.ana-hero-block { padding-bottom: var(--space-6); border-bottom: 1px solid var(--line); }
.ana-kpis { display: grid; gap: var(--space-2) var(--space-8); grid-template-columns: minmax(0, 1fr); margin-bottom: var(--space-5); }
.ana-hero { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-3); margin: 0; }
.ana-hero-number { font-family: var(--font-text); font-weight: 700; font-size: var(--step-5); line-height: var(--leading-tight); letter-spacing: -0.01em; }
.ana-hero-label { font-size: var(--step-1); color: var(--text-muted); }
.ana-growth { margin: 0; font-weight: 600; color: var(--text-muted); }
.ana-growth::before { content: ""; display: inline-block; width: 0; height: 0; margin-right: var(--space-2); border-inline: calc(5 * var(--unit)) solid transparent; vertical-align: 0.1em; }
.ana-growth[data-trend="none"]::before, .ana-growth[data-trend="flat"]::before { display: none; }
.ana-growth[data-trend="up"]::before { border-bottom: calc(8 * var(--unit)) solid var(--status-active-dot); }
.ana-growth[data-trend="down"]::before { border-top: calc(8 * var(--unit)) solid var(--status-danger-dot); }
.ana-facts { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-8); margin: var(--space-3) 0 0; }
.ana-facts div { max-width: 32ch; }
.ana-facts dt { font-weight: 650; }
.ana-facts dd { margin: 0; font-size: var(--step-1); font-weight: 650; }
.ana-facts dd.small { font-size: var(--step--1); font-weight: 400; }
.ana-figure { margin: 0; }
.ana-caption { font-weight: 650; margin-bottom: var(--space-2); }
.ana-chart { width: 100%; min-width: 0; }
.ana-chart:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); border-radius: var(--radius-xs); }
.ana-chart svg { display: block; width: 100%; height: auto; overflow: visible; }
.ana-readout { min-height: 1.6em; margin: var(--space-2) 0 0; font-variant-numeric: tabular-nums; color: var(--text-muted); }
.ana-legend { display: flex; flex-wrap: wrap; gap: var(--space-4); list-style: none; padding: 0; margin: 0 0 var(--space-2); font-size: var(--step--1); color: var(--text-muted); }
.ana-legend li { display: flex; align-items: center; gap: var(--space-2); }
.ana-key { display: inline-block; width: calc(16 * var(--unit)); height: 0; border-top: 2px solid var(--brand); }
.ana-key.is-extra { border-top: 2px dashed var(--text-muted); }
.chart-grid { stroke: var(--line); stroke-width: 1; }
.chart-land { fill: var(--surface-sunken); stroke: var(--line-strong); stroke-width: 1; stroke-linejoin: round; }
.chart-tick { fill: var(--text-muted); font-family: var(--font-text); font-size: var(--step--2); font-variant-numeric: tabular-nums; }
.chart-line.is-compact .chart-tick { font-size: var(--step--2); }
.chart-area { fill: var(--brand); fill-opacity: 0.1; stroke: none; }
.chart-stroke { fill: none; stroke: var(--brand); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.chart-stroke.is-extra { stroke: var(--text-muted); stroke-dasharray: 5 4; }
.chart-dot { fill: var(--brand); stroke: var(--surface); stroke-width: 2; }
.chart-pin { fill: var(--text); stroke: var(--surface); stroke-width: 1; fill-opacity: 0.85; }
.chart-bar { fill: var(--brand); }
.chart-hit { fill: transparent; }
.chart-hit.is-active, .chart-col:hover .chart-hit { fill: var(--brand-tint); fill-opacity: 0.6; }
.chart-note line { stroke: var(--text-muted); stroke-width: 1; }
.chart-note path { fill: var(--text); stroke: var(--surface); stroke-width: 2; }
.heat-0 { fill: var(--surface-sunken); }
.heat-1 { fill: var(--brand); fill-opacity: 0.14; }
.heat-2 { fill: var(--brand); fill-opacity: 0.32; }
.heat-3 { fill: var(--brand); fill-opacity: 0.52; }
.heat-4 { fill: var(--brand); fill-opacity: 0.74; }
.heat-5 { fill: var(--brand); }
.ana-notes { list-style: none; padding: 0; margin: 0 0 var(--space-4); display: grid; gap: var(--space-1); font-size: var(--step--1); overflow-wrap: anywhere; }
.ana-notes li { display: flex; gap: var(--space-2); align-items: baseline; }
.ana-note-mark { flex: none; width: calc(8 * var(--unit)); height: calc(8 * var(--unit)); background: var(--text); transform: rotate(45deg); }
.ana-table-toggle { margin-top: var(--space-3); }
.ana-table-toggle summary { cursor: pointer; color: var(--link); min-height: var(--tap-min); display: inline-flex; align-items: center; }
.ana-scroll { overflow-x: auto; }
.ana-table { width: 100%; margin: var(--space-2) 0 0; border-collapse: collapse; font-size: var(--step--1); font-variant-numeric: tabular-nums; }
.ana-table th, .ana-table td { text-align: left; padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--line); vertical-align: top; }
.ana-table th:first-child, .ana-table td:first-child { padding-left: 0; }
.ana-table thead th { font-weight: 650; color: var(--text-muted); border-bottom: 1px solid var(--line-strong); }
.ana-table .num { text-align: right; white-space: nowrap; }
.ana-table tbody th { font-weight: 500; }
.ana-name { display: block; overflow-wrap: anywhere; }
.bar-cell { display: block; width: 100%; height: calc(8 * var(--unit)); margin-top: var(--space-1); }
.bar-track { fill: var(--surface-sunken); }
.bar-fill { fill: var(--brand); }
.ana-heat-table th, .ana-heat-table td { padding: var(--space-2); }
.ana-section { padding: var(--space-7) 0; border-bottom: 1px solid var(--line); }
.ana-section h2 { font-size: var(--step-2); margin: 0 0 var(--space-4); }
.ana-list h3 { font-family: var(--font-text); font-size: var(--step-0); font-weight: 700; margin: 0 0 var(--space-2); }
.ana-grid { display: grid; gap: var(--space-6) var(--space-8); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(300 * var(--unit))), 1fr)); align-items: start; }
/* Places: a compact world map, then the ranked lists in a dense row beneath, not a wide empty band. */
.ana-map { margin: 0 0 var(--space-5); }
.ana-map .ana-chart { max-width: calc(620 * var(--unit)); }
.ana-table tbody th { min-width: 10ch; }
.ana-raw-note { margin: var(--space-5) 0 0; max-width: var(--measure); }
.ana-live .section-bar h2 { display: flex; align-items: center; gap: var(--space-2); font-size: var(--step-2); }
.ana-live-dot { width: calc(10 * var(--unit)); height: calc(10 * var(--unit)); border-radius: 50%; background: var(--status-active-dot); box-shadow: 0 0 0 calc(4 * var(--unit)) var(--status-active-bg); }
.ana-moment { margin: 0 0 var(--space-3); padding: var(--space-2) var(--space-3); border: 1px solid var(--line); border-radius: calc(8 * var(--unit)); }
.ana-moment .ana-live-dot { display: inline-block; width: calc(8 * var(--unit)); height: calc(8 * var(--unit)); margin-right: var(--space-2); vertical-align: middle; }
.ana-recent { list-style: none; padding: 0; margin: 0 0 var(--space-3); display: grid; gap: var(--space-1); font-size: var(--step--1); }
.ana-recent li { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); }
.ana-recent-time { font-variant-numeric: tabular-nums; font-weight: 650; }
.ana-compare-form { display: grid; gap: var(--space-3); max-width: calc(420 * var(--unit)); margin-bottom: var(--space-5); }
.ana-compare-form select { min-height: 0; padding: var(--space-2); border: 1px solid var(--line-input); border-radius: var(--radius-s); background: var(--surface); color: var(--text); font: inherit; }
.ana-multiples { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-6); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(300 * var(--unit))), 1fr)); }
.ana-multiples h3 { margin: 0; }
.ana-multiples p { margin: 0 0 var(--space-2); }
.ana-export-actions { list-style: none; padding: 0; margin: var(--space-3) 0; display: flex; flex-wrap: wrap; gap: var(--space-3); }
.ana-exports { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-2); font-size: var(--step--1); }
.ana-total { padding: var(--space-6) 0; }
@media (width >= 900px) { .ana-kpis { grid-template-columns: auto minmax(0, 1fr); align-items: end; } .ana-facts { grid-column: 1 / -1; } }
@media (forced-colors: active) {
  .chart-stroke, .chart-grid, .chart-note line { stroke: CanvasText; }
  .chart-land { fill: Canvas; stroke: CanvasText; }
  .chart-area, .chart-bar, .bar-fill, .heat-1, .heat-2, .heat-3, .heat-4, .heat-5 { fill: Highlight; }
  .chart-tick { fill: CanvasText; }
}
/* ==================== analytics:end ==================== */

/* ==================== site-pages:start (src/site/pages, views/site) ====================
   Pricing (billing toggle in CSS only, plan cards, helper, pass picker with the proof frame,
   comparison by group), the trust, status, money, about and contact pages, and the policy pages. */
@media (width >= 900px) { .footer-grid { grid-template-columns: 1.4fr repeat(5, 1fr); } }

/* Pricing, UX v3 (.factory/ux-v3/direction.md 9): the five plans in one row on a shared subgrid (name, price,
   checkout right under the price, lines, the stop-paying disclosure line up across cards), 3 + 2 below 1100 wide,
   a snap rail below 760; passes and Keep-alive side by side, each sized to its content; every table on one column
   template; the FAQ cards and the accordion on one width. Only transform and opacity move. */
.pricing-head { max-width: var(--measure); margin-bottom: var(--space-6); }
.pricing-head h1 { max-width: 18ch; margin-bottom: var(--space-4); font-size: var(--step-5); font-weight: 650; letter-spacing: -0.03em; line-height: 1.02; }
.pricing-answer, .site-page-answer { font-size: var(--step-1); line-height: 1.5; color: var(--text-muted); max-width: 60ch; margin: 0; }

.billing-toggle { border: 0; margin: 0 0 var(--space-5); display: inline-flex; flex-wrap: wrap; gap: var(--space-1); background: var(--surface-sunken); border: 1px solid var(--line); border-radius: var(--radius-pill); padding: var(--space-1); }
.billing-toggle legend { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.toggle-option { position: relative; display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--tap-min); padding: 0 var(--space-5); border-radius: var(--radius-pill); font-weight: 650; cursor: pointer; color: var(--text-muted); transition: color 140ms var(--ease-out); }
.toggle-option input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.toggle-option:has(input:checked) { background: var(--surface); color: var(--text); box-shadow: var(--shadow-1); }
.toggle-option:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
.toggle-note { font-size: var(--step--2); font-weight: 700; color: var(--neon-ink); background: var(--neon); border-radius: var(--radius-pill); padding: 1px var(--space-2); }

/* Annual is the default (owner 2026-10-14): the year side shows, the month side hides, until Monthly is picked. */
.pricing .is-month { display: none; }
.pricing:has(#bill-month:checked) .is-month { display: block; }
.pricing:has(#bill-month:checked) .is-year { display: none; }

/* The plan row. */
.plan-row { display: grid; margin: 0; gap: var(--space-5) var(--space-4); grid-template-columns: minmax(0, 1fr); align-items: stretch; }
.plan-row > .price-card { display: grid; grid-template-rows: subgrid; grid-row: span 5; row-gap: var(--space-3); align-content: start; }
@media (width >= 760px) {
  .plan-row { grid-template-columns: repeat(6, minmax(0, 1fr)); row-gap: 0; }
  .plan-row > .price-card { grid-column: span 2; }
  .plan-row > .price-card:nth-child(n + 4) { grid-column: span 3; margin-top: var(--space-5); }
}
@media (width >= 1100px) {
  .plan-row { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .plan-row > .price-card { padding-inline: var(--space-4); }
  .plan-row > .price-card, .plan-row > .price-card:nth-child(n + 4) { grid-column: auto; margin-top: 0; }
}
@media (width < 760px) {
  /* Phones: one swipeable rail, each card nearly a screen wide. Each card is its own grid sized to its
     content (no shared subgrid rows), so the Free card has no empty gap under its price while the button
     and feature list keep their full-width card layout. */
  .plan-row { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 84%; grid-template-rows: none; row-gap: 0; overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; scroll-padding-inline: var(--space-1); padding: var(--space-3) var(--space-1) var(--space-4); margin-inline: calc(-1 * var(--space-1)); }
  .plan-row > .price-card { grid-template-rows: none; grid-row: auto; scroll-snap-align: start; }
}
.price-card { position: relative; padding: var(--space-6) var(--space-5) var(--space-5); border-radius: var(--radius-l); gap: var(--space-3); transition: transform 140ms var(--ease-out), box-shadow 140ms var(--ease-out); }
.plan-row > .price-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); }
.price-card.is-featured { border: 1px solid var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); background: linear-gradient(180deg, var(--neon-tint), var(--surface) calc(180 * var(--unit))); }
.plan-row > .price-card.is-featured:hover { box-shadow: inset 0 0 0 1.5px var(--brand), var(--shadow-2); }
.price-card.is-ring { border-color: var(--brand); }
.price-card-head { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2); min-width: 0; }
.price-card .plan-name { font-size: var(--step-1); font-weight: 650; letter-spacing: -0.01em; }
.plan-badge { margin: 0; font-size: var(--step--2); font-weight: 650; color: var(--text); background: var(--neon-tint); border: 1px solid color-mix(in srgb, var(--brand) 35%, transparent); border-radius: var(--radius-pill); padding: 1px var(--space-2); }
.price-card .plan-note { font-size: var(--step--1); line-height: 1.45; }
.price-side > p, .price-free > p { margin: 0; }
.price-card .plan-price { font-size: var(--step-4); font-weight: 650; letter-spacing: -0.03em; line-height: 1.1; }
/* The unit ("per month, billed yearly" / "once") sits on its own small line under the big price, so every
   card's price block has the same shape and the amounts line up (owner 2026-10-14). */
.price-card .plan-price span { display: block; margin: 2px 0 0; font-size: var(--step--2); font-weight: 400; letter-spacing: 0; line-height: 1.2; color: var(--text-muted); }
.price-side .plan-price { margin-bottom: var(--space-2); }
.plan-period, .plan-today { font-size: var(--step--2); color: var(--text-muted); }
.plan-today { font-weight: 650; color: var(--text); }
.plan-save { margin-top: var(--space-2) !important; font-size: var(--step--2); font-weight: 650; color: var(--brand-tint-text); }
.plan-save-free { background: var(--neon); color: var(--neon-ink); border-radius: var(--radius-pill); padding: 1px var(--space-2); margin-left: var(--space-1); }
.price-card .plan-features { font-size: var(--step--1); gap: var(--space-2); padding-top: var(--space-3); border-top: 1px solid var(--line); }
.price-card .plan-features li:first-child { font-weight: 650; color: var(--text); }
.price-card .plan-features li { color: var(--text-muted); }
.plan-lapse { margin: 0; font-size: var(--step--2); color: var(--text-muted); border-left: 2px solid var(--line-strong); padding-left: var(--space-3); }
.price-cta { align-self: end; padding-bottom: var(--space-1); }
.free-card .price-card-head .plan-note { margin: 0; }
.price-cta .plan-checkout, .pass-card .plan-checkout { gap: var(--space-2); }
.plan-checkout .check { font-size: var(--step--2); line-height: 1.4; color: var(--text-muted); gap: var(--space-2); }
.plan-checkout [data-terms] { font-size: var(--step--2); margin: 0; }
.plan-checkout .button, .price-cta > .button { width: 100%; padding-inline: var(--space-3); }
.plan-checkout .button { margin-top: var(--space-1); }
.plan-soon { margin: 0; font-weight: 650; color: var(--text-muted); }
.free-more { margin: 0; font-size: var(--step--1); }
.free-trial { font-weight: 650; }

.tip { display: inline; }
/* The info icon stays on the same line as the last word of the feature (UX, owner 2026-10-12): the two
   are kept together as one unbreakable unit, so the "i" never wraps to a line of its own. */
.tip-keep { white-space: nowrap; }
.tip summary { display: inline-flex; align-items: center; justify-content: center; width: var(--target-min); height: var(--target-min); border-radius: 50%; border: 1px solid var(--line-input); color: var(--link); font-size: var(--step--2); font-weight: 700; cursor: pointer; list-style: none; vertical-align: middle; }
.tip summary::-webkit-details-marker { display: none; }
.tip[open] summary { background: var(--brand-tint); border-color: var(--brand); }
.tip p { display: block; margin: var(--space-2) 0 0; padding: var(--space-3); background: var(--surface-sunken); border-radius: var(--radius-s); color: var(--text); font-size: var(--step--2); font-weight: 400; }

/* "Fits you": laid over the card's top edge, so showing it moves nothing in the card. */
.price-card.is-fit { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); }
.plan-fits { position: absolute; top: calc(-1 * var(--space-3)); left: var(--space-5); margin: 0; font-size: var(--step--2); font-weight: 700; color: var(--neon-ink); background: var(--neon); border-radius: var(--radius-pill); padding: 2px var(--space-3); }
.plan-fits[hidden] { display: none; }

/* On every plan: one neat strip, each fact on a line with a check, the Terms link set at its end. */
.every-plan { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-5); margin: var(--space-5) 0 0; padding: var(--space-3) var(--space-5); background: var(--neon-tint); border-radius: var(--radius-l); }
.every-plan-title { font-family: var(--font-text); font-size: var(--step--1); font-weight: 700; letter-spacing: 0; color: var(--text); margin: 0; }
.every-plan-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-5); font-size: var(--step--1); color: var(--text); }
.every-plan-list li { position: relative; padding-left: var(--space-5); }
.every-plan-list li::before { content: ""; position: absolute; left: 1px; top: 0.45em; width: calc(9 * var(--unit)); height: calc(5 * var(--unit)); border-left: 2px solid var(--brand); border-bottom: 2px solid var(--brand); transform: rotate(-45deg); }
.every-plan-terms { margin: 0; padding-left: var(--space-5); position: relative; align-self: center; font-size: var(--step--1); }
.every-plan-terms::before { content: ""; position: absolute; left: var(--space-2); top: 50%; width: 1px; height: 1.1em; transform: translateY(-50%); background: color-mix(in srgb, var(--brand) 40%, transparent); }
@media (width < 760px) { .every-plan-terms { padding-left: 0; } .every-plan-terms::before { display: none; } }

/* The two-question helper, after the row (owner 2026-10-14): one compact inline band, not a half-empty card.
   The title, a short number input, the domain as a segmented control and the live answer sit on one line and
   wrap cleanly; the answer lights up the fitting card and glance column. */
.helper { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-5); margin: var(--space-4) 0 0; padding: var(--space-4) var(--space-5); border: 1px solid var(--line); background: var(--surface); border-radius: var(--radius-l); }
.helper > h3 { font-size: var(--step-0); font-weight: 650; margin: 0; flex: 0 0 auto; }
@media (scripting: none) { .helper-live { display: none; } }
.helper-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3) var(--space-4); flex: 1 1 calc(420 * var(--unit)); }
.helper-form .field { margin: 0; flex: 0 1 auto; }
.helper-form #helper-codes { width: calc(84 * var(--unit)); }
.helper-form .field label, .helper-domain legend { font-size: var(--step--2); font-weight: 650; color: var(--text-muted); }
/* The domain answer is ONE joined segmented control (owner 2026-10-14): the options share edges, no gaps. */
.helper-domain { border: 0; padding: 0; margin: 0; min-width: 0; display: flex; flex-wrap: wrap; align-items: stretch; gap: 0; flex: 0 1 auto; }
.helper-domain legend { padding: 0; margin-bottom: var(--space-2); flex: 1 1 100%; }
.helper-domain .option { position: relative; display: inline-flex; align-items: center; min-height: var(--tap-min); padding: 0 var(--space-3); border: 1px solid var(--line-input); margin-left: -1px; background: var(--surface); font-size: var(--step--1); cursor: pointer; white-space: nowrap; }
.helper-domain .option:first-of-type { margin-left: 0; border-top-left-radius: var(--radius-m); border-bottom-left-radius: var(--radius-m); }
.helper-domain .option:last-of-type { border-top-right-radius: var(--radius-m); border-bottom-right-radius: var(--radius-m); }
.helper-domain .option input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.helper-domain .option:has(input:checked) { z-index: 1; border-color: var(--brand); background: var(--brand-tint); color: var(--text); font-weight: 650; box-shadow: inset 0 0 0 1px var(--brand); }
.helper-domain .option:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
.helper-form .field-error { flex: 1 1 100%; }
.helper-result { margin: 0; font-weight: 650; font-size: var(--step--1); display: flex; flex-wrap: wrap; align-items: center; align-self: flex-start; gap: var(--space-1) var(--space-3); flex: 1 1 calc(220 * var(--unit)); }
.helper-result:empty { display: none; }
.helper-go { flex: none; }

/* Not a subscription (owner 2026-10-14): one panel with a short date-finder line, then Event pass, Campaign
   pass and Keep-alive as three equal cards in one row. */
.pay-once { margin-top: var(--space-section); border: 1px solid var(--line); border-radius: var(--radius-l); background: var(--surface); padding: var(--space-6); }
.pass-box { display: grid; gap: var(--space-5); border: 0; background: none; padding: 0; }
.pay-card-head h2 { font-size: var(--step-3); font-weight: 650; letter-spacing: -0.02em; margin: 0 0 var(--space-2); max-width: 24ch; }
.pay-card-head p { margin: 0; color: var(--text-muted); font-size: var(--step--1); max-width: 60ch; }
/* The three cards sit on an equal three-up grid, each framed like a plan card. */
.pass-row { display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr); align-items: stretch; }
@media (width >= 760px) { .pass-row { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.pass-row > .price-card { display: flex; flex-direction: column; gap: var(--space-2); border: 1px solid var(--line); border-radius: var(--radius-l); padding: var(--space-5); background: var(--surface); }
.pass-row > .price-card.is-featured { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); background: linear-gradient(180deg, var(--neon-tint), var(--surface) calc(180 * var(--unit))); }
.pass-row > .price-card .plan-price { font-size: var(--step-4); }
.pass-row > .price-card .plan-features { gap: var(--space-2); padding-top: var(--space-3); margin-top: var(--space-2); border-top: 1px solid var(--line); font-size: var(--step--1); color: var(--text-muted); }
.pass-row > .price-card .pass-refund { margin: 0; color: var(--text-muted); font-size: var(--step--2); }
/* The button area is pinned to the card bottom, so buttons line up across the three equal-height cards. */
.pass-row > .price-card .plan-checkout, .pass-row > .price-card .price-cta { margin-top: auto; padding-top: var(--space-3); }
.pass-row > .price-card .price-cta { align-self: stretch; }
.pass-row > .price-card .plan-checkout .button, .pass-row > .price-card .price-cta .button { width: 100%; }
.pass-row > .price-card .plan-checkout select, .pass-row > .price-card .plan-checkout input[type="email"] { width: 100%; min-height: var(--tap-min); padding: 0 var(--space-3); border: 1px solid var(--line-input); border-radius: var(--radius-m); background: var(--surface); color: var(--text); font: inherit; }
.pass-card .plan-today { font-size: var(--step--1); color: var(--text-muted); }
/* Keep-alive uses the paid-card partial (button before features in the DOM); reorder so its full-width
   button sits at the card bottom like the pass cards. */
.pass-row > [data-plan="keepalive"] .plan-features { order: 1; margin-top: var(--space-2); }
.pass-row > [data-plan="keepalive"] .price-cta { order: 2; }

/* The date finder: one inline line above the cards (label, field, button on one row, same height). */
.picker-inline { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); padding: var(--space-3) var(--space-4); border-radius: var(--radius-m); background: var(--neon-tint); }
.picker-inline > label { font-weight: 650; font-size: var(--step--1); flex: 1 1 100%; min-width: 0; }
.picker-inline .field-hint { margin: 0; font-size: var(--step--2); color: var(--text-muted); flex: 1 1 100%; order: 3; }
.picker-row { display: flex; flex-wrap: nowrap; align-items: stretch; gap: var(--space-2); }
.picker-row input { flex: 0 1 calc(190 * var(--unit)); min-width: 0; background: var(--surface); }
.picker-inline .button { min-height: var(--tap-min); flex: none; }
/* The date finder reads as a designed field, not a raw browser date input. */
.picker-row input[type="date"] { appearance: none; -webkit-appearance: none; min-height: var(--tap-min); padding: 0 var(--space-3); border: 1px solid var(--line-input); border-radius: var(--radius-m); background: var(--surface); color: var(--text); font: inherit; font-variant-numeric: tabular-nums; }
.picker-row input[type="date"]:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
.picker-row input[type="date"]::-webkit-calendar-picker-indicator { cursor: pointer; opacity: 0.6; }
.picker-row input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: 1; }
.picker-row .button { flex: none; }
.field-error[hidden] { display: none; }
.picker-result:empty { display: none; }
.picker-result { display: grid; gap: var(--space-1); }
.picker-lead { margin: 0; color: var(--text-muted); font-size: var(--step--1); }
.picker-line { margin: 0; font-family: var(--font-display); font-size: var(--step-1); font-weight: 650; letter-spacing: -0.01em; line-height: 1.25; }
.picker-too-long { margin: 0; font-size: var(--step--1); }

/* Plans at a glance and Compare every plan: one column template on both (a fixed table layout, the first column
   22% and the plan columns sharing the rest equally), one width: the plan columns line up exactly. */
.plan-scroll { overflow-x: auto; }
.plan-scroll:focus-visible { outline-offset: 2px; }
.plan-table { table-layout: fixed; margin: 0; }
.plan-table tr > :first-child { width: 24%; }
/* Numbers and values right-align under each plan so they read down a clean edge; the row label stays left. */
.plan-table th[scope="col"], .plan-table td { text-align: right; font-variant-numeric: tabular-nums; }
.plan-table th[scope="row"] { text-align: left; font-weight: 650; color: var(--text); }
.plan-table td { color: var(--text-muted); }
.plan-table th[scope="col"] { font-family: var(--font-display); font-size: var(--step-0); font-weight: 650; color: var(--text); border-bottom: 2px solid var(--line-strong); }
/* The comparison (owner 2026-10-14): one open table of the five subscription plans, auto layout so the
   columns fill the width. ~15 headline rows show by default; the rest sit behind "Show all features". */
.compare-table { table-layout: fixed; width: 100%; }
.compare-table th[scope="col"] { text-align: center; }
/* The first column (feature labels) is left-aligned and wide enough that labels stay on one line. */
.compare-table th[scope="col"]:first-child { text-align: left; width: 30%; }
.compare-table th[scope="row"] { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 500; }
.compare-table td { text-align: center; color: var(--text); }
.compare .section-head { margin-bottom: var(--space-5); }
/* The plan header stays in view while the comparison scrolls. */
.compare-table thead th { position: sticky; top: 0; z-index: 2; background: var(--bg); }
/* Values read as checks, dashes and short values in the body font; differences stand out by weight/colour. */
.cmp-ico { font-size: var(--step-0); line-height: 1; font-variant-numeric: tabular-nums; }
.compare-table td.c-yes .cmp-ico { color: var(--brand); font-weight: 700; }
.compare-table td.c-no { color: var(--text-muted); }
.compare-table td.c-no .cmp-ico { color: var(--line-strong); }
.compare-table td.c-val { font-weight: 600; font-variant-numeric: tabular-nums; }
.compare-table td[data-fit], .compare-table thead th[data-fit] { background: var(--neon-tint); }
/* The non-headline rows and groups appear only when "Show all features" is ticked. */
.compare-table .cmp-extra, .compare-table .cmp-group-extra { display: none; }
.compare:has(#cmp-all:checked) .compare-table .cmp-extra { display: table-row; }
.compare:has(#cmp-all:checked) .compare-table .cmp-group-extra { display: table-row-group; }
.compare-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-3) var(--space-6); max-width: none; }
.compare-head h2 { margin: 0; }
.compare-all { font-size: var(--step--1); align-items: center; min-height: var(--tap-min); }
/* Each yaml group is a tbody that opens with a sub-header row; the header never repeats (owner 2026-10-14). */
.compare-group-head > th { position: sticky; top: calc(var(--tap-min)); z-index: 1; text-align: left; font-family: var(--font-display); font-weight: 650; font-size: var(--step--1); letter-spacing: 0.02em; text-transform: uppercase; color: var(--text-muted); padding-top: var(--space-5); padding-bottom: var(--space-2); background: var(--bg); border-bottom: 1px solid var(--line); }
.compare-table tbody:first-of-type .compare-group-head > th { padding-top: var(--space-3); }
.compare-scroll { margin-bottom: var(--space-4); }
@media (width < 760px) {
  /* Phones and small tablets: the table scrolls sideways with a sticky feature column. */
  .compare-table { table-layout: auto; min-width: calc(560 * var(--unit)); }
  .compare-table th[scope="col"]:first-child, .compare-table th[scope="row"] { width: calc(150 * var(--unit)); }
  .compare-table tr > :first-child { position: sticky; left: 0; background: var(--bg); z-index: 1; }
}
.compare-legend { max-width: var(--measure); margin-top: var(--space-4); }
.pricing-md { margin-top: var(--space-6); }

/* Questions: the answer cards (3 by 2) and the FAQ as a clean two-column accordion; items stay collapsible. */
.pricing .qa .faq { max-width: none; }
@media (width >= 760px) { .pricing .qa .faq { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--space-7); align-items: start; } }
.pricing .qa-cards { grid-template-columns: minmax(0, 1fr); }
@media (width >= 600px) { .pricing .qa-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Columns that divide the count: 4 cards in one row, 6 in two rows of 3, 3 in one row. */
@media (width >= 900px) { .pricing .qa-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); } .pricing .qa-cards:has(> :nth-child(4):last-child) { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.pricing .qa-card { border-radius: var(--radius-l); }
.pricing .qa-kicker { text-transform: none; letter-spacing: 0; font-size: var(--step-0); color: var(--text); font-weight: 650; }


/* Motion: prices rise in when the billing period changes; the date-matched pass rises in with a soft ring. */
@media (prefers-reduced-motion: no-preference) {
  .pricing.is-billing-live .price-side { animation: price-in 240ms var(--ease-out) both; }
  .pass-row > .price-card.is-picked { animation: pass-in 600ms var(--ease-out) both; }
  .picker-result.is-in { animation: price-in 240ms var(--ease-out) both; }
}
@keyframes price-in { from { opacity: 0; transform: translateY(calc(8 * var(--unit))); } }
@keyframes pass-in { 0% { opacity: 0; transform: translateY(calc(12 * var(--unit))); } 60% { opacity: 1; transform: none; } }

.site-page { max-width: var(--measure); }
.site-page-head { margin-bottom: var(--space-8); }
.site-page-head h1 { margin-bottom: var(--space-4); }
.site-sections > section + section { margin-top: var(--space-8); }
.site-sections h2 { font-size: var(--step-2); }
.section-tight { margin-top: var(--space-8); }
.site-page .pillars { max-width: none; }
.about-tagline { font-family: var(--font-display); font-size: var(--step-2); font-weight: 650; color: var(--brand-tint-text); margin: 0 0 var(--space-4); }
.site-list { padding-left: var(--space-6); }
.site-list li + li { margin-top: var(--space-2); }
.site-links { list-style: none; padding: 0; margin: 0 0 var(--space-4); display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); }
.site-links a { display: inline-flex; align-items: center; min-height: var(--tap-min); }
.contact-mail { margin: var(--space-5) 0 0; }

.status-summary { display: flex; align-items: center; gap: var(--space-3); font-family: var(--font-display); font-size: var(--step-2); font-weight: 700; margin: 0 0 var(--space-6); }
.status-dot { flex: none; width: calc(14 * var(--unit)); height: calc(14 * var(--unit)); border-radius: 50%; background: var(--status-active-dot); box-shadow: 0 0 0 calc(5 * var(--unit)) var(--status-active-bg); }
.status-summary.is-down .status-dot { border-radius: 3px; background: var(--status-danger-dot); box-shadow: 0 0 0 calc(5 * var(--unit)) var(--status-danger-bg); }
.status-list { list-style: none; margin: 0 0 var(--space-5); padding: 0; border-top: 1px solid var(--line); }
.status-item { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3) var(--space-5); padding: var(--space-5) 0; border-bottom: 1px solid var(--line); }
.status-item h2 { font-size: var(--step-1); margin: 0 0 var(--space-1); }
.status-item p { margin: 0; }

.legal-page h2 { scroll-margin-top: var(--space-6); }
.legal-page h1, .site-page h1, .pricing-head h1 { hyphens: auto; overflow-wrap: break-word; }
.legal-binding { margin: var(--space-5) 0; }
.legal-page table { display: table; table-layout: fixed; width: 100%; }
.legal-page th, .legal-page td { overflow-wrap: anywhere; hyphens: auto; }
.legal-others { margin-top: var(--space-10); padding-top: var(--space-6); border-top: 1px solid var(--line); }
.legal-others h2 { font-size: var(--step-1); margin-top: 0; }
/* ==================== site-pages:end ==================== */

/* ==================== templates:start (views/site/templates, src/site/templates/grid.ts) ====================
   The template hub and category galleries (UX v3). Every grid lands on full rows: the column counts here
   match TILE_COLUMNS and COLLECTION_COLUMNS, and a grid whose count does not divide them ends with one
   closing tile spanning exactly the cells the last row leaves (data-spanN, 0 hides it at N columns).
   One tile shape everywhere: a sunken well at 4:5 with the preview contained, captions on a subgrid. */
.tpl-well { display: grid; place-items: center; aspect-ratio: 4 / 5; padding: 9%; border-radius: var(--radius-m); background: var(--surface-sunken); overflow: hidden; }
.tpl-well img { display: block; width: 100%; height: 100%; object-fit: contain; }
/* Previews are printed things: in dark they keep a paper-light well, or dark inks would vanish; the
   light table under them stays a soft wash in dark instead of a dark green slab. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tpl-well { background: color-mix(in srgb, var(--fixed-white) 88%, var(--surface-sunken)); }
  :root:not([data-theme="light"]) :is(.tpl-coll-end, .tpl-point-show, .tpl-tile-end) { background: color-mix(in srgb, var(--neon-tint) 55%, var(--surface)); }
}
:root[data-theme="dark"] .tpl-well { background: color-mix(in srgb, var(--fixed-white) 88%, var(--surface-sunken)); }
:root[data-theme="dark"] :is(.tpl-coll-end, .tpl-point-show, .tpl-tile-end) { background: color-mix(in srgb, var(--neon-tint) 55%, var(--surface)); }
a.tpl-well, .tpl-strip { transition: transform var(--dur-hover) var(--ease-out), box-shadow var(--dur-hover) var(--ease-out); }

/* Head: H1, one line, the chips in one row (scrolling sideways on phones). */
.tpl-head { margin-top: var(--space-8); }
.tpl-head h1 { max-width: 20ch; margin: 0 0 var(--space-3); font-size: var(--step-5); letter-spacing: -0.03em; }
.tpl-sub { max-width: 60ch; margin: 0 0 var(--space-6); font-size: var(--step-1); color: var(--text-muted); }
.tpl-filters { min-inline-size: 0; margin: 0; padding: 0; border: 0; }
.tpl-chips { display: flex; flex-wrap: nowrap; gap: var(--space-2); min-width: 0; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; padding-block: calc(5 * var(--unit)); }
.tpl-chips::-webkit-scrollbar { display: none; }
.tpl-chips .chip { flex: none; }
@media (width < 760px) {
  .tpl-chips { margin-inline: calc(-1 * var(--gutter)); padding-inline: var(--gutter); scroll-snap-type: x proximity; scroll-padding-inline: var(--gutter); }
  .tpl-chips .chip { scroll-snap-align: start; }
}
.tpl-groups { margin-top: var(--space-7); }

/* Collections: one aligned grid, 3/2/1 columns; title, text, a full row of three previews, count and action. */
.tpl-colls { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-5); grid-template-columns: minmax(0, 1fr); }
.tpl-coll { position: relative; display: grid; grid-template-rows: subgrid; grid-row: span 4; row-gap: var(--space-3); padding: var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-l); background: var(--surface); transition: transform var(--dur-hover) var(--ease-out), box-shadow var(--dur-hover) var(--ease-out), border-color var(--dur-hover) var(--ease-out); }
.tpl-coll h3 { margin: 0; font-size: var(--step-2); letter-spacing: -0.01em; line-height: var(--leading-snug); }
.tpl-coll h3 a { color: var(--text); text-decoration: none; }
.tpl-coll h3 a::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.tpl-coll-text { margin: 0; color: var(--text-muted); font-size: var(--step--1); }
.tpl-strip { position: relative; z-index: 1; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-2); }
.tpl-coll-foot { position: relative; z-index: 1; display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin: 0; }
.tpl-count { color: var(--text-muted); font-size: var(--step--1); font-variant-numeric: tabular-nums; }
.tpl-coll-go { font-weight: 650; }
.tpl-coll:not(.tpl-coll-end):hover { transform: translateY(-2px); box-shadow: var(--shadow-2); border-color: var(--line-strong); }
.tpl-coll:has(h3 a:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
.tpl-coll h3 a:focus-visible { outline: none; }
.tpl-coll-end { display: flex; flex-direction: column; gap: var(--space-3); background: var(--neon-tint); border-color: var(--line); }
.tpl-coll-end .tpl-coll-foot { margin-top: auto; justify-content: flex-start; }
.tpl-blank { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.tpl-blank .tpl-well { grid-column: 2; background: var(--fixed-white); box-shadow: var(--shadow-1); }
@media (width >= 600px) {
  .tpl-colls { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tpl-coll-end[data-span2="0"] { display: none; }
}
@media (width >= 900px) {
  .tpl-colls { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .tpl-coll-end[data-span2] { display: flex; }
  .tpl-coll-end[data-span3="0"] { display: none; }
  .tpl-coll-end[data-span3="2"] { grid-column: span 2; }
}
/* Filters (radios, no script): slot N shows the collections that list N; the closing card shows on "All" only. */
@supports selector(:has(*)) {
  .tpl-hub:has(input[data-slot]:checked) .tpl-coll-end { display: none; }
  .tpl-hub:has(input[data-slot="1"]:checked) .tpl-coll:not([data-in~="1"]),
  .tpl-hub:has(input[data-slot="2"]:checked) .tpl-coll:not([data-in~="2"]),
  .tpl-hub:has(input[data-slot="3"]:checked) .tpl-coll:not([data-in~="3"]),
  .tpl-hub:has(input[data-slot="4"]:checked) .tpl-coll:not([data-in~="4"]),
  .tpl-hub:has(input[data-slot="5"]:checked) .tpl-coll:not([data-in~="5"]) { display: none; }
}

/* How to choose: the head beside three points, each shown with real designs on a lit light table. */
.tpl-choose { display: grid; gap: var(--space-7); }
.tpl-choose-head h2 { margin: 0 0 var(--space-4); }
.tpl-choose-head .home-answer { font-size: var(--step--1); }
.tpl-choose-head .small { margin-top: var(--space-3); }
.tpl-points { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-6) var(--space-5); grid-template-columns: minmax(0, 1fr); }
.tpl-point { display: grid; grid-template-rows: subgrid; grid-row: span 3; row-gap: var(--space-2); }
.tpl-point h3 { margin: var(--space-2) 0 0; font-size: var(--step-1); }
.tpl-point p { margin: 0; color: var(--text-muted); font-size: var(--step--1); }
.tpl-point-show { display: flex; align-items: center; justify-content: center; gap: var(--space-4); aspect-ratio: 4 / 3; padding: var(--space-5); border-radius: var(--radius-l); background: var(--neon-tint); }
.tpl-point-show .tpl-well { height: 100%; aspect-ratio: 4 / 5; background: var(--fixed-white); box-shadow: var(--shadow-2); }
.tpl-point:first-child .tpl-point-show[data-n="2"] .tpl-well:first-child { height: 62%; }
.tpl-point-show[data-n="2"] .tpl-well { height: 86%; }
@media (width < 600px) { .tpl-point-show { aspect-ratio: 2 / 1; } }
@media (width >= 600px) { .tpl-points { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (width >= 900px) { .tpl-choose { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); column-gap: var(--space-9); align-items: start; } }
.tpl-hub .faq, .tpl-cat .faq { max-width: none; }

/* Category gallery: 6/5/4/2 columns of one tile (well, name, action) on a subgrid, so names and buttons align. */
.tpl-tiles { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-6) var(--space-4); grid-template-columns: repeat(2, minmax(0, 1fr)); }
.tpl-tile { position: relative; display: grid; grid-template-rows: subgrid; grid-row: span 3; row-gap: var(--space-2); align-content: start; }
.tpl-tile > .tpl-badge { position: absolute; top: var(--space-2); right: var(--space-2); background: var(--surface); }
.tpl-tile h3 { margin: var(--space-1) 0 0; font-family: var(--font-text); font-size: var(--step--1); font-weight: 650; letter-spacing: 0; line-height: var(--leading-snug); }
.tpl-tile h3 a { color: var(--text); text-decoration: none; }
.tpl-tile h3 a:hover { text-decoration: underline; }
.tpl-tile-foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0; }
.tpl-badge { padding: 0 var(--space-2); border: 1px solid var(--line); border-radius: var(--radius-pill); color: var(--text-muted); font-size: var(--step--2); line-height: 1.6; white-space: nowrap; }
.tpl-tile:hover a.tpl-well { transform: translateY(-2px); box-shadow: var(--shadow-2); }
.tpl-tile[data-chosen] a.tpl-well { box-shadow: inset 0 0 0 1.5px var(--brand), var(--shadow-2); }
.tpl-tile-end { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-l); background: var(--neon-tint); }
.tpl-tile-end h3 { font-family: var(--font-display); font-size: var(--step-1); }
.tpl-tile-end p { margin: 0; color: var(--text-muted); font-size: var(--step--1); }
.tpl-tile-end .tpl-tile-foot { margin-top: auto; }
.tpl-tile-end[data-span2="0"] { display: none; }
@media (width >= 600px) {
  .tpl-tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .tpl-tile-end[data-span2] { display: flex; }
  .tpl-tile-end[data-span4="0"] { display: none; }
  .tpl-tile-end[data-span4="2"] { grid-column: span 2; }
  .tpl-tile-end[data-span4="3"] { grid-column: span 3; }
}
@media (width >= 900px) {
  .tpl-tiles { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .tpl-tile-end[data-span4] { display: flex; grid-column: auto; }
  .tpl-tile-end[data-span5="0"] { display: none; }
  .tpl-tile-end[data-span5="2"] { grid-column: span 2; }
  .tpl-tile-end[data-span5="3"] { grid-column: span 3; }
  .tpl-tile-end[data-span5="4"] { grid-column: span 4; }
}
@media (width >= 1100px) {
  .tpl-tiles { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .tpl-tile-end[data-span5] { display: flex; grid-column: auto; }
  .tpl-tile-end[data-span6="0"] { display: none; }
  .tpl-tile-end[data-span6="2"] { grid-column: span 2; }
  .tpl-tile-end[data-span6="3"] { grid-column: span 3; }
  .tpl-tile-end[data-span6="4"] { grid-column: span 4; }
  .tpl-tile-end[data-span6="5"] { grid-column: span 5; }
}
@media (prefers-reduced-motion: reduce) {
  .tpl-coll, a.tpl-well { transition: none; }
  .tpl-coll:not(.tpl-coll-end):hover, .tpl-tile:hover a.tpl-well { transform: none; }
}
/* ==================== templates:end ==================== */
/* ==================== studio:start ==================== */
/* Design studio (views/studio). The print mat: the preview sits on a sunken surface with a faint grid
   and a live ruler, so the design is always seen at a printed size. */
.studio-head { margin-bottom: var(--space-4); }
/* The app's field and layout rules set display; the hidden attribute must still win in the studio. */
.studio [hidden], .studio-export [hidden], .studio-red[hidden] { display: none !important; }
.studio-head p { margin: 0; }

.studio {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: minmax(calc(220 * var(--unit)), calc(280 * var(--unit))) minmax(0, 1fr) minmax(calc(260 * var(--unit)), calc(340 * var(--unit)));
  align-items: start;
}

/* Library ------------------------------------------------------------------------------------ */
.studio-library, .studio-controls { min-width: 0; }
/* The four library tabs can be wider than the ~220px column: a strip that scrolls sideways within
   itself, the scrollbar hidden and the trailing edge faded so the overflow reads as "more to the side". */
.studio-tabs { display: flex; flex-wrap: nowrap; gap: var(--space-1); border-bottom: 1px solid var(--line); margin-bottom: var(--space-3); overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; scroll-snap-type: x proximity; mask-image: linear-gradient(to right, var(--fixed-white) calc(100% - calc(18 * var(--unit))), transparent); }
.studio-tabs::-webkit-scrollbar { display: none; }
.studio-tabs [role="tab"] {
  appearance: none; background: none; border: 0; border-bottom: 3px solid transparent;
  padding: var(--space-2) var(--space-1); min-height: var(--tap-min); font: inherit; font-size: var(--step--1); color: var(--text-muted); cursor: pointer; white-space: nowrap; scroll-snap-align: start;
}
.studio-tabs [role="tab"][aria-selected="true"] { color: var(--text); border-bottom-color: var(--brand); font-weight: 700; }
.studio-panel { max-height: 72vh; overflow-y: auto; overflow-x: hidden; padding-right: var(--space-1); }
.studio-filter { display: grid; gap: var(--space-1); margin-bottom: var(--space-3); }
.studio-group-title { font-size: var(--step--1); color: var(--text-muted); margin: var(--space-4) 0 var(--space-2); font-weight: 700; }
.studio-tiles { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(calc(96 * var(--unit)), 1fr)); gap: var(--space-2); }
.studio-tile {
  appearance: none; width: 100%; display: grid; gap: var(--space-1); justify-items: center; text-align: center;
  padding: var(--space-2); border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--surface);
  color: var(--text); font: inherit; font-size: var(--step--2); cursor: pointer;
}
.studio-tile:hover { border-color: var(--line-strong); }
.studio-tile[aria-pressed="true"] { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); background: var(--brand-tint); }
.studio-thumb { display: grid; place-items: center; width: calc(72 * var(--unit)); height: calc(72 * var(--unit)); overflow: hidden; }
.studio-thumb svg { width: 100%; height: 100%; }
.studio-tile-name { line-height: var(--leading-snug); }
.studio-swatches { width: calc(42 * var(--unit)); height: calc(14 * var(--unit)); color: var(--text); flex: none; }
.studio-thumb .studio-swatches { width: calc(60 * var(--unit)); height: calc(20 * var(--unit)); }
.studio-kits { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.studio-kits li { display: flex; align-items: center; gap: var(--space-2); }
.studio-match { display: grid; gap: var(--space-3); margin-top: var(--space-5); padding-top: var(--space-4); border-top: 1px solid var(--line); }
.studio-match[hidden], .studio-match-result[hidden] { display: none; }
.studio-match-inputs { display: grid; gap: var(--space-3); justify-items: start; }
.studio-match-site { display: grid; gap: var(--space-1); width: 100%; }
.studio-match-result { display: grid; gap: var(--space-3); }
/* Colours and the kit name share the first row (the name truncates); the long "Save as brand kit"
   button sits whole on the next row, so it never rides over the name. */
.studio-match-kit { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: var(--space-1) var(--space-2); }
.studio-match-kit .studio-swatches { width: calc(42 * var(--unit)); height: calc(14 * var(--unit)); }
.studio-match-kit [data-match-save] { grid-column: 1 / -1; justify-self: start; }
.studio-match .studio-thumb svg { width: 100%; height: 100%; }
.studio-kit-name { flex: 1; min-width: 0; }
.studio-match-kit .studio-kit-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Stage: the print mat -------------------------------------------------------------------------- */
.studio-stage { position: sticky; top: var(--space-4); display: grid; gap: var(--space-3); }
.studio-mat {
  background-color: var(--surface-sunken);
  background-image:
    linear-gradient(to right, var(--line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line) 1px, transparent 1px);
  background-size: calc(40 * var(--unit)) calc(40 * var(--unit));
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  padding: var(--space-7) var(--space-5) var(--space-4);
  display: grid; justify-items: center; gap: var(--space-3);
}
.studio-figure { margin: 0; width: min(100%, calc(420 * var(--unit))); }
.studio-preview { display: grid; place-items: center; min-height: calc(240 * var(--unit)); }
.studio-preview svg { width: 100%; height: auto; max-height: 60vh; display: block; }
.studio-ruler { width: min(100%, calc(420 * var(--unit))); display: grid; gap: var(--space-1); justify-items: center; font-size: var(--step--1); color: var(--text-muted); }
.studio-ruler-bar {
  width: 100%; height: calc(10 * var(--unit)); border: 1px solid var(--text-muted); border-top: 0;
  background-image: linear-gradient(to right, var(--text-muted) 1px, transparent 1px);
  background-size: 10% 100%;
}
.studio-badge {
  margin: 0; padding: var(--space-2) var(--space-3); border-radius: var(--radius-s); font-weight: 700;
  background: var(--status-active-bg); color: var(--status-active-text);
}
.studio-badge[data-verdict="amber"] { background: var(--status-trial-bg); color: var(--status-trial-text); }
.studio-badge[data-verdict="red"] { background: var(--status-danger-bg); color: var(--status-danger-text); }
/* Busy: a lighter weight, never a lower contrast (UX-020). */
.studio-badge[data-busy="true"] { font-weight: 400; }
.studio-note { margin: 0; color: var(--text-muted); min-height: 1lh; }
.studio-note:empty { min-height: 0; }
.studio-note[data-level="bad"], .studio-note[data-level="error"] { color: var(--status-danger-text); }
.studio-note[data-level="low"], .studio-note[data-level="inverted"] { color: var(--status-trial-text); }
.studio-note[data-level="ok"] { color: var(--status-active-text); }
.studio-print summary, .studio-group summary { cursor: pointer; font-weight: 700; min-height: var(--tap-min); display: flex; align-items: center; }
/* A chevron so these collapsed sections read as "open me", not an orphan heading with nothing under it. */
.studio-print > summary, .test-scan > summary { justify-content: space-between; gap: var(--space-2); }
.studio-print > summary::after, .test-scan > summary::after { content: ""; flex: none; width: calc(8 * var(--unit)); height: calc(8 * var(--unit)); border-right: 2px solid var(--text-muted); border-bottom: 2px solid var(--text-muted); transform: translateY(-2px) rotate(45deg); transition: transform 160ms var(--ease-out); }
.studio-print[open] > summary::after, .test-scan[open] > summary::after { transform: translateY(2px) rotate(-135deg); }
.studio-actions { flex-wrap: wrap; }
.studio-content textarea { width: 100%; }

/* Controls -------------------------------------------------------------------------------------- */
.studio-controls { display: grid; gap: var(--space-2); }
.studio-group { border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--surface); padding: 0 var(--space-3); }
.studio-group[open] { padding-bottom: var(--space-3); }
.studio-group fieldset { border: 0; padding: 0; margin: 0 0 var(--space-3); min-width: 0; }
.studio-group legend { font-weight: 700; font-size: var(--step--1); margin-bottom: var(--space-2); padding: 0; }
.studio-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(calc(120 * var(--unit)), 1fr)); gap: var(--space-3); margin-bottom: var(--space-3); }
.studio-fields .field { margin: 0; }
/* A print size is a 2-4 digit value in mm: keep the field compact rather than a full-width box. */
.studio-fields .field input[type="number"] { max-width: calc(120 * var(--unit)); }
.studio-row { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); }
.studio-choice { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--tap-min); }
.studio-shapes { display: grid !important; grid-template-columns: repeat(auto-fill, minmax(calc(44 * var(--unit)), 1fr)); gap: var(--space-1); }
.studio-shapes legend { grid-column: 1 / -1; }
.studio-shape { display: grid; place-items: center; min-height: var(--tap-min); border: 1px solid var(--line); border-radius: var(--radius-xs); cursor: pointer; color: var(--text); }
.studio-shape input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.studio-shape:has(input:checked) { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); background: var(--brand-tint); color: var(--brand); }
.studio-shape:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: 1px; }
.studio-swatch { width: calc(28 * var(--unit)); height: calc(28 * var(--unit)); }
input[type="color"] { min-height: var(--tap-min); width: 100%; padding: 2px; }
input[type="range"] { width: 100%; }

/* Export dialog and the red interruption ------------------------------------------------------ */
.studio-export { border: 1px solid var(--line); border-radius: var(--radius-m); padding: var(--space-5); max-width: min(calc(560 * var(--unit)), calc(100vw - calc(32 * var(--unit)))); background: var(--surface); color: var(--text); }
.studio-export::backdrop { background: var(--overlay); }
.studio-export h2 { margin-top: 0; }
.studio-formats { border: 0; padding: 0; margin: 0 0 var(--space-3); display: grid; }
.studio-red {
  position: fixed; inset: auto var(--space-4) var(--space-4) auto; max-width: calc(420 * var(--unit)); z-index: 30;
  background: var(--surface-raised); border: 2px solid var(--danger-solid); border-radius: var(--radius-m); padding: var(--space-4); box-shadow: var(--shadow-3);
}
.studio-red h2 { margin-top: 0; font-size: var(--step-1); }

/* Gallery ------------------------------------------------------------------------------------- */
.studio-gallery-filter { display: grid; gap: var(--space-3); margin-bottom: var(--space-4); }
.studio-gallery-filter .studio-filter { margin: 0; }
.studio-gallery-filter [hidden] { display: none; }
.chip-dot { flex: none; margin-right: calc(6 * var(--unit)); }
.chip-dot circle { stroke: var(--line-strong); stroke-width: 1; }
.studio-gallery-filter .field { margin: 0; }
.studio-gallery { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(calc(190 * var(--unit)), 1fr)); gap: var(--space-4); }
.studio-card { border: 1px solid var(--line); border-radius: var(--radius-s); padding: var(--space-3); display: grid; gap: var(--space-2); align-content: start; background: var(--surface); }
.studio-card-art { aspect-ratio: 3 / 4; display: grid; place-items: center; background: var(--surface-sunken); border-radius: var(--radius-xs); padding: var(--space-3); }
.studio-card-art svg:not(.studio-swatches) { width: 100%; height: 100%; }
.studio-card-title { font-size: var(--step-0); margin: 0; }
.studio-card p { margin: 0; }

/* Brand kits ---------------------------------------------------------------------------------- */
.studio-kit-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.studio-kit-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--line); }
.studio-kit-main { flex: 1; min-width: calc(180 * var(--unit)); }
.studio-kit-title { margin: 0; font-size: var(--step-0); }
.studio-kit-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.studio-kit-actions form { margin: 0; }
.studio-kit-form fieldset { min-width: 0; }
/* The default-domain menu is sized to its hostnames, not stretched across the card (so its focus ring
   is a neat pill, not a wide green band). */
.studio-kit-domain select { width: auto; max-width: 100%; min-width: calc(180 * var(--unit)); justify-self: start; }
/* Save and Cancel sit in one aligned footer at the foot of the card. */
.studio-kit-foot { gap: var(--space-2); margin-top: var(--space-2); padding-top: var(--space-4); border-top: 1px solid var(--line); }
.studio-code-pick { border: 0; padding: 0; margin: 0; }
.studio-code-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-2); }
.studio-code-count { font-size: var(--step--1); font-weight: 650; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.studio-code-list { list-style: none; margin: 0; padding: 0; max-height: calc(320 * var(--unit)); overflow-y: auto; overflow-x: hidden; display: grid; border: 1px solid var(--line); border-radius: var(--radius-s); }
.studio-code-list li { border-top: 1px solid var(--line); }
.studio-code-list li:first-child { border-top: 0; }
.studio-code-list .studio-choice { width: 100%; padding: var(--space-1) var(--space-3); }
.studio-code-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.studio-link { margin-top: var(--space-4); }

/* Visual controls ------------------------------------------------------------------------------
   The generator's tile system (.gen-tiles / .tile / .swatch-pick / .dropzone, above) in the studio's
   narrow column: six tiles to a row, the tab strip as one segmented control, short exclusive choices as
   segmented pills, longer ones as option cards. */
.studio-controls { --cols: 6; --tile-gap: calc(8 * var(--unit)); gap: 0; }
.studio-controls .studio-ctl-tabs { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(max-content, 1fr); gap: 2px; padding: var(--space-1); border: 0; border-radius: var(--radius-m); background: var(--surface-sunken); overflow-x: auto; scrollbar-width: none; mask-image: linear-gradient(to right, var(--fixed-white) calc(100% - calc(18 * var(--unit))), transparent); }
.studio-controls .studio-ctl-tabs::-webkit-scrollbar { display: none; }
.studio-ctl-tabs [role="tab"] { min-height: calc(38 * var(--unit)); padding: 0 var(--space-1); border: 0; border-radius: calc(var(--radius-m) - 3px); font-size: var(--step--1); white-space: nowrap; }
.studio-ctl-tabs [role="tab"][aria-selected="true"] { background: var(--surface); box-shadow: 0 0 0 1px var(--line), var(--shadow-1); }
.studio-ctl { display: grid; gap: var(--space-5); align-content: start; }
.studio-ctl .gen-tiles + .gen-tiles { margin-top: 0; }
.studio-ctl .gen-tiles.is-large .tile { grid-column: span 2; }
.studio-ctl .tile[data-key] .tile-art, .studio-ctl .tile-art:has(svg) { background: transparent; }
.studio-ctl .tile-art[data-tile="face"] { color: var(--text); background: var(--surface); }
.studio-ctl .tile-art[data-tile="face"] svg { width: 80%; height: 80%; }
.studio-ctl .gen-tiles.is-large .tile { aspect-ratio: 3 / 2; }
.studio-ctl .tile-art[data-tile="face"] svg:not([viewBox]) { width: 86%; height: 56%; }
/* The typeface picker (DES-023): a search, then the popular set and one titled row of tiles per style, in a
   scrolling well so 60 faces stay one control. */
.studio-faces .studio-face-search { margin-bottom: var(--space-3); }
.studio-face-groups { display: grid; gap: var(--space-4); max-height: 30rem; overflow-y: auto; overscroll-behavior: contain; padding: calc(6 * var(--unit)); margin: -6px; }
.studio-face-group[hidden], .studio-faces .tile[hidden] { display: none; }
.studio-face-heading { margin: 0 0 var(--space-2); font-size: var(--step--1); font-weight: 700; color: var(--text-muted); }
.studio-colour .swatch-row { gap: 2px; }
.studio-colour .swatch-pick { width: var(--tap-min); height: var(--tap-min); }
.studio-sub { margin: 0 0 var(--space-2); font-weight: 700; }
.studio-photo [data-photo-controls], .studio-logo-controls, .studio-frame-controls { display: grid; gap: var(--space-4); }
.studio-photo [data-photo-controls] { margin-top: var(--space-3); }
.studio-ctl .dropzone { padding: var(--space-5) var(--space-4); }
.studio-ctl .gen-cta { margin-top: 0; }
.studio-ctl .gen-cta-chips { margin-top: var(--space-2); }

/* Segmented choice: radio buttons as joined pills; the checked one is a raised sheet. */
.seg { border: 0; padding: 0; margin: 0; min-width: 0; }
.seg legend { padding: 0; margin-bottom: var(--space-2); font-weight: 700; font-size: var(--step--1); }
.seg-row { display: inline-flex; flex-wrap: wrap; gap: 2px; padding: 3px; border-radius: var(--radius-m); background: var(--surface-sunken); max-width: 100%; }
.seg-option { position: relative; display: inline-grid; place-items: center; min-height: var(--tap-min); padding: 0 var(--space-3); border-radius: calc(var(--radius-m) - 3px); color: var(--text-muted); font-size: var(--step--1); font-weight: 650; cursor: pointer; }
.seg-option input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.seg-option:hover { color: var(--text); }
.seg-option:has(input:checked) { color: var(--text); background: var(--surface); box-shadow: 0 0 0 1px var(--line), var(--shadow-1); }
.seg-option:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: 1px; }
.studio-print .seg { margin-bottom: var(--space-3); }

/* Option cards: a radio with a sentence (error correction, export format). */
.studio-ecl, .studio-formats { border: 0; padding: 0; margin: 0; display: grid; gap: var(--space-1); min-width: 0; }
.studio-ecl legend, .studio-formats legend { padding: 0; margin-bottom: var(--space-2); font-weight: 700; }
.option-card { display: flex; gap: var(--space-3); align-items: center; min-height: var(--tap-min); padding: var(--space-2) var(--space-3); border: 1px solid var(--line-input); border-radius: var(--radius-s); background: var(--surface); font-size: var(--step--1); cursor: pointer; }
.option-card input { margin: 0; accent-color: var(--brand); }
.option-card:has(input:checked) { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); background: var(--brand-tint); }

/* Print layouts as sheets drawn to scale, the code in its place. */
.studio-layouts { border: 0; padding: 0; margin: 0 0 var(--space-3); min-width: 0; }
.studio-layouts legend { padding: 0; margin-bottom: var(--space-2); font-weight: 700; }
.studio-layout-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(calc(96 * var(--unit)), 1fr)); gap: var(--space-2); }
.studio-layout { position: relative; display: grid; justify-items: center; gap: var(--space-1); padding: var(--space-2); border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--surface); font-size: var(--step--2); text-align: center; line-height: var(--leading-snug); cursor: pointer; }
.studio-layout input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.studio-layout svg { width: calc(44 * var(--unit)); height: calc(44 * var(--unit)); }
.studio-layout-sheet { fill: var(--fixed-white); stroke: var(--line-strong); stroke-width: 0.8; }
.studio-layout-code { fill: var(--text); }
.studio-layout:has(input:checked) { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); background: var(--brand-tint); }
.studio-layout:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: 2px; }
.studio-export-size { display: flex; flex-wrap: wrap; align-items: end; gap: var(--space-3) var(--space-4); margin-bottom: var(--space-3); }
.studio-export-size .field { margin: 0; max-width: 9rem; }
.studio-export > form > .seg { margin-bottom: var(--space-3); }

/* Library chips and live thumbnails. */
.studio-filter { border: 0; padding: 0; margin: 0 0 var(--space-3); min-width: 0; }
.studio-filter legend { padding: 0; margin-bottom: var(--space-2); font-weight: 700; font-size: var(--step--1); }
/* The use-case and style chips wrap onto aligned rows and size to their label, so none is clipped mid-word. */
.studio-chips { gap: var(--space-2); flex-wrap: wrap; }
.studio-thumb-none svg { width: 60%; height: 60%; color: var(--text-muted); }

/* The proof: a peek (a tile under the pointer or focus) shows with a dashed outline; the proof pass sweeps once after a real decode. */
.studio-proof { position: relative; isolation: isolate; }
.studio-proof .proof-ghost { position: absolute; inset: 0 0 auto; }
.studio-figure.is-previewing .studio-preview { outline: 1px dashed var(--brand); outline-offset: calc(6 * var(--unit)); }
.studio-badge.is-stamping { animation: gen-stamp var(--dur-stamp) var(--ease-out) calc(var(--dur-sweep) - 60ms) both; }
.studio-badge.is-shaking { animation: gen-shake var(--dur-swap) var(--ease-out); }
@media (prefers-reduced-motion: reduce) {
  .studio-badge.is-fading { animation: gen-fade-in var(--dur-calm) linear both !important; }
}

/* Brand kit form: the form beside a sticky sample code in the kit. */
.studio-kit-layout { display: grid; gap: var(--space-6); align-items: start; }
@media (width >= 900px) { .studio-kit-layout { grid-template-columns: minmax(0, 1fr) calc(300 * var(--unit)); } }
/* The preview is the grid column itself, so it sticks through the whole (very tall) form; the inner block
   only lays its pieces out. Sticky needs the column to start-align, which the layout already does. */
@media (width >= 900px) { .studio-kit-preview { position: sticky; top: var(--space-5); align-self: start; } }
.studio-kit-preview-in { display: grid; gap: var(--space-3); }
.studio-kit-mat { padding: var(--space-5); }
.studio-kit-mat.is-previewing .studio-preview { outline: 1px dashed var(--brand); outline-offset: calc(6 * var(--unit)); }
.studio-kit-form { --cols: 8; --tile-gap: calc(8 * var(--unit)); }
.studio-kit-cards { display: grid; gap: var(--space-5); }
.studio-kit-cards .gen-tiles + .gen-tiles { margin-top: 0; }
.studio-kit-cards .gen-tiles.is-large .tile { aspect-ratio: 3 / 2; }
.studio-kit-form .tile-art[data-tile="face"], .studio-kit-form .tile-art:not([data-key]) { color: var(--text); }
.studio-kit-form .tile-art[data-tile="face"] svg { width: 80%; height: 80%; }
.studio-kit-form .tile-art[data-tile="kit-frame"] svg { width: 100%; height: 100%; }
.studio-kit-form .gen-tiles.is-large .tile-art[data-tile="kit-frame"] { padding: 6%; }
.studio-images .tile-art img { padding: 10%; }
.studio-file-initial { font-weight: 700; font-size: var(--step--1); color: var(--text-muted); text-transform: none; }
@media (width < 760px) { .studio-kit-form { --cols: 5; } }

/* Tablet and phone ------------------------------------------------------------------------------ */
@media (width < 1100px) {
  .studio { grid-template-columns: minmax(0, 1fr) minmax(calc(260 * var(--unit)), calc(340 * var(--unit))); }
  .studio-library { grid-column: 1 / -1; order: 2; }
  .studio-stage { order: 1; }
  .studio-controls { order: 1; }
  .studio-panel { max-height: none; }
}
@media (width < 760px) {
  .studio { grid-template-columns: minmax(0, 1fr); }
  /* Only the mat stays in view while the controls scroll under it. */
  .studio-stage { position: static; }
  .studio-mat { position: sticky; top: 0; z-index: 5; padding: var(--space-2); }
  .studio-preview { min-height: 0; }
  .studio-preview svg { max-height: 28vh; }
  .studio-ruler { display: none; }
  .studio-red { inset: auto var(--space-4) var(--space-4) var(--space-4); }
  /* The library becomes sideways rails, so the controls stay close to the proof. */
  .studio-library .studio-tiles { grid-auto-flow: column; grid-template-columns: none; grid-auto-columns: calc(112 * var(--unit)); overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity; scrollbar-width: none; padding-bottom: var(--space-1); }
  .studio-library .studio-tiles > li { scroll-snap-align: start; }
}
/* ==================== studio:end ==================== */

/* Type picker and catalogue forms (03 TYP-120/121; views/types). */
.gen:has(input[name="type"][value="catalog"]:checked) [data-panel="catalog"] { display: grid; }
.type-picker { margin-bottom: var(--space-5); }
.type-picker > summary { cursor: pointer; font-weight: 700; }
.type-search { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: end; margin: var(--space-4) 0; }
.type-pick-h { font-size: var(--step-0); margin: var(--space-4) 0 var(--space-2); }
.type-picks { list-style: none; padding: 0; display: grid; gap: var(--space-2); grid-template-columns: repeat(auto-fill, minmax(calc(180 * var(--unit)), 1fr)); }
.type-pick { display: grid; grid-template-columns: auto 1fr; gap: 0 var(--space-2); align-items: center; padding: var(--space-2) var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-m, calc(8 * var(--unit))); text-decoration: none; color: inherit; }
.type-pick.is-current { border-color: currentColor; }
.type-pick-modes { grid-column: 2; font-size: var(--step--1, 0.85rem); opacity: 0.75; }
.type-jobs ul { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-2); }
.phone-mock { margin: var(--space-4) 0 0; max-width: calc(240 * var(--unit)); }
.phone-mock-screen { border: 2px solid var(--line); border-radius: calc(28 * var(--unit)); padding: var(--space-6) var(--space-3); min-height: calc(160 * var(--unit)); display: grid; align-items: center; }
.phone-mock-card { display: grid; justify-items: center; gap: var(--space-2); text-align: center; padding: var(--space-3); border: 1px solid var(--line); border-radius: calc(12 * var(--unit)); }
.phone-mock-line { overflow-wrap: anywhere; margin: 0; }

/* Sign-in "More options" (09 ACC-001) */
.more-options { margin-top: var(--space-6); border-top: 1px solid var(--line); padding-top: var(--space-4); }
.more-options > summary { cursor: pointer; font-weight: 600; }
.more-options[open] > summary { margin-bottom: var(--space-4); }
/* Provider buttons: full width, the brand mark at its own colours left of the label (LEG-027). */
.signin .oauth { flex-direction: column; align-items: stretch; }
.signin .oauth .provider { width: 100%; }
.provider-mark { width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); flex: none; }
.signin-or { display: flex; align-items: center; gap: var(--space-3); margin: var(--space-2) 0 var(--space-4); color: var(--text-muted); font-size: var(--step--1); }
.signin-or::before, .signin-or::after { content: ""; flex: 1; border-top: 1px solid var(--line); }
.more-options .oauth { margin-top: 0; }
/* Sign-up honeypot (ACC-005): out of view and out of the tab order; people never reach it. */
.hp-field { position: absolute !important; left: calc(-10000 * var(--unit)); width: 1px; height: 1px; overflow: hidden; }

/* ==================== onboarding:start ====================
   The app's first run (src/onboarding, views/onboarding, client/app/onboarding.ts): the checklist's
   progress bar, "Your code is ready" with its proof sheet and live first-scan row, and the walkthrough
   (a crop-mark spotlight and a step card). Motion: transform, opacity and clip-path only; under reduced
   motion the global rule above removes every transition and animation, and the content stays the same. */
.ob-progress { height: calc(6 * var(--unit)); margin: var(--space-2) 0 var(--space-1); background: var(--surface-sunken); border-radius: var(--radius-pill); overflow: hidden; }
.ob-progress-bar { display: block; height: 100%; background: var(--brand-fill); transform-origin: 0 50%; transform: scaleX(0); transition: transform 240ms var(--ease-out); }
.ob-progress[data-pct="20"] .ob-progress-bar { transform: scaleX(0.2); }
.ob-progress[data-pct="25"] .ob-progress-bar { transform: scaleX(0.25); }
.ob-progress[data-pct="33"] .ob-progress-bar { transform: scaleX(0.333); }
.ob-progress[data-pct="40"] .ob-progress-bar { transform: scaleX(0.4); }
.ob-progress[data-pct="50"] .ob-progress-bar { transform: scaleX(0.5); }
.ob-progress[data-pct="60"] .ob-progress-bar { transform: scaleX(0.6); }
.ob-progress[data-pct="67"] .ob-progress-bar { transform: scaleX(0.667); }
.ob-progress[data-pct="75"] .ob-progress-bar { transform: scaleX(0.75); }
.ob-progress[data-pct="80"] .ob-progress-bar { transform: scaleX(0.8); }
.ob-progress[data-pct="100"] .ob-progress-bar { transform: scaleX(1); }

/* The job picker (views/onboarding/chips.ejs): the chips, then one button; the source question waits folded beside it. */
.ob-start .ob-jobs { border: 0; padding: 0; min-width: 0; }
.ob-start .ob-question { padding: 0; margin-bottom: var(--space-2); font-size: var(--step--1); color: var(--text-muted); }
.ob-go { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-6); }
.ob-heard summary { cursor: pointer; font-size: var(--step--1); font-weight: 600; color: var(--text-muted); min-height: var(--tap-min); display: inline-flex; align-items: center; gap: var(--space-2); }
.ob-heard summary:hover { color: var(--text); }
.ob-optional { padding: 0 var(--space-2); border: 1px solid var(--line); border-radius: var(--radius-pill); font-size: var(--step--2); font-weight: 600; }
.ob-heard[open] { flex-basis: 100%; }
.ob-heard .field { margin: var(--space-2) 0 0; max-width: calc(420 * var(--unit)); }
/* App home, before the first job: the picker is one calm card above the codes. */
.home-start { padding: var(--space-6); margin-bottom: var(--space-7); border: 1px solid var(--line); border-radius: var(--radius-l); background: var(--surface); box-shadow: var(--shadow-1); }
.home-start h2 { margin: 0 0 var(--space-1); }
.home-start > .muted { margin: 0 0 var(--space-5); }
@media (width < 600px) { .home-start { padding: var(--space-5); } }
/* While the picker shows, its button is the one primary step: the empty library's action steps back. */
.home-start ~ .home-grid [data-empty-action] { background: var(--surface); color: var(--text); border-color: var(--line-strong); box-shadow: none; }
.home-start ~ .home-grid [data-empty-action]:hover { background: var(--brand-tint); color: var(--brand-tint-text); border-color: var(--brand); }
.ob-welcome [hidden] { display: none !important; }
.ob-welcome { max-width: calc(1080 * var(--unit)); }
.ob-head { margin-bottom: var(--space-7); max-width: 40rem; }
.ob-head h1 { font-family: var(--font-display); font-size: var(--step-5); font-variation-settings: "opsz" 96; line-height: var(--leading-tight); letter-spacing: -0.02em; margin: 0 0 var(--space-3); }
.ob-status { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin: 0; }
.ob-trial { color: var(--text-muted); font-size: var(--step--1); }
.ob-intro { margin: 0; color: var(--text-muted); max-width: var(--measure); }
.ob-pending { max-width: 40rem; }
.ob-stage { display: grid; gap: var(--space-8); align-items: start; }
@media (width >= 900px) { .ob-stage { grid-template-columns: minmax(calc(260 * var(--unit)), calc(360 * var(--unit))) minmax(0, 1fr); gap: var(--space-10); } }

/* The proof: white paper in both themes, crop marks outside its corners, one slow ring while it waits. */
.ob-proof { position: relative; margin: 0; padding: calc(26 * var(--unit)); max-width: calc(360 * var(--unit)); }
.ob-sheet { position: relative; background: var(--fixed-white); box-shadow: var(--shadow-2); padding: var(--space-5); aspect-ratio: 1; }
.ob-code svg { display: block; width: 100%; height: auto; }
.ob-crop { position: absolute; inset: calc(-20 * var(--unit)); pointer-events: none; background-repeat: no-repeat;
  background-image: linear-gradient(var(--proof-mark), var(--proof-mark)), linear-gradient(var(--proof-mark), var(--proof-mark)), linear-gradient(var(--proof-mark), var(--proof-mark)), linear-gradient(var(--proof-mark), var(--proof-mark)),
    linear-gradient(var(--proof-mark), var(--proof-mark)), linear-gradient(var(--proof-mark), var(--proof-mark)), linear-gradient(var(--proof-mark), var(--proof-mark)), linear-gradient(var(--proof-mark), var(--proof-mark));
  background-size: calc(12 * var(--unit)) 1px, calc(12 * var(--unit)) 1px, calc(12 * var(--unit)) 1px, calc(12 * var(--unit)) 1px, 1px calc(12 * var(--unit)), 1px calc(12 * var(--unit)), 1px calc(12 * var(--unit)), 1px calc(12 * var(--unit));
  background-position: left 0 top calc(20 * var(--unit)), right 0 top calc(20 * var(--unit)), left 0 bottom calc(20 * var(--unit)), right 0 bottom calc(20 * var(--unit)), left calc(20 * var(--unit)) top 0, right calc(20 * var(--unit)) top 0, left calc(20 * var(--unit)) bottom 0, right calc(20 * var(--unit)) bottom 0; }
.ob-sheet::after { content: ""; position: absolute; inset: calc(-8 * var(--unit)); border: 2px solid var(--brand); opacity: 0; pointer-events: none; }
.ob-proof[data-waiting] .ob-sheet::after { animation: ob-pulse 2.4s var(--ease-out) 3; }
@keyframes ob-pulse { 0% { opacity: 0.55; transform: scale(1); } 100% { opacity: 0; transform: scale(1.1); } }
@media (prefers-reduced-motion: reduce) { .ob-proof[data-waiting] .ob-sheet::after { opacity: 0.45; } }
.ob-caption { margin-top: var(--space-5); color: var(--text-muted); font-size: var(--step--1); overflow-wrap: anywhere; }

.ob-side { display: grid; gap: var(--space-7); min-width: 0; }
.ob-side section { padding-top: var(--space-4); border-top: 2px solid var(--text); }
.ob-side h2 { font-family: var(--font-text); font-size: var(--step-1); font-weight: 700; letter-spacing: 0; margin: 0 0 var(--space-2); }
.ob-link-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin: 0; }
.ob-url { font-family: var(--font-mono); font-size: var(--step-1); background: none; padding: 0; overflow-wrap: anywhere; }
.ob-scan-text { margin: 0 0 var(--space-2); max-width: var(--measure); }
.ob-scan-test { margin: 0 0 var(--space-4); color: var(--text-muted); }
.ob-wait { display: flex; align-items: center; gap: var(--space-3); margin: 0; color: var(--text-muted); }
.ob-wait-dot { width: calc(10 * var(--unit)); height: calc(10 * var(--unit)); border: 2px solid var(--brand); border-radius: 50%; }
.ob-timeout { margin: 0; }
.ob-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.ob-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); padding: var(--space-3) var(--space-4); background: var(--brand-tint); color: var(--brand-tint-text); border-radius: var(--radius-s); font-weight: 650; }
.ob-row-time { font-weight: 400; font-size: var(--step--1); }
.ob-tick { position: relative; flex: none; width: calc(20 * var(--unit)); height: calc(20 * var(--unit)); border-radius: var(--radius-xs); background: var(--brand-fill); }
.ob-tick::after { content: ""; position: absolute; left: calc(5 * var(--unit)); top: calc(5 * var(--unit)); width: calc(9 * var(--unit)); height: calc(5 * var(--unit)); border-left: 2px solid var(--on-brand); border-bottom: 2px solid var(--on-brand); transform: rotate(-45deg); }
.ob-row.is-new { animation: ob-row-in 240ms var(--ease-out); }
.ob-row.is-new .ob-tick::after { animation: ob-tick-draw 200ms var(--ease-out) 120ms both; }
@keyframes ob-row-in { from { opacity: 0; transform: translateY(calc(8 * var(--unit))); } }
@keyframes ob-tick-draw { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
.ob-arrived { margin-top: var(--space-4); }
.ob-arrived p { margin: 0; }
.ob-arrived-title { font-family: var(--font-display); font-size: var(--step-3); line-height: var(--leading-tight); }
.ob-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); }
.ob-home { margin-left: var(--space-2); }
.ob-compose { max-width: 36rem; display: grid; gap: var(--space-4); }
.ob-compose label { display: block; font-weight: 700; margin-bottom: var(--space-2); }
.ob-compose input[type="url"] { width: 100%; min-height: var(--tap-large); padding: var(--space-2) var(--space-4); border: 1px solid var(--line-input); border-radius: var(--radius-s); background: var(--surface); color: var(--text); font-family: var(--font-mono); font-size: var(--step-0); }
.ob-compose .hint { margin: var(--space-2) 0 0; }
.ob-compose-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-5); margin: 0; }

/* The walkthrough: a veil with a hole (clip-path), white crop marks at the hole's corners, and the step card. */
.ob-tour { position: fixed; inset: 0; z-index: 90; }
.ob-tour-veil { position: absolute; inset: 0; background: var(--overlay); transition: clip-path 320ms var(--ease-out); }
.ob-tour-mark { position: absolute; top: 0; left: 0; width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); border: 0 solid var(--fixed-white); transition: transform 320ms var(--ease-out); pointer-events: none; }
.ob-tour-mark.is-tl { border-top-width: 3px; border-left-width: 3px; }
.ob-tour-mark.is-tr { border-top-width: 3px; border-right-width: 3px; margin-left: calc(-18 * var(--unit)); }
.ob-tour-mark.is-bl { border-bottom-width: 3px; border-left-width: 3px; margin-top: calc(-18 * var(--unit)); }
.ob-tour-mark.is-br { border-bottom-width: 3px; border-right-width: 3px; margin: calc(-18 * var(--unit)) 0 0 calc(-18 * var(--unit)); }
.ob-tour-card { position: absolute; top: 0; left: 0; width: min(calc(360 * var(--unit)), calc(100vw - calc(24 * var(--unit)))); transition: transform 320ms var(--ease-out); }
.ob-tour-card[data-mode="dock"] { top: auto; right: calc(12 * var(--unit)); bottom: calc(12 * var(--unit)); left: calc(12 * var(--unit)); width: auto; max-width: calc(520 * var(--unit)); margin-inline: auto; transform: none; }
.ob-tour-step { background: var(--surface-raised); color: var(--text); border: 1px solid var(--line-strong); border-top: calc(4 * var(--unit)) solid var(--brand); border-radius: var(--radius-s); padding: var(--space-4) var(--space-5) var(--space-5); box-shadow: var(--shadow-3); animation: ob-step-in 240ms var(--ease-out); }
/* The step container takes focus so screen readers read it; its buttons carry the visible focus. */
.ob-tour-step:focus { outline: none; }
@keyframes ob-step-in { from { opacity: 0; transform: translateY(calc(8 * var(--unit))); } }
.ob-tour-count { display: flex; align-items: center; gap: var(--space-3); margin: 0 0 var(--space-2); color: var(--text-muted); font-size: var(--step--1); }
.ob-tour-ticks { display: inline-flex; gap: 3px; }
.ob-tour-ticks span { width: calc(14 * var(--unit)); height: 3px; background: var(--line-strong); }
.ob-tour-ticks span.is-on { background: var(--brand-fill); }
.ob-tour-title { font-family: var(--font-display); font-size: var(--step-2); line-height: var(--leading-snug); margin: 0 0 var(--space-2); }
.ob-tour-text { margin: 0 0 var(--space-4); }
.ob-tour-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.ob-tour-skip { margin-right: auto; min-height: calc(32 * var(--unit)); padding: 0 var(--space-1); background: none; border: 0; color: var(--link); font: inherit; font-size: var(--step--1); text-decoration: underline; cursor: pointer; }
/* ==================== onboarding:end ==================== */
/* ==================== rules:start ====================
   The Rules tab (views/app/editor/rules.ejs, client/app/rules.ts): saved rules read as sentences with
   their conditions as marked clauses; the add form picks conditions from chips and writes the rule as
   a sentence; the simulator is a scan ticket whose answer marks the rule that matched. Without JS the
   selects and fields show instead of the chips (.rb-native), and the form posts the same fields. */
.js .rb-native { display: none; }
:root:not(.js) .rb-chips, :root:not(.js) .rb-pick:not([data-pick="time"]), :root:not(.js) .rb-say-box { display: none; }
.rb-form [hidden], .rb-rules [hidden], .rb-sim [hidden] { display: none !important; }

.rb-rules { list-style: none; counter-reset: rule; padding-left: 0; gap: var(--space-3); }
.rb-rules .rule-item { counter-increment: rule; position: relative; padding: var(--space-4) var(--space-4) var(--space-4) calc(var(--space-4) + var(--space-8)); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); box-shadow: var(--tile-rest); }
.rb-rules .rule-item::before { content: counter(rule); position: absolute; left: var(--space-4); top: var(--space-4); width: calc(28 * var(--unit)); height: calc(28 * var(--unit)); display: grid; place-items: center; border-radius: var(--radius-pill); background: var(--surface-sunken); font-weight: 700; font-size: var(--step--1); font-variant-numeric: tabular-nums; }
.rb-rules .rule-item .actions { margin-top: var(--space-2); }
.rb-sentence { font-weight: 400; line-height: 1.9; }
.rb-if, .rb-then, .rb-op { color: var(--text-muted); }
.rb-op { font-weight: 650; }
.rb-clause { padding: 2px var(--space-2); border-radius: var(--radius-s); background: var(--brand-tint); color: var(--brand-tint-text); font-weight: 650; box-decoration-break: clone; -webkit-box-decoration-break: clone; }
.rb-rules .rule-url { margin-top: var(--space-1); color: var(--text); font-size: var(--step--1); }
.rb-hit { display: inline-flex; align-items: center; gap: var(--space-1); margin: var(--space-2) 0 0; padding: 2px var(--space-3); border-radius: var(--radius-pill); background: var(--status-active-bg); color: var(--status-active-text); font-weight: 650; }
.rb-hit::before { content: ""; width: calc(8 * var(--unit)); height: calc(8 * var(--unit)); border-radius: 50%; background: var(--status-active-dot); }
[data-rule-id].is-hit, .rb-say-box.is-hit { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand), var(--tile-lift); }
.rule-default { border-radius: 0 var(--radius-s) var(--radius-s) 0; }
.rule-default.is-hit { border-left-color: var(--brand); }

/* The add form: one card per condition, chips for what it checks and which values. */
.rb-form { display: grid; gap: var(--space-4); }
.rb-form > h3 { margin: 0; }
.rb-cond { margin: 0; padding: var(--space-4); display: grid; gap: var(--space-3); min-width: 0; border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); }
.rb-cond > legend { padding: 0 var(--space-2); font-weight: 650; }
.rb-cond .rule-time { margin: 0; }
.rb-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.rb-chip { position: relative; display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--tap-min); padding: 0 var(--space-4); border: 1px solid var(--line-input); border-radius: var(--radius-pill); background: var(--surface); font-size: var(--step--1); font-weight: 600; color: var(--text); cursor: pointer; }
.rb-chip input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.rb-chip svg { width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); flex: none; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.rb-chip:hover { border-color: var(--brand); }
.rb-chip:has(input:checked) { background: var(--brand-fill); border-color: var(--brand-fill); color: var(--on-brand); }
.rb-chip:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus); outline-offset: var(--focus-offset); }
.rb-pick { display: grid; gap: var(--space-2); }
.rb-pick > .field-hint { margin: 0; }
.rb-sublabel { margin: 0; font-size: var(--step--1); font-weight: 650; color: var(--text-muted); }
.rb-pick .rb-chip { border-radius: var(--radius-s); min-height: var(--tap-min); padding: 0 var(--space-3); }
.rb-not { justify-self: start; }
.rb-remove { justify-self: start; }
.rb-add-slot { margin: 0; }
.rb-add-slot svg, .rb-form .button svg { width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; vertical-align: -3px; }
.rb-label { margin: 0 0 var(--space-2); font-weight: 650; }
.rb-match { display: grid; }

/* The rule as you build it: a proof strip under the conditions. */
.rb-say-box { padding: var(--space-4); border: 1px solid var(--line); border-left: calc(4 * var(--unit)) solid var(--brand); border-radius: var(--radius-s); background: var(--surface-sunken); }
.rb-say { margin: 0; font-size: var(--step-1); line-height: var(--leading-snug); overflow-wrap: anywhere; }

/* The scan ticket: the simulator inputs and its answer on one card with a perforated top. */
.rb-sim { margin: 0; padding: var(--space-5) var(--space-4) var(--space-4); display: grid; gap: var(--space-3); min-width: 0; border: 1px solid var(--line-strong); border-top: 2px dashed var(--line-strong); border-radius: 0 0 var(--radius-l) var(--radius-l); background: var(--surface); }
.rb-sim > legend { padding: 0 var(--space-2); font-family: var(--font-display); font-size: var(--step-1); font-weight: 650; }
.rb-sim > .field-hint { margin: 0; }
.rb-sim .sim-result { margin: 0; padding: var(--space-4); border-radius: var(--radius-m); background: var(--brand-tint); color: var(--brand-tint-text); font-size: var(--step-0); font-weight: 600; overflow-wrap: anywhere; transition: opacity var(--dur-swap) var(--ease-out); }
.rb-sim .sim-result .label-line { display: block; margin: 0 0 var(--space-1); font-size: var(--step--1); }
.rb-sim .sim-result.is-checking { opacity: 0.7; }
.rb-sim .sim-result.is-refused { background: var(--status-danger-bg); color: var(--status-danger-text); }
@media (hover: hover) and (pointer: fine) {
  .rb-chip { transition: border-color var(--dur-hover) var(--ease-out), background-color var(--dur-hover) var(--ease-out); }
  [data-rule-id], .rb-say-box { transition: box-shadow var(--dur-stamp) var(--ease-out), border-color var(--dur-stamp) var(--ease-out); }
}
/* ==================== rules:end ==================== */

/* DES-092: the sandbox test scan panel (views/studio/test-scan.ejs), and DES-090 check 7's one-time tip. */
.test-scan { margin-top: var(--space-3); }
.test-scan summary { cursor: pointer; font-weight: 700; min-height: var(--tap-min); display: flex; align-items: center; }
.test-scan > * + * { margin-top: var(--space-2); }
.test-scan-qr { inline-size: 9rem; max-inline-size: 100%; background: var(--surface); padding: var(--space-2); border-radius: var(--radius-s); }
.test-scan-qr svg { display: block; inline-size: 100%; block-size: auto; }
.test-scan[data-scanned] [data-test-status] { font-weight: 700; }
.test-scan-page { max-inline-size: 36rem; padding-block: var(--space-6); }
.large-run-tip { margin-top: var(--space-3); }
/* Trial download dialog (PLN-032): server-rendered open dialog over the editor ------------------- */
.trial-dialog { position: fixed; inset: 50% auto auto 50%; transform: translate(-50%, -50%); z-index: 40; margin: 0; width: min(calc(560 * var(--unit)), calc(100vw - calc(32 * var(--unit)))); max-height: calc(100vh - calc(32 * var(--unit))); overflow: auto; border: 1px solid var(--line); border-radius: var(--radius-m); padding: var(--space-5); background: var(--surface-raised); color: var(--text); box-shadow: var(--shadow-3); }
.trial-dialog h2 { margin-top: 0; }
.trial-dialog-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: var(--space-4) 0 var(--space-2); }
.trial-dialog-actions form { margin: 0; }
/* Limit moment (LCY-011, PLN-072): one gentle open dialog per session, then the same words inline -------- */
.limit-modal { position: fixed; inset: 50% auto auto 50%; transform: translate(-50%, -50%); z-index: 40; margin: 0; width: min(calc(480 * var(--unit)), calc(100vw - calc(32 * var(--unit)))); max-height: calc(100vh - calc(32 * var(--unit))); overflow: auto; border: 1px solid var(--line); border-radius: var(--radius-m); padding: var(--space-5); background: var(--surface-raised); color: var(--text); box-shadow: var(--shadow-3); }
.limit-modal h2 { margin-top: 0; }
.limit-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: var(--space-3) 0 var(--space-2); }
.limit-close { margin: 0; text-align: end; }
.limit-close button { background: none; border: 0; padding: var(--space-1) var(--space-2); color: var(--text-muted); cursor: pointer; text-decoration: underline; font: inherit; }
.limit-inline { border: 1px solid var(--line); border-radius: var(--radius-m); padding: var(--space-3) var(--space-4); background: var(--surface-raised); margin-block: var(--space-3); }
.limit-inline p { margin: 0; }
/* Starter review before paying (PLN-036): what changes as tiles, then the pick list ---------------------- */
.review-tiles { list-style: none; padding: 0; margin: var(--space-3) 0; display: grid; gap: var(--space-3); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(260 * var(--unit))), 1fr)); }
.review-tile { border: 1px solid var(--line); border-radius: var(--radius-m); padding: var(--space-4); background: var(--surface-raised); }
.review-tile strong { display: block; margin-bottom: var(--space-1); }
.review-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
/* ---------- 18 UX-027: empty, error and loading states (views/partials/empty, error-state, skeleton) ---------- */
.state-icon { width: calc(48 * var(--unit)); height: calc(48 * var(--unit)); color: var(--brand); flex: none; }
.empty .state-icon { padding: var(--space-2); box-sizing: content-box; border-radius: 50%; background: var(--brand-tint); }
.empty [data-empty-action] { margin-top: var(--space-1); }
.state-error { display: grid; justify-items: start; gap: var(--space-3); padding: var(--space-7) var(--space-6); border-radius: var(--radius-m); border: 1px solid var(--line); border-left: calc(4 * var(--unit)) solid var(--status-danger-dot); background: var(--surface); margin: 0 0 var(--space-5); }
.state-error .state-icon { color: var(--status-danger-dot); }
.state-error h1, .state-error h2, .state-error h3 { margin: 0; }
.state-error p { margin: 0; max-width: 56ch; }
.skeleton { display: grid; gap: var(--space-3); padding: var(--space-4) 0; }
.skeleton-row { display: flex; align-items: center; gap: var(--space-3); }
.skeleton-dot, .skeleton-line, .skeleton-block { display: block; border-radius: var(--radius-s); background: var(--surface-sunken); }
.skeleton-dot { width: calc(32 * var(--unit)); height: calc(32 * var(--unit)); flex: none; }
.skeleton-line { height: calc(14 * var(--unit)); width: 70%; }
.skeleton-row:nth-child(3n) .skeleton-line { width: 54%; }
.skeleton-row:nth-child(3n+1) .skeleton-line { width: 78%; }
.skeleton-block { height: calc(180 * var(--unit)); width: 100%; }
/* The page-change bar: shown by public/js/ui.js when a link or form takes longer than 400 ms. */
.nav-progress { position: fixed; z-index: 60; inset: 0 0 auto 0; height: 3px; background: var(--brand-fill); transform-origin: left; transform: scaleX(0.25); }
.nav-progress[hidden] { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .empty[data-state="empty"], .state-error { animation: state-in 320ms var(--ease-out) both; }
  .empty .state-icon { animation: state-pop 420ms var(--ease-out) both; }
  .skeleton-dot, .skeleton-line, .skeleton-block { background: linear-gradient(90deg, var(--surface-sunken) 0%, var(--line) 50%, var(--surface-sunken) 100%); background-size: 200% 100%; animation: skeleton-shimmer 1.4s linear infinite; }
  .nav-progress { animation: nav-progress 8s cubic-bezier(0.1, 0.6, 0.2, 1) forwards; }
  @keyframes state-in { from { opacity: 0; transform: translateY(calc(6 * var(--unit))); } to { opacity: 1; transform: none; } }
  @keyframes state-pop { from { opacity: 0; transform: scale(0.8); } to { opacity: 1; transform: none; } }
  @keyframes skeleton-shimmer { from { background-position: 100% 0; } to { background-position: -100% 0; } }
  @keyframes nav-progress { from { transform: scaleX(0.05); } to { transform: scaleX(0.9); } }
}

/* Logo icon library (DES-004, views/partials/icon-library.ejs): search, category chips, icon tiles. */
.icon-lib { display: grid; gap: var(--space-2); margin-block: var(--space-2); }
.icon-lib-open { justify-self: start; }
.icon-lib-panel { display: grid; gap: var(--space-2); padding: calc(12 * var(--unit)); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface-sunken); }
.icon-lib-find input { width: 100%; }
.icon-lib-cats { display: flex; flex-wrap: wrap; gap: calc(6 * var(--unit)); }
.icon-lib-cat { cursor: pointer; }
.icon-lib-cat[aria-pressed="true"] { background: var(--brand-fill); border-color: var(--brand-fill); color: var(--on-brand); }
.icon-lib-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(calc(52 * var(--unit)), 1fr)); gap: calc(6 * var(--unit)); max-height: calc(320 * var(--unit)); overflow-y: auto; padding: 2px; }
.icon-lib-tile { display: grid; place-items: center; aspect-ratio: 1; padding: calc(4 * var(--unit)); border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--surface); cursor: pointer; }
.icon-lib-tile:hover { border-color: var(--line-strong); }
.icon-lib-tile[aria-pressed="true"] { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); background: var(--brand-tint); }
.icon-lib-tile img { width: calc(40 * var(--unit)); height: calc(40 * var(--unit)); }
.gen-logo-lib { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.gen-logo-lib[hidden] { display: none; }
.gen-logo-lib-pick { display: inline-flex; align-items: center; gap: var(--space-2); padding: calc(6 * var(--unit)) calc(12 * var(--unit)); border: 1px solid var(--brand); border-radius: var(--radius-m); background: var(--surface); cursor: pointer; }
.gen-logo-lib-pick img { width: calc(40 * var(--unit)); height: calc(40 * var(--unit)); border-radius: var(--radius-s); }
.gen-logo-lib-pick input { accent-color: var(--brand); }

/* The frame library picker (DES-020, client/frames/picker.ts): family chips, search, lazily painted tiles. */
.gen-frame-lib, .studio-frame-lib { display: grid; gap: var(--space-2); justify-items: start; }
.frame-lib-panel { display: grid; gap: var(--space-2); width: 100%; padding: calc(12 * var(--unit)); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface-sunken); }
.frame-lib-search input { width: 100%; }
.frame-lib-chips { display: flex; flex-wrap: wrap; gap: calc(6 * var(--unit)); max-height: calc(120 * var(--unit)); overflow-y: auto; }
.frame-lib-chips [aria-pressed="true"] { background: var(--brand-fill); border-color: var(--brand-fill); color: var(--on-brand); }
.frame-lib-grid { list-style: none; margin: 0; padding: 2px; display: grid; grid-template-columns: repeat(auto-fill, minmax(calc(96 * var(--unit)), 1fr)); gap: var(--space-2); max-height: calc(520 * var(--unit)); overflow-y: auto; }
.frame-lib-tile .studio-thumb { min-height: calc(96 * var(--unit)); }
.frame-lib-tile .studio-thumb svg { width: 100%; height: auto; max-height: calc(120 * var(--unit)); }
.frame-lib-tile[aria-pressed="true"] { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); background: var(--brand-tint); }
/* ---------- signature moments (UX-045): one per key page, each shows a concept ----------
   The scan sweep (sign-up sample, the library's first code, the editor's preview) passes a scan line
   over a printed code twice; the plan fit (pricing) draws the ring onto the card that fits. With reduced
   motion nothing moves: the code and the ring are simply there. */
.sig-sweep { position: relative; overflow: hidden; }
.sig-sweep::after { content: ""; position: absolute; inset-inline: 0; top: 0; block-size: 22%; background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--brand) 40%, transparent), transparent); opacity: 0; pointer-events: none; }
@media (prefers-reduced-motion: no-preference) {
  .sig-sweep::after { animation: sig-sweep 1.8s var(--ease-in-out) 0.4s 2 both; }
  .price-card.is-fit { animation: fit-ring 0.6s var(--ease-out) both; }
}
@keyframes sig-sweep { 0% { opacity: 0; transform: translateY(-100%); } 15%, 85% { opacity: 1; } 100% { opacity: 0; transform: translateY(460%); } }
@keyframes fit-ring { from { outline-color: transparent; outline-offset: calc(14 * var(--unit)); } }

/* The thank-you page after payment (views/billing/summary.ejs): a warm line, one button into the codes. */
.thanks { display: grid; justify-items: center; gap: var(--space-3); text-align: center; padding: var(--space-8) 0 var(--space-6); }
.thanks h1 { margin: 0; font-size: var(--step-3); letter-spacing: -0.02em; }
.thanks-lead { margin: 0; max-width: 40ch; color: var(--text-muted); font-size: var(--step-1); }
.thanks-go { margin: var(--space-3) 0 0; }
.thanks-mark { width: calc(64 * var(--unit)); height: calc(64 * var(--unit)); fill: none; stroke-linecap: round; stroke-linejoin: round; }
.thanks-mark circle { transform-box: fill-box; transform-origin: center; stroke: var(--brand); stroke-width: 2; fill: color-mix(in srgb, var(--brand) 14%, transparent); }
.thanks-mark path { stroke: var(--text); stroke-width: 3; }
@media (prefers-reduced-motion: no-preference) {
  .thanks-mark path { stroke-dasharray: 40; stroke-dashoffset: 40; animation: thanks-tick 520ms 160ms var(--ease-out) forwards; }
  .thanks-mark circle { animation: thanks-pop 420ms var(--ease-out) both; }
}
@keyframes thanks-tick { to { stroke-dashoffset: 0; } }
@keyframes thanks-pop { from { transform: scale(0.8); opacity: 0; } }
/* The "two clicks" demo near the top of home (views/home.ejs): type, press Download, the code appears.
   One 7 s loop; with reduced motion the finished still (typed link, the code shown, no cursor). */
.two-clicks { display: none; margin: 0; gap: var(--space-2); justify-items: end; }
@media (width >= 1100px) {
  .home-intro { position: relative; }
  .two-clicks { display: grid; position: absolute; top: var(--space-6); right: 0; }
}
/* The field and one output cell are the only columns; the Download button and the finished code share that
   cell and cross-fade (button out, code in), so the code never covers the button text and the pill keeps its
   size whether the code is shown or hidden (no reserved empty column, CLS 0). */
.tc-stage { position: relative; display: grid; grid-template-columns: auto auto; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-pill); background: var(--surface-raised); box-shadow: var(--sheet-shadow); }
/* A fixed width (not content-based, so the mono web font loading never reflows it: CLS 0) wide enough for the
   whole sample link at every width the figure shows, including the longest localised sample (the French
   votremarque.com/menu, about 171px of text at the capped font size). */
.tc-field { display: inline-flex; align-items: center; width: calc(250 * var(--unit)); overflow: hidden; padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill); background: var(--surface); border: 1px solid var(--line); font-family: var(--font-mono); font-size: var(--step--1); color: var(--text); }
/* A fixed slot (not content width) that holds the longest sample, so the caret after it keeps one position
   while the mono web font loads instead of shifting with the text metrics (CLS 0). The typing reveal is the
   clip-path on this element; overflow keeps a slightly wider fallback render from spilling past the caret. */
.tc-type { display: inline-block; white-space: nowrap; width: calc(218 * var(--unit)); overflow: hidden; }
.tc-caret { display: inline-block; width: 2px; height: 1.1em; margin-left: 1px; background: var(--brand); }
/* Both children sit in the one grid area, so the cell is as wide and tall as the larger of the two and
   neither reserves extra space. The finished still (reduced motion, no animation) shows the code; the button
   is hidden by default, and the loop fades it in only while the code is hidden. */
.tc-out { position: relative; display: grid; place-items: center; }
.tc-button { grid-area: 1 / 1; opacity: 0; padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill); background: var(--brand-fill); color: var(--on-brand); font-size: var(--step--1); font-weight: 650; white-space: nowrap; }
.tc-code { grid-area: 1 / 1; opacity: 1; width: calc(52 * var(--unit)); height: calc(52 * var(--unit)); display: grid; place-items: center; transform-origin: center; }
.tc-code .print-svg { width: 100%; height: 100%; }
.tc-cursor { position: absolute; z-index: 2; width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); fill: var(--text); stroke: var(--surface); stroke-width: 1.2; left: 0; top: 0; opacity: 0; pointer-events: none; }
.tc-caption { margin: 0; font-size: var(--step--1); color: var(--text-muted); }
@media (prefers-reduced-motion: no-preference) {
  .tc-type { animation: tc-type 7s steps(18, end) infinite; }
  .tc-caret { animation: tc-caret 7s linear infinite; }
  .tc-cursor { animation: tc-cursor 7s var(--ease-out) infinite; }
  /* The button is visible while the code is hidden, then fades out before the code fades in (no frame has
     both of them readable at once); tc-press gives the click its squeeze. */
  .tc-button { animation: tc-press 7s ease infinite, tc-button-fade 7s var(--ease-out) infinite; }
  .tc-code { animation: tc-code 7s var(--ease-out) infinite; }
}
@keyframes tc-type { 0%, 4% { clip-path: inset(0 100% 0 0); } 34%, 100% { clip-path: inset(0 0 0 0); } }
@keyframes tc-caret { 0%, 36% { opacity: 1; } 37%, 100% { opacity: 0; } }
@keyframes tc-cursor {
  0%, 30% { opacity: 0; transform: translate(calc(60 * var(--unit)), calc(30 * var(--unit))); }
  36% { opacity: 1; transform: translate(calc(60 * var(--unit)), calc(30 * var(--unit))); }
  48% { opacity: 1; transform: translate(calc(276 * var(--unit)), calc(18 * var(--unit))); }
  52% { opacity: 1; transform: translate(calc(276 * var(--unit)), calc(18 * var(--unit))) scale(0.85); }
  56%, 86% { opacity: 1; transform: translate(calc(280 * var(--unit)), calc(22 * var(--unit))); }
  92%, 100% { opacity: 0; transform: translate(calc(280 * var(--unit)), calc(22 * var(--unit))); }
}
@keyframes tc-press { 0%, 50% { transform: none; filter: none; } 53% { transform: scale(0.94); filter: brightness(1.1); } 58%, 100% { transform: none; } }
/* The button shows while the code is hidden and is gone before the code is readable; they never share a frame. */
@keyframes tc-button-fade { 0%, 50% { opacity: 1; } 55%, 95% { opacity: 0; } 100% { opacity: 1; } }
@keyframes tc-code { 0%, 54% { opacity: 0; transform: scale(0.6); } 64% { opacity: 1; transform: scale(1.06); } 70%, 88% { opacity: 1; transform: none; } 94%, 100% { opacity: 0; transform: scale(0.9); } }

/* ---------- the experience template (F-WEB-011a): type, outcome and industry pages ----------
   views/site/xp/: the generator first, the benefit demo (CSS only, still with reduced motion), the
   looks, numbered sections, FAQ, related pages. Transforms and opacity only, fixed ratios: CLS 0. */
.xp-hero .home-answer time { display: inline-block; margin-left: var(--space-2); font-size: var(--step--2); color: var(--text-muted); white-space: nowrap; }
.xp-demo { display: grid; gap: var(--space-6); align-items: center; padding: var(--space-6) var(--space-5); border-radius: var(--radius-l); background: radial-gradient(120% 90% at 85% 10%, color-mix(in srgb, var(--brand) 16%, transparent), transparent 60%), linear-gradient(135deg, var(--brand-tint), var(--surface-sunken)); overflow: hidden; }
.xp-demo-copy h2 { margin-bottom: var(--space-3); max-width: 18ch; }
.xp-demo-copy p { color: var(--text-muted); max-width: 40ch; margin: 0; }
.xp-stage { position: relative; margin: 0; width: 100%; aspect-ratio: 16 / 11; container-type: inline-size; }
.xp-object { position: absolute; left: 7%; top: 8%; display: grid; justify-items: center; align-content: center; gap: 2.4cqw; padding: 4.5cqw; background: var(--fixed-white); color: var(--paper-ink); box-shadow: var(--paper-lift); transform-origin: 50% 80%; }
.xp-code { display: block; width: 100%; height: auto; }
.xp-lines { display: grid; gap: 1.8cqw; width: 100%; }
.xp-bar { display: block; height: 1.7cqw; width: 100%; border-radius: 2px; background: var(--paper-ink); opacity: 0.16; }
.xp-bar.is-strong { width: 72%; height: 2.6cqw; opacity: 0.75; }
.xp-bar.is-short { width: 46%; }
.xp-tent { width: 36%; aspect-ratio: 127 / 178; top: 6%; border-radius: 2px; transform: rotate(-3deg); }
.xp-tent::after { content: ""; position: absolute; left: 6%; right: 6%; bottom: -3.2cqw; height: 3.2cqw; border-radius: 0 0 50% 50%; background: color-mix(in srgb, var(--paper-ink) 22%, transparent); filter: blur(calc(5 * var(--unit))); z-index: -1; }
.xp-card { width: 56%; aspect-ratio: 85 / 55; top: 24%; grid-template-columns: 1fr 42%; align-items: center; gap: 4cqw; padding: 5cqw; border-radius: var(--radius-xs); transform: rotate(-5deg); }
.xp-poster, .xp-invoice { width: 37%; aspect-ratio: 1 / 1.414; top: 2%; align-content: space-between; justify-items: start; transform: rotate(-2deg); }
.xp-poster .xp-code { width: 62%; justify-self: end; }
.xp-invoice .xp-code { width: 42%; }
.xp-sticker { width: 40%; aspect-ratio: 1; top: 14%; padding: 8cqw; border-radius: 50%; border: 1.8cqw solid var(--paper-ink); transform: rotate(8deg); }
.xp-sign { width: 46%; aspect-ratio: 5 / 4; top: 6%; padding: 4cqw 9cqw; border-radius: var(--radius-xs); border: 1.6cqw solid var(--paper-ink); }
.xp-sign .xp-code { width: 78%; }
.xp-posts { position: absolute; left: 14%; right: 14%; top: 100%; height: 14cqw; background: linear-gradient(90deg, var(--paper-ink) 0 2.2cqw, transparent 2.2cqw calc(100% - 2.2cqw), var(--paper-ink) calc(100% - 2.2cqw)); z-index: -1; }
.xp-phone { position: absolute; right: 7%; top: 3%; width: 29%; aspect-ratio: 9 / 18.5; padding: 1.3cqw; border-radius: 5cqw; background: var(--device-bezel); box-shadow: var(--device-shadow); }
.xp-screen { position: relative; display: block; height: 100%; border-radius: 4cqw; background: var(--fixed-white); color: var(--paper-ink); overflow: hidden; }
.xp-camera { position: absolute; inset: 0; background: radial-gradient(circle at 50% 45%, transparent 26%, color-mix(in srgb, var(--paper-ink) 55%, transparent) 27%), linear-gradient(160deg, color-mix(in srgb, var(--device-bezel) 80%, var(--fixed-white)), var(--device-bezel)); opacity: 0; }
.xp-camera::before { content: ""; position: absolute; left: 24%; right: 24%; top: 32%; aspect-ratio: 1; border: 0.6cqw solid var(--island-button-bg); border-radius: 2cqw; }
.xp-scanline { position: absolute; left: 24%; right: 24%; top: 32%; height: 0.6cqw; background: var(--island-button-bg); box-shadow: 0 0 3cqw var(--island-button-bg); opacity: 0; }
.xp-result { position: absolute; inset: 0; display: grid; align-content: center; justify-items: center; gap: 1.8cqw; padding: 3cqw; text-align: center; font-size: 2.4cqw; line-height: 1.25; background: linear-gradient(180deg, var(--brand-tint), var(--fixed-white) 55%); }
.xp-result strong { font-family: var(--font-display); font-size: 3.1cqw; line-height: 1.1; overflow-wrap: anywhere; }
.xp-result > span:not(.xp-icon):not(.xp-action) { color: color-mix(in srgb, var(--paper-ink) 72%, transparent); overflow-wrap: anywhere; }
.xp-icon { display: grid; place-items: center; width: 9cqw; height: 9cqw; border-radius: 50%; background: var(--fixed-white); color: var(--brand-tint-text); box-shadow: 0 0 0 0.6cqw color-mix(in srgb, var(--brand) 30%, transparent); }
.xp-icon .type-glyph { width: 5cqw; height: 5cqw; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.xp-action { margin-top: 1cqw; padding: 1.2cqw 3cqw; border-radius: var(--radius-pill); background: var(--brand-fill); color: var(--on-brand); font-weight: 750; }
@media (width >= 760px) {
  .xp-demo { grid-template-columns: minmax(0, 0.75fr) minmax(0, 1.25fr); padding: var(--space-8); gap: var(--space-8); }
}
@media (prefers-reduced-motion: no-preference) {
  .xp-phone { animation: xp-phone 7.5s var(--ease-in-out) infinite; }
  .xp-camera { animation: xp-camera 7.5s linear infinite; }
  .xp-scanline { animation: xp-scan 7.5s var(--ease-in-out) infinite; }
  .xp-result { animation: xp-result 7.5s var(--ease-out) infinite; }
  .xp-action { animation: xp-tap 7.5s var(--ease-out) infinite; }
  .xp-object { animation: xp-lift 7.5s var(--ease-out) infinite; }
}
@keyframes xp-phone {
  0%, 6% { transform: translate(6%, 8%) rotate(7deg); }
  20%, 40% { transform: translate(-46%, 6%) rotate(-3deg); }
  54%, 100% { transform: none; }
}
@keyframes xp-camera { 0%, 42% { opacity: 1; } 47%, 100% { opacity: 0; } }
@keyframes xp-scan {
  0%, 20% { opacity: 0; transform: translateY(0); }
  22% { opacity: 1; }
  38% { opacity: 1; transform: translateY(14cqw); }
  42%, 100% { opacity: 0; transform: translateY(14cqw); }
}
@keyframes xp-result { 0%, 44% { opacity: 0; transform: scale(0.94); } 52%, 100% { opacity: 1; transform: none; } }
@keyframes xp-tap { 0%, 68% { transform: none; } 72% { transform: scale(0.92); } 78%, 100% { transform: none; } }
@keyframes xp-lift { 0%, 18% { box-shadow: var(--paper-lift); } 30%, 38% { box-shadow: var(--paper-lift), 0 0 0 1cqw color-mix(in srgb, var(--brand) 35%, transparent); } 50%, 100% { box-shadow: var(--paper-lift); } }
.xp-section .section-head { margin-bottom: var(--space-6); }
.xp-num { margin: 0 0 var(--space-2); font-family: var(--font-mono); font-size: var(--step--1); font-weight: 700; letter-spacing: 0.08em; color: var(--brand-tint-text); }
.xp-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-6); }
.xp-steps > li { position: relative; padding-left: calc(56 * var(--unit)); }
.xp-steps > li::before { content: ""; position: absolute; left: calc(19 * var(--unit)); top: calc(44 * var(--unit)); bottom: calc(-1 * var(--space-6)); width: 2px; background: linear-gradient(var(--brand), var(--line)); }
.xp-steps > li:last-child::before { display: none; }
.xp-step-num { position: absolute; left: 0; top: 0; display: grid; place-items: center; width: calc(40 * var(--unit)); height: calc(40 * var(--unit)); border-radius: 50%; background: var(--brand-fill); color: var(--on-brand); font-family: var(--font-display); font-weight: 750; font-size: var(--step-1); box-shadow: 0 0 0 calc(5 * var(--unit)) var(--brand-tint); }
.xp-steps h3 { margin: 0 0 var(--space-2); padding-top: var(--space-2); }
.xp-steps p { margin: 0; color: var(--text-muted); }
@media (width >= 900px) {
  .xp-steps { grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: var(--space-7); }
  .xp-steps > li { padding: calc(60 * var(--unit)) 0 0; }
  .xp-steps > li::before { left: calc(52 * var(--unit)); right: calc(-1 * var(--space-7) + 8 * var(--unit)); top: calc(19 * var(--unit)); bottom: auto; width: auto; height: 2px; background: linear-gradient(90deg, var(--brand), var(--line)); }
}
/* Fixed vs editable as an interactive comparison (UX v4): two equal-height cards with a glyph anchor and
   an "or" chip between them; the recommended side is tinted, and hovering a card lifts it forward. */
.xp-modes { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-5); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(300 * var(--unit))), 1fr)); align-items: stretch; position: relative; }
.xp-mode { position: relative; display: grid; align-content: start; gap: var(--space-3); padding: var(--space-6); padding-top: calc(var(--space-6) + 40 * var(--unit)); border-radius: var(--radius-l); background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow-1); transition: transform 160ms var(--ease-out), box-shadow 160ms var(--ease-out), border-color 160ms var(--ease-out); }
.xp-mode::before { content: ""; position: absolute; left: var(--space-6); top: var(--space-6); width: calc(32 * var(--unit)); height: calc(32 * var(--unit)); border-radius: var(--radius-s); background: var(--brand-tint); box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--brand) 55%, transparent); }
.xp-mode.is-fixed::before { background: linear-gradient(135deg, var(--brand) 0 50%, var(--brand-tint) 50% 100%); box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--brand) 55%, transparent); }
.xp-mode.is-editable::before { background: var(--brand-tint); box-shadow: inset 0 0 0 2px var(--brand), inset 0 0 0 calc(9 * var(--unit)) var(--surface), inset 0 0 0 calc(11 * var(--unit)) var(--brand); }
.xp-mode.is-editable { border-color: color-mix(in srgb, var(--brand) 45%, var(--line)); background: linear-gradient(180deg, var(--brand-tint), var(--surface) 70%); }
.xp-mode h3 { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.xp-mode p { margin: 0; color: var(--text-muted); }
.xp-facts { display: grid; gap: var(--space-4); margin: 0; grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(240 * var(--unit))), 1fr)); align-items: stretch; }
.xp-facts > div { display: grid; align-content: start; gap: var(--space-2); padding: var(--space-5); padding-left: calc(var(--space-5) + 8 * var(--unit)); border-radius: var(--radius-m); background: var(--surface-sunken); border-left: calc(4 * var(--unit)) solid var(--brand); }
.xp-facts dt { font-weight: 700; margin: 0; }
.xp-facts dd { margin: 0; color: var(--text-muted); }
/* Card sections (cards kind): equal-height tiles with a small code-glyph anchor instead of a bare top rule. */
.xp-cards { gap: var(--space-5); align-items: stretch; }
.xp-cards .pillar { position: relative; display: grid; align-content: start; gap: var(--space-2); border-top: 0; padding: var(--space-5); padding-top: calc(var(--space-5) + 40 * var(--unit)); border: 1px solid var(--line); border-radius: var(--radius-l); background: var(--surface); box-shadow: var(--shadow-1); transition: transform 160ms var(--ease-out), box-shadow 160ms var(--ease-out); }
.xp-cards .pillar::before { content: ""; position: absolute; left: var(--space-5); top: var(--space-5); width: calc(30 * var(--unit)); height: calc(30 * var(--unit)); border-radius: var(--radius-s); background: linear-gradient(var(--brand), var(--brand)) center / 42% 42% no-repeat, var(--brand-tint); box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--brand) 55%, transparent); }
.xp-cards .pillar h3 { margin: 0; }
.xp-cards .pillar p { margin: 0; }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .xp-mode:hover, .xp-cards .pillar:hover { transform: translateY(-3px); box-shadow: var(--shadow-2, var(--shadow-1)); }
}
/* The FAQ as a clean two-column accordion on wide screens; each column balances its disclosures. The tool
   pages (scanner, barcode, size...) share the treatment so their Q&A fills the width instead of sitting in
   the left half with the right half empty. One column on phones. */
@media (width >= 900px) {
  .xp-faq .faq, .tool-faq .faq { max-width: none; columns: 2; column-gap: var(--space-7); border-top: 0; }
  .xp-faq .faq details, .tool-faq .faq details { break-inside: avoid; border-top: 1px solid var(--line); border-bottom: 0; }
}
.xp-look-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-5); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(200 * var(--unit))), 1fr)); }
.xp-look { display: grid; gap: var(--space-2); align-content: start; padding: var(--space-5); border-radius: var(--radius-l); background: var(--surface); border: 1px solid var(--line); }
.xp-look img { width: calc(110 * var(--unit)); height: auto; aspect-ratio: 1; padding: var(--space-2); border-radius: var(--radius-m); background: var(--fixed-white); box-shadow: var(--paper-shadow); }
.xp-look h3 { margin: var(--space-2) 0 0; }
.xp-look p { margin: 0; color: var(--text-muted); }
.xp-look form { margin-top: var(--space-2); }
.xp-related-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-4); }
.xp-related-card { flex: 1 1 calc(240 * var(--unit)); padding: var(--space-5); border-radius: var(--radius-m); border: 1px solid var(--line); background: var(--surface); }
.xp-related-card a { font-weight: 700; font-size: var(--step-1); }
.xp-related-card p { margin: var(--space-2) 0 0; color: var(--text-muted); font-size: var(--step--1); }
.xp-related-more { flex: 0 1 auto; }
.xp-related-more a { display: inline-flex; align-items: center; min-height: var(--tap-min); padding: 0 var(--space-4); border-radius: var(--radius-pill); border: 1px solid var(--line-strong); background: var(--surface); font-size: var(--step--1); font-weight: 600; text-decoration: none; }
.xp-related-more a:hover { border-color: var(--brand); }
/* The change-the-link demo in the hero of the dynamic page (views/site/xp/swap.ejs, WEB-013): one printed
   code, three destinations as radio buttons, the phone line follows the checked one. CSS only; every
   screen line takes the same space, so picking one never moves the layout. */
.xp-swap { display: grid; grid-template-columns: calc(108 * var(--unit)) minmax(0, 1fr); gap: var(--space-3) var(--space-4); align-items: start; margin: var(--space-4) 0 0; padding: var(--space-4); border: 1px solid color-mix(in srgb, var(--brand) 40%, var(--line)); border-radius: var(--radius-l); background: linear-gradient(135deg, var(--brand-tint), var(--surface) 70%); }
.xp-swap legend { float: left; width: 100%; grid-column: 1 / -1; margin: 0; padding: 0; font-family: var(--font-display); font-weight: 750; font-size: var(--step-0); }
.xp-swap-code { display: grid; justify-items: center; gap: var(--space-1); min-width: 0; padding: var(--space-2); border-radius: var(--radius-s); background: var(--fixed-white); color: var(--paper-ink); box-shadow: var(--paper-shadow); overflow: hidden; }
.xp-swap-code .xp-code { width: 100%; max-width: 100%; height: auto; aspect-ratio: 1; }
.xp-swap-short { max-width: 100%; font-family: var(--font-mono); font-size: var(--step--2); line-height: 1.2; text-align: center; overflow-wrap: anywhere; }
.xp-swap-pick { display: grid; gap: var(--space-1); }
.xp-swap-legend { margin: 0; font-size: var(--step--1); color: var(--text-muted); }
.xp-swap-option { display: flex; align-items: center; gap: var(--space-2); min-height: var(--tap-min); padding: 0 var(--space-3); border: 1px solid var(--line-strong); border-radius: var(--radius-pill); background: var(--surface); font-size: var(--step--1); font-weight: 600; cursor: pointer; }
.xp-swap-option:has(input:checked) { border-color: var(--brand); background: var(--brand-tint); color: var(--brand-tint-text); }
.xp-swap-option input { accent-color: var(--brand); margin: 0; }
.xp-swap-phone { display: grid; grid-column: 1 / -1; padding: var(--space-3) var(--space-4); border-radius: var(--radius-m); background: var(--island-bg); color: var(--island-text); font-size: var(--step--1); }
.xp-swap-screen { grid-area: 1 / 1; margin: 0; visibility: hidden; }
.xp-swap-screen span { color: var(--island-muted); }
.xp-swap:has(.xp-swap-option:nth-of-type(1) input:checked) .xp-swap-screen:nth-child(1),
.xp-swap:has(.xp-swap-option:nth-of-type(2) input:checked) .xp-swap-screen:nth-child(2),
.xp-swap:has(.xp-swap-option:nth-of-type(3) input:checked) .xp-swap-screen:nth-child(3),
.xp-swap:has(.xp-swap-option:nth-of-type(4) input:checked) .xp-swap-screen:nth-child(4) { visibility: visible; }
/* The plain fact beside the band's decision buttons (views/partials/band.ejs `note`). */
.band-note { margin-top: var(--space-5); padding: var(--space-4) var(--space-5); border: 1px solid var(--island-line); border-radius: var(--radius-m); max-width: 60ch; }
.band-note h3 { margin: 0 0 var(--space-2); color: var(--island-text); font-size: var(--step-0); }
.band-note ul { margin: 0; padding-left: var(--space-5); color: var(--island-muted); font-size: var(--step--1); display: grid; gap: var(--space-1); }
.band-note p { margin-top: var(--space-2); font-size: var(--step--1); }

/* Barcode tool (TYP-100): symbology tiles grouped by use, the live preview and the bulk run. */
.barcode-symbologies { display: grid; gap: var(--space-4); }
.barcode-group-title { margin: 0 0 var(--space-2); font-size: var(--step--1); font-weight: 700; color: var(--text-muted); }
.barcode-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(calc(150 * var(--unit)), 1fr)); gap: var(--space-2); }
.barcode-tile { position: relative; display: grid; gap: 2px; min-height: var(--tap-min); padding: var(--space-2) var(--space-3); border: 1px solid var(--line-input); border-radius: var(--radius-s); background: var(--surface); cursor: pointer; transition: border-color 120ms ease, box-shadow 120ms ease; }
.barcode-tile input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.barcode-tile-name { font-weight: 700; font-size: var(--step--1); }
.barcode-tile-use { font-size: var(--step--2); color: var(--text-muted); }
.barcode-tile:hover { border-color: var(--brand); }
.barcode-tile:has(input:checked) { border-color: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); background: var(--brand-tint); }
.barcode-tile:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 2px; }
.barcode-live { display: grid; justify-items: center; gap: var(--space-2); padding: var(--space-4); border: 1px dashed var(--line-input); border-radius: var(--radius-m); background: var(--surface); }
.barcode-live img { max-width: 100%; height: auto; max-height: calc(220 * var(--unit)); }
.barcode-live-title { margin: 0; font-size: var(--step--2); font-weight: 700; justify-self: start; }
.barcode-downloads { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.barcode-bulk { display: grid; gap: var(--space-3); margin-top: var(--space-6); padding-top: var(--space-5); border-top: 1px solid var(--line-input); }
@media (prefers-reduced-motion: reduce) { .barcode-tile { transition: none; } }

/* DES-040 AI art tab in the studio (views/studio/ai.ejs) */
.studio-ai-credits progress { inline-size: 100%; block-size: calc(10 * var(--unit)); accent-color: var(--brand); }
.studio-ai-tiles { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
.studio-ai-tiles li { display: grid; gap: var(--space-2); justify-items: start; }
.studio-ai-tiles img { inline-size: 100%; block-size: auto; border-radius: var(--radius-s); }
.studio-panel[data-state="loading"] [data-ai-line] { opacity: 0.7; }

/* ---------- bulk step indicator (UX-008): 8 steps in order; done, current, upcoming ---------- */
.bulk-steps ol { list-style: none; margin: 0 0 var(--space-5); padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); }
.bulk-steps li { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--step--1); color: var(--text-muted); }
.bulk-step-n { display: inline-grid; place-items: center; inline-size: calc(24 * var(--unit)); block-size: calc(24 * var(--unit)); border-radius: var(--radius-pill); border: 1px solid var(--line-strong); font-weight: 600; font-variant-numeric: tabular-nums; }
.bulk-steps li[data-state="done"] .bulk-step-n { background: var(--brand-tint); border-color: transparent; color: var(--brand-tint-text); }
.bulk-steps li[data-state="current"] { color: var(--text); font-weight: 600; }
.bulk-steps li[data-state="current"] .bulk-step-n { background: var(--brand-fill); border-color: transparent; color: var(--on-brand); }

/* UX-020 (2.4.11): focus never lands under a sticky bar. The library's sticky bulk bar sits on top; client/app
   sets scroll-padding-top from its measured height (this rule is the fallback) so a focused row scrolls clear of it; the billing links meet the 24 px target (2.5.8). */
html:has(.bulk-bar) { scroll-padding-top: calc(var(--space-6) + 6rem); }
/* Date and time inputs focus a segment inside the field, which Chrome does not count as focus-visible. */
input:is([type="date"], [type="datetime-local"], [type="time"], [type="month"], [type="week"]):focus { outline: var(--focus-width) solid var(--focus); outline-offset: 1px; }
input::-webkit-calendar-picker-indicator:focus-visible { outline: var(--focus-width) solid var(--focus); outline-offset: 1px; }
.billing-links a { display: inline-flex; align-items: center; min-block-size: var(--target-min); }

/* The step sequence (views/site/xp/sequence.ejs, UX v4 owner 2026-10-14): ONE block that replaces the old
   duplicate of the step-path visual and the How-to list. A reactive scene (visual.ejs) beside the numbered
   steps; a stop lights as its step is hovered, focused or scrolled to (ui.js toggles .is-on / .is-done on
   the stop group and its step). The step text lives once, in the list, and is readable without JS. Theme
   colours via fill classes, so light and dark both work. */
.xp-sequence .section-head { margin-bottom: var(--space-5); }
.xp-seq-grid { display: grid; gap: var(--space-6); align-items: start; }
.xp-visual { margin: 0; }
.xp-visual svg { display: block; width: 100%; height: auto; border-radius: var(--radius-l); box-shadow: var(--shadow-1); }
.xp-sequence .xp-steps { margin: 0; }
@media (width >= 900px) {
  .xp-seq-grid { grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr); gap: var(--space-7); align-items: center; }
  .xp-sequence .xp-steps { grid-auto-flow: row; grid-auto-columns: auto; gap: var(--space-5); }
  .xp-sequence .xp-steps > li { padding: 0 0 0 calc(56 * var(--unit)); }
  .xp-sequence .xp-steps > li::before { left: calc(19 * var(--unit)); right: auto; top: calc(44 * var(--unit)); bottom: calc(-1 * var(--space-5)); width: 2px; height: auto; background: linear-gradient(var(--brand), var(--line)); }
  .xp-sequence .xp-steps > li:last-child::before { display: none; }
}
.xv-bg { fill: var(--brand-tint); }
.xv-object { fill: var(--surface); stroke: var(--line-strong); stroke-width: 2; }
.xv-line-fill { fill: var(--line-strong); }
.xv-paper { fill: var(--surface); }
.xv-ink { fill: var(--text); }
.xv-path { fill: none; stroke: var(--brand); stroke-width: 3; stroke-dasharray: 6 8; stroke-linecap: round; }
.xv-stop { fill: var(--brand); }
.xv-num { fill: var(--text-inverse); font: 700 calc(20 * var(--unit)) var(--font-display); }
.xv-label { fill: var(--text); font: 600 calc(19 * var(--unit)) var(--font-text); }

/* ===============================================================   ux-v4 hubs and secondary pages: full-width experience layouts.
   Reusable so the hubs read as galleries and docs, not capped columns.
   Sizes come from tokens or calc(N * var(--unit)); breakpoints reuse
   the 600 / 760 / 900 / 1100 set. See .factory/ux-v4/ux4-hubs-critique.md.
   ====================================================================== */

/* An experience page fills main.wrap (max 1120px) instead of the 66ch
   reading measure, so no column of text sits beside emptiness. */
.exp-page { max-width: none; }
.exp-page > .section:first-child { margin-top: 0; }

/* Two-column hero: copy on the left, a visual anchor on the right. */
.exp-hero { margin-bottom: var(--space-9); }
.exp-hero-grid { display: grid; gap: var(--space-7); align-items: center; }
.exp-eyebrow { font-family: var(--font-display); font-weight: 650; font-size: var(--step-1); color: var(--brand-tint-text); margin: 0 0 var(--space-3); }
.exp-hero-copy h1 { margin-bottom: var(--space-4); }
.exp-hero-copy .lead, .exp-hero-copy .site-page-answer { max-width: 48ch; }
.exp-hero-copy .actions { margin-top: var(--space-6); }
.exp-hero-visual { min-width: 0; }
@media (width >= 900px) {
  .exp-hero-grid { grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr); gap: var(--space-10); }
  .exp-hero-grid.text-lead { grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.7fr); }
}

/* A soft framed panel that holds a mockup, a montage or a code preview. */
.anchor { position: relative; display: flex; flex-direction: column; justify-content: center; gap: var(--space-4); padding: var(--space-8); border: 1px solid var(--line); border-radius: var(--radius-l); background: linear-gradient(160deg, var(--brand-tint), var(--surface)); box-shadow: var(--shadow-2); overflow: hidden; }
.anchor-plain { background: var(--surface); }
.anchor-start { text-align: left; }
.anchor-code { display: block; width: calc(220 * var(--unit)); max-width: 70%; height: auto; margin-inline: auto; border-radius: var(--radius-m); background: var(--fixed-white); box-shadow: var(--shadow-1); }
.anchor-caption { text-align: center; color: var(--text-muted); font-size: var(--step--1); margin: 0; }

/* Bespoke hero visual (views/site/partials/hero-visual.ejs): one on-topic scene per growth/About page,
   in place of the shared QR anchor. The SVG carries the framed panel look; the hv-* classes map to tokens
   so the scene reads in both themes. Decorative. */
.hv { margin: 0; }
.hv svg { display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; border: 1px solid var(--line); border-radius: var(--radius-l); background: linear-gradient(160deg, var(--brand-tint), var(--surface)); box-shadow: var(--shadow-2); }
.hv-panel { fill: var(--surface); stroke: var(--line-strong); stroke-width: 1.5; }
.hv-node { fill: var(--surface); stroke: var(--brand); stroke-width: 2; }
.hv-card { fill: var(--surface); stroke: var(--line-strong); stroke-width: 1.5; }
.hv-frame { fill: var(--surface); stroke: var(--brand); stroke-width: 3; }
.hv-chip { fill: var(--surface-sunken); }
.hv-paper { fill: var(--fixed-white); }
.hv-ink { fill: var(--text); }
.hv-brand { fill: var(--brand); }
.hv-mint { fill: var(--brand-fill); }
.hv-tint { fill: var(--brand-tint); }
.hv-tint-ink2 { fill: var(--brand-tint-text); }
.hv-muted { fill: var(--line-strong); }
.hv-sunken { fill: var(--surface-sunken); stroke: var(--line); stroke-width: 1; }
.hv-hair { fill: var(--line); }
.hv-row { fill: var(--surface-sunken); stroke: var(--line); stroke-width: 1; }
.hv-row-on { fill: var(--brand-tint); stroke: var(--brand); stroke-width: 2; }
.hv-phone { fill: var(--device-bezel); }
.hv-screen { fill: var(--fixed-white); }
.hv-wire { fill: none; stroke: var(--brand); stroke-width: 2.5; stroke-linecap: round; }
.hv-plug { fill: none; stroke: var(--brand-tint-text); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.hv-beam { fill: var(--brand-fill); opacity: 0.22; }

/* Plan fact tiles: the figures that give each audience plan card density beside its sentence. */
.plan-facts { list-style: none; margin: var(--space-2) 0 0; padding: 0; display: grid; gap: var(--space-2); grid-template-columns: repeat(2, 1fr); }
.plan-facts li { display: flex; flex-direction: column; gap: 2px; padding: var(--space-3) var(--space-4); border-radius: var(--radius-s); background: var(--surface-sunken); }
.plan-facts .pf-v { font-family: var(--font-display); font-weight: 650; font-size: var(--step-1); line-height: 1.1; font-variant-numeric: tabular-nums; color: var(--text); }
.plan-facts .pf-k { font-size: var(--step--2); color: var(--text-muted); }
/* In a plan card the sentence sizes to its content so the fact tiles sit right under it; a trailing
   foot or chip row still anchors to the bottom (margin-top: auto), keeping the cards aligned. */
.hub-card[data-plan] > p { flex: 0 0 auto; }
.hub-card[data-plan] .plan-facts { margin-top: var(--space-3); }

/* Client switcher mock (agencies): one login, every client. A static, themed board, not a live control. */
.switch-mock { flex: 1 1 calc(300 * var(--unit)); min-width: 0; display: grid; gap: var(--space-3); padding: var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-l); background: var(--surface); box-shadow: var(--shadow-1); }
.switch-head { display: flex; align-items: center; gap: var(--space-3); font-weight: 650; font-size: var(--step--1); color: var(--text-muted); }
.switch-head .tile-icon { width: calc(32 * var(--unit)); height: calc(32 * var(--unit)); border-radius: var(--radius-s); }
.switch-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-radius: var(--radius-m); background: var(--surface-sunken); }
.switch-row.is-active { background: var(--brand-tint); box-shadow: inset 0 0 0 1.5px var(--brand); }
.switch-row .sw-code { flex: none; width: calc(28 * var(--unit)); height: calc(28 * var(--unit)); border-radius: var(--radius-s); background: var(--fixed-white); box-shadow: var(--shadow-1); display: grid; place-items: center; }
.switch-row .sw-code svg { width: calc(20 * var(--unit)); height: calc(20 * var(--unit)); color: var(--brand); }
.switch-row .sw-name { font-weight: 600; font-size: var(--step--1); color: var(--text); }
.switch-row .sw-dot { margin-left: auto; width: calc(10 * var(--unit)); height: calc(10 * var(--unit)); border-radius: var(--radius-pill); background: var(--line-strong); }
.switch-row.is-active .sw-dot { background: var(--brand); }

/* Gallery card grid with equal-height cards (grid stretches each row). */
.hub-grid { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fill, minmax(calc(270 * var(--unit)), 1fr)); }
.hub-grid.cols-2 { grid-template-columns: 1fr; }
.hub-grid.cols-4 { grid-template-columns: repeat(auto-fill, minmax(calc(230 * var(--unit)), 1fr)); }
@media (width >= 760px) {
  .hub-grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
}

.hub-card { display: flex; flex-direction: column; gap: var(--space-3); min-height: 100%; padding: var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); box-shadow: var(--shadow-1); color: inherit; text-decoration: none; }
.hub-card > p { flex: 1 1 auto; margin: 0; color: var(--text-muted); font-size: var(--step--1); line-height: 1.5; }
.hub-card-title { font-family: var(--font-display); font-weight: 650; font-size: var(--step-1); line-height: 1.2; margin: 0; }
a.hub-card .hub-card-title, .hub-card a { color: var(--text); text-decoration: none; }
.hub-card-foot { margin-top: auto; display: inline-flex; align-items: center; gap: var(--space-2); font-weight: 600; font-size: var(--step--1); color: var(--brand-tint-text); }
.hub-card-foot svg { width: calc(16 * var(--unit)); height: calc(16 * var(--unit)); fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
a.hub-card:hover, .hub-card:focus-within { border-color: var(--brand); box-shadow: var(--shadow-2); }
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .hub-card { transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease; }
  a.hub-card:hover { transform: translateY(-2px); }
}

/* An icon tile: the per-card visual anchor. */
.tile-icon { display: inline-flex; align-items: center; justify-content: center; width: calc(44 * var(--unit)); height: calc(44 * var(--unit)); border-radius: var(--radius-m); background: var(--brand-tint); color: var(--brand-tint-text); flex: none; }
.tile-icon svg { width: calc(24 * var(--unit)); height: calc(24 * var(--unit)); fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* Feature rows: an icon-led list used where three text blocks used to sit. */
.feature-grid { display: grid; gap: var(--space-5); grid-template-columns: 1fr; }
@media (width >= 760px) { .feature-grid { grid-template-columns: repeat(2, 1fr); } }
@media (width >= 1100px) { .feature-grid.cols-3 { grid-template-columns: repeat(3, 1fr); } }
.feature { display: flex; gap: var(--space-4); align-items: flex-start; }
.feature .tile-icon { width: calc(40 * var(--unit)); height: calc(40 * var(--unit)); }
.feature-body h3 { margin: 0 0 var(--space-1); font-size: var(--step-0); }
.feature-body p { margin: 0; color: var(--text-muted); font-size: var(--step--1); line-height: 1.5; }

/* Docs layout: a sticky table of contents beside the content. */
.doc { display: grid; gap: var(--space-7); align-items: start; }
.doc-nav { min-width: 0; }
.doc-nav-inner { border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); padding: var(--space-4); }
.doc-nav h2, .doc-nav .doc-nav-title { font-family: var(--font-display); font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); margin: 0 0 var(--space-3); }
.doc-nav ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-1); }
.doc-nav li { display: flex; align-items: baseline; gap: var(--space-2); }
.doc-nav a { flex: 1 1 auto; display: block; padding: var(--space-2) var(--space-3); border-radius: var(--radius-s); color: var(--text-muted); text-decoration: none; font-size: var(--step--1); line-height: 1.3; }
.doc-nav li .small { flex: none; }
.doc-nav a:hover { background: var(--brand-tint); color: var(--brand-tint-text); }
.doc-body { min-width: 0; }
.doc-body.prose { max-width: none; }
@media (width >= 900px) {
  .doc { grid-template-columns: calc(280 * var(--unit)) minmax(0, 1fr); gap: var(--space-9); }
  /* The nav column stretches to the document's height so its sticky rail stays pinned the whole way down,
     not only for the first screenful (the grid's align-items: start otherwise shrinks the column). */
  .doc-nav { align-self: stretch; }
  .doc-nav-inner { position: sticky; top: var(--space-6); max-height: calc(100vh - var(--space-10)); overflow: auto; }
}

/* Developer docs (unit ux5-docs): the rail highlights the group in view, phones get a compact jump menu,
   and each resource group collapses so the page opens short instead of one endless column. */
.doc-nav [data-toc-link].is-active { background: var(--brand-tint); color: var(--brand-tint-text); font-weight: 650; }

/* Compact phone jump menu; the full sticky rail takes over on wide screens. */
.doc-toc-rail { display: none; }
.doc-jump { position: sticky; top: var(--space-3); z-index: 2; border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); box-shadow: var(--shadow-1); }
.doc-jump > summary { display: flex; align-items: center; gap: var(--space-2); min-height: var(--tap-large); padding: 0 var(--space-4); font-family: var(--font-display); font-weight: 650; cursor: pointer; list-style: none; }
.doc-jump > summary::-webkit-details-marker { display: none; }
.doc-jump > summary::after { content: ""; margin-left: auto; flex: none; width: calc(9 * var(--unit)); height: calc(9 * var(--unit)); border-right: 2px solid var(--brand); border-bottom: 2px solid var(--brand); transform: translateY(-25%) rotate(45deg); transition: transform 160ms var(--ease-out); }
.doc-jump[open] > summary::after { transform: translateY(25%) rotate(-135deg); }
.doc-jump > ul { list-style: none; margin: 0; padding: var(--space-2); display: grid; gap: var(--space-1); max-height: 60vh; overflow: auto; border-top: 1px solid var(--line); }
.doc-jump a { display: flex; justify-content: space-between; gap: var(--space-2); padding: var(--space-2) var(--space-3); border-radius: var(--radius-s); color: var(--text-muted); text-decoration: none; font-size: var(--step--1); line-height: 1.3; }
.doc-jump a:hover { background: var(--brand-tint); color: var(--brand-tint-text); }
@media (width >= 900px) {
  .doc-jump { display: none; }
  .doc-toc-rail { display: block; }
}
@media (prefers-reduced-motion: reduce) { .doc-jump > summary::after { transition: none; } }

/* A resource group: a header row that reads like a section title, a chevron, equal inner spacing. */
.api-group { border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); box-shadow: var(--shadow-1); margin: var(--space-6) 0; }
.api-group > summary { display: flex; align-items: center; gap: var(--space-3); min-height: var(--tap-large); padding: var(--space-4) var(--space-5); cursor: pointer; list-style: none; }
.api-group > summary::-webkit-details-marker { display: none; }
.api-group > summary::after { content: ""; flex: none; width: calc(10 * var(--unit)); height: calc(10 * var(--unit)); border-right: 2px solid var(--brand); border-bottom: 2px solid var(--brand); transform: translateY(-25%) rotate(45deg); transition: transform 160ms var(--ease-out); }
.api-group[open] > summary::after { transform: translateY(25%) rotate(-135deg); }
.api-group > summary:hover .api-group-name { color: var(--brand-tint-text); }
.api-group .api-group-name { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: var(--space-3); margin: 0; font-family: var(--font-display); font-weight: 650; font-size: var(--step-1); line-height: 1.2; text-transform: capitalize; }
.api-group-count { margin-left: auto; font-family: var(--font-text); font-weight: 500; font-size: var(--step--1); color: var(--text-muted); text-transform: none; font-variant-numeric: tabular-nums; }
.api-group-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-5); padding: 0 var(--space-5) var(--space-5); min-width: 0; }
.api-group-body > p { margin: 0; }
.api-group-body > .card { margin: 0; }
@media (prefers-reduced-motion: reduce) { .api-group > summary::after { transition: none; } }

/* The copy button on a code block head stays compact and never crowds the label. */
.code-block-head .button.code-copy { margin-left: auto; min-height: calc(30 * var(--unit)); padding: 0 var(--space-3); font-size: var(--step--1); }

/* Help centre: a section card holds its icon, title, popular articles. */
.help-hero { display: grid; gap: var(--space-6); padding: var(--space-8); border-radius: var(--radius-l); background: linear-gradient(160deg, var(--brand-tint), var(--surface)); border: 1px solid var(--line); margin-bottom: var(--space-9); }
.help-hero h1 { margin: 0; }
.help-hero .lead { margin: 0; max-width: 52ch; }
.help-hero form.filters { margin: 0; }
/* A masonry-style column grid packs section cards of different lengths with no voids. */
.help-grid { column-width: calc(360 * var(--unit)); column-gap: var(--space-4); }
.help-section { break-inside: avoid; display: flex; flex-direction: column; gap: var(--space-3); margin: 0 0 var(--space-4); padding: var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); box-shadow: var(--shadow-1); }
.help-section .tile-icon { width: calc(40 * var(--unit)); height: calc(40 * var(--unit)); }
.help-section-body h3 { margin: 0 0 var(--space-3); font-size: var(--step-0); }
.help-section-body h3 .small { color: var(--text-muted); font-weight: 500; }
.help-section ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.help-section li { margin: 0; }
.help-section a { color: var(--text); text-decoration: none; font-size: var(--step--1); line-height: 1.35; }
.help-section a:hover { color: var(--brand-tint-text); text-decoration: underline; }
@media (width >= 760px) { .help-hero { grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr); align-items: center; } }

/* A band of quick links rendered as chips rather than a bare bullet list. */
.link-chips { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-3); }
.link-chips a { display: inline-flex; align-items: center; min-height: var(--tap-min); gap: var(--space-2); padding: 0 var(--space-5); border: 1px solid var(--line-strong); border-radius: var(--radius-pill); background: var(--surface); font-weight: 600; font-size: var(--step--1); text-decoration: none; color: var(--text); }
.link-chips a:hover { border-color: var(--brand); color: var(--brand-tint-text); }

/* About: the story panel fills the width so no text sits beside emptiness. */
.story-panel { display: flex; flex-wrap: wrap; gap: var(--space-6) var(--space-8); align-items: center; justify-content: space-between; padding: var(--space-7) var(--space-8); border: 1px solid var(--line); border-radius: var(--radius-l); background: var(--surface); box-shadow: var(--shadow-1); }
.story-panel-text { flex: 1 1 calc(380 * var(--unit)); min-width: 0; }
.story-panel-text h2 { margin: 0 0 var(--space-3); }
.story-panel-text p { margin: 0; color: var(--text-muted); max-width: 60ch; }
.story-panel .link-chips { flex: 0 1 auto; }
.card-push { margin-top: auto; }

/* A legal document inside the doc grid fills its column (the TOC takes the first). */
.doc > .prose.legal-page { max-width: none; min-width: 0; }
/* ================= UX v4 app polish (unit/ux4-app) ================= */
/* One primary per screen: a save/submit button inside a stacked form sits at its natural width and
   left-aligns, instead of stretching the full grid column into a heavy full-width bar. */
form.stack > .button:not(.block),
form.stack > button[type="submit"]:not(.block),
form.panel-block > .button:not(.block),
form.panel-block > button[type="submit"]:not(.block) { justify-self: start; }

/* Home side rail reads as a set of cards, not a flat ruled stack. */
.home-side section { padding: var(--app-panel-pad, var(--space-5)); border: 1px solid var(--line); border-top: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); }
.home-side section > :first-child { margin-top: 0; }
.home-side h2 { font-size: var(--step-0); }

/* Home recent codes: calm equal cards instead of one sunken sheet that reads like a table. */
.contact-sheet { padding: 0; background: none; gap: var(--space-4); }
.contact { padding: var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); gap: var(--space-3); transition: border-color var(--dur-hover) var(--ease-out), box-shadow var(--dur-hover) var(--ease-out); }
@media (hover: hover) { .contact:hover { border-color: var(--brand); box-shadow: var(--shadow-1); } }
.contact-meta { gap: var(--space-2); font-size: var(--step--1); }
@media (prefers-reduced-motion: reduce) { .contact { transition: none; } }

/* Bulk bar: the destructive action stays quiet until hover (brief principle 7). */
.bulk-buttons .button.danger { background: var(--surface); color: var(--danger-solid); border-color: var(--line-strong); box-shadow: none; }
.bulk-buttons .button.danger:hover { background: var(--danger-solid); color: var(--on-danger); border-color: var(--danger-solid); }

/* Billing: a full-width status card, plan cards and a tidy action card (no raw bullets). */
.billing-card { margin-bottom: var(--space-6); padding: var(--space-5) var(--space-6); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); }
.billing-card .stat-row { margin: 0; gap: var(--space-9); }
.billing-card h2 { margin-top: 0; }
.billing-manage { padding: var(--space-5) var(--space-6); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); margin-bottom: var(--space-7); max-width: calc(620 * var(--unit)); }
.billing-manage h2 { margin-top: 0; }
.billing-manage .billing-action-row { margin-bottom: var(--space-4); }
.billing-links { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; border: 1px solid var(--line); border-radius: var(--radius-m); overflow: hidden; }
.billing-links li { border-top: 1px solid var(--line); }
.billing-links li:first-child { border-top: 0; }
.billing-links a { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); min-block-size: var(--tap-min); padding: var(--space-3) var(--space-4); color: var(--text); text-decoration: none; }
.billing-links a::after { content: "\2192"; color: var(--text-muted); }
.billing-links a:hover { background: var(--brand-tint); color: var(--brand-tint-text); }

/* Billing cards inside the app (owner 2026-10-14, the SnapRender pattern): every plan, the passes and
   Keep-alive as clickable tiles, with a compact annual/monthly toggle. The toggle is a pure-CSS :has()
   switch (no inline script; the CSP forbids one): the checked radio hides the other interval's price and CTA. */
.billing-plan-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }
.billing-plan-head h2 { margin: 0; }
.bill-cards { margin-bottom: var(--space-7); }
/* Passes, add-on and Payments sections keep the same gap as Plans, so none touches the next card. */
.billing-section { margin-bottom: var(--space-7); }
.bill-cards-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; margin-bottom: var(--space-4); }
.bill-cards-head h2 { margin: 0; }
.bill-toggle { margin: 0; }
.seg-hint { color: var(--brand-tint-text); font-weight: 650; }
.bill-cards .plans { margin: 0 0 var(--space-6); }
.bill-cards > h2 { margin: var(--space-2) 0; }
.bill-cards:not(:has(#bill-month:checked)) [data-bill="month"] { display: none; }
.bill-cards:has(#bill-month:checked) [data-bill="year"] { display: none; }
.plan-tile.is-featured { box-shadow: var(--shadow-2); }
.plan-tile.is-current { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand); }
.plan-tile .plan-price { margin-bottom: 0; }
/* Plan cards: the period sits on its own small line in every card, so the price blocks line up across the row. */
.plan-unit { margin: var(--space-1) 0 0; font-family: var(--font-text); font-size: var(--step--2); font-weight: 400; color: var(--text-muted); line-height: 1.3; }
/* Pass and Keep-alive cards keep their descriptor beside the price (single cards, not a 5-across row). */
.plan-tile .plan-price .unit { display: inline-block; margin-left: var(--space-1); font-family: var(--font-text); font-size: var(--step--2); font-weight: 400; color: var(--text-muted); letter-spacing: 0; white-space: nowrap; }
.plan-sub { margin: 0; color: var(--text-muted); font-size: var(--step--2); }
.plan-cta { margin-top: auto; }
.plan-tile .plan-current { margin-top: auto; font-size: var(--step--1); }
.pass-tile .plan-price { font-size: var(--step-3); }
/* Phones: the plan cards stack one per row, so they size to their own content. Drop the empty spacer line
   the Free card carries to align with the paid cards' sub (it left a big gap under "$0"). The price unit
   now sits inline inside the price, like the pass and keep-alive cards (owner pass 2). */
@media (width < 760px) {
  .bill-cards .plans { align-items: start; }
  .bill-cards .plan-sub[aria-hidden="true"] { display: none; }
}
.pay-table { inline-size: 100%; border-collapse: collapse; font-size: var(--step--1); }
.pay-table th, .pay-table td { text-align: start; padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--line); }
.pay-table th { color: var(--text-muted); font-weight: 650; }
.pay-table td { font-variant-numeric: tabular-nums; }

/* Editor schedule: style the native date-time controls so they match the other inputs (no raw glyph box). */
input[type="datetime-local"], input[type="date"], input[type="time"] { color-scheme: light dark; }

/* Home "Setup steps" help panel: a real disclosure control, not a bare browser triangle. */
.home-checklist details > summary { list-style: none; display: flex; align-items: center; gap: var(--space-3); min-height: var(--tap-min); cursor: pointer; }
.home-checklist details > summary::-webkit-details-marker { display: none; }
.home-checklist details > summary h2 { margin: 0; }
.home-checklist details > summary::after { content: ""; width: calc(9 * var(--unit)); height: calc(9 * var(--unit)); margin-left: auto; border-right: 2px solid var(--text-muted); border-bottom: 2px solid var(--text-muted); transform: rotate(-45deg); transition: transform var(--dur-hover) var(--ease-out); }
.home-checklist details[open] > summary::after { transform: rotate(45deg); }
@media (prefers-reduced-motion: reduce) { .home-checklist details > summary::after { transition: none; } }

/* File inputs get a styled treatment instead of the browser's raw control: the picker button matches a
   quiet secondary button and the chosen filename reads in muted ink. (Hidden custom pickers, e.g. the
   studio dropzones, use .visually-hidden and keep their own trigger.) */
input[type="file"]:not(.visually-hidden) { display: block; width: 100%; max-width: calc(460 * var(--unit)); font: inherit; color: var(--text-muted); }
input[type="file"]:not(.visually-hidden)::file-selector-button { margin-right: var(--space-3); min-height: var(--tap-min); padding: var(--space-2) var(--space-4); border: 1px solid var(--line-strong); border-radius: var(--radius-m); background: var(--surface); color: var(--text); font: inherit; font-weight: 650; cursor: pointer; transition: background-color var(--dur-hover) var(--ease-out), border-color var(--dur-hover) var(--ease-out); }
input[type="file"]:not(.visually-hidden)::file-selector-button:hover { background: var(--brand-tint); border-color: var(--brand); color: var(--brand-tint-text); }
@media (prefers-reduced-motion: reduce) { input[type="file"]:not(.visually-hidden)::file-selector-button { transition: none; } }
.xv-path { fill: none; stroke: var(--line-strong); stroke-width: 3; stroke-dasharray: 2 9; stroke-linecap: round; opacity: 0.85; }
.xv-stop-g .xv-stop { fill: var(--surface); stroke: var(--brand); stroke-width: 3; transition: fill var(--dur-hover) var(--ease-out), stroke var(--dur-hover) var(--ease-out); }
.xv-stop-g .xv-num { fill: var(--brand-tint-text); font: 700 calc(20 * var(--unit)) var(--font-display); transition: fill var(--dur-hover) var(--ease-out); }
.xv-halo { fill: var(--brand); opacity: 0; transform-box: fill-box; transform-origin: center; transform: scale(0.55); transition: opacity var(--dur-hover) var(--ease-out), transform var(--dur-hover) var(--ease-out); }
.xv-stop-g.is-done .xv-stop { fill: var(--brand-tint); }
.xv-stop-g.is-on .xv-stop { fill: var(--brand); stroke: var(--brand); }
.xv-stop-g.is-on .xv-num { fill: var(--on-brand); }
.xv-stop-g.is-on .xv-halo { opacity: 0.16; transform: scale(1); }
.xp-steps > li.is-on .xp-step-num { box-shadow: 0 0 0 calc(5 * var(--unit)) var(--brand-tint), 0 0 0 calc(7 * var(--unit)) var(--brand); }
/* Scroll storytelling (UX v4): sections are visible by default. ui.js, only when motion is allowed, hides
   the sections still below the fold (data-reveal-pending, off-screen so no flash) and reveals them on entry.
   The global reduced-motion reset turns the transition off, so nothing moves and everything stays visible. */
[data-reveal] { transition: opacity 0.5s var(--ease-out), transform 0.5s var(--ease-out); }
/* Slide only, never fade: text keeps its full contrast while it waits (axe, readers, crawlers). */
[data-reveal][data-reveal-pending] { transform: translateY(calc(16 * var(--unit))); }
[data-reveal].is-in { opacity: 1; transform: none; }

/* ======================================================================
   ux-v4 hubs2 (owner review 2026-10-14): the second slice of the
   experience layer. Timeline, copyable code blocks, CSS tabs, a polished
   comparison table and verdict card, a full-width tool shell with a
   designed result, a friendly error page and the help-article doc.
   Tokens only; breakpoints reuse 600 / 760 / 900 / 1100. See
   .factory/ux-v4/ux4-hubs-critique.md.
   ====================================================================== */

/* A card head that carries an icon tile, a title and an optional status badge. */
.hub-card-head { display: flex; align-items: center; gap: var(--space-3); }
.hub-card-head .hub-card-title { margin: 0; }
.hub-card-head .badge { margin-left: auto; }
.hub-card .tile-icon { width: calc(40 * var(--unit)); height: calc(40 * var(--unit)); }

/* Changelog timeline: a dated rail, each day a node with its shipped items. */
.timeline { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-8); }
.timeline-day { position: relative; padding-left: var(--space-7); border-left: 2px solid var(--line); }
.timeline-day::before { content: ""; position: absolute; left: calc(-6 * var(--unit)); top: calc(6 * var(--unit)); width: calc(11 * var(--unit)); height: calc(11 * var(--unit)); border-radius: 50%; background: var(--brand); box-shadow: 0 0 0 calc(4 * var(--unit)) var(--brand-tint); }
.timeline-date { font-family: var(--font-display); font-weight: 650; font-size: var(--step-1); margin: 0 0 var(--space-4); }
.timeline-date time { color: var(--text); }
.timeline-items { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.timeline-item { display: flex; gap: var(--space-3); align-items: flex-start; padding: var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); box-shadow: var(--shadow-1); }
.timeline-item .tile-icon { width: calc(34 * var(--unit)); height: calc(34 * var(--unit)); border-radius: var(--radius-s); }
.timeline-item .tile-icon svg { width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); }
.timeline-item p { margin: 0; }

/* A copyable code block: a label row, a scrollable code area and a copy button
   that never overlaps the code. Replaces bare <pre> that overflowed the column. */
.code-block { border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface-sunken); overflow: hidden; margin: var(--space-4) 0; }
.code-block-head { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-4); border-bottom: 1px solid var(--line); background: var(--surface); }
.code-block-label { font-family: var(--font-mono); font-size: var(--step--1); color: var(--text-muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.code-block-head .button { margin-left: auto; flex: none; }
.code-block pre { margin: 0; padding: var(--space-4); overflow-x: auto; }
.code-block code { font-family: var(--font-mono); font-size: var(--step--1); line-height: 1.6; white-space: pre; color: var(--text); }
.code-inline { display: inline-flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.code-inline code { font-family: var(--font-mono); font-size: var(--step--1); padding: var(--space-1) var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--surface-sunken); word-break: break-all; }

/* CSS-only tabs: direct-child radios drive which panel shows, mapped by order with
   :has() and :nth-of-type so one rule set serves any tab count (no script). */
.tabset { margin: var(--space-5) 0; }
.tabset > input { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.tablist { display: flex; flex-wrap: wrap; gap: var(--space-2); border-bottom: 1px solid var(--line); margin-bottom: var(--space-5); }
.tablist label { display: inline-flex; align-items: center; min-height: var(--tap-min); padding: 0 var(--space-4); border: 1px solid transparent; border-bottom: none; border-radius: var(--radius-s) var(--radius-s) 0 0; font-weight: 600; font-size: var(--step--1); color: var(--text-muted); cursor: pointer; }
.tablist label:hover { color: var(--text); background: var(--brand-tint); }
.tabpanels > .tabpanel { display: none; }
.tabpanels > .tabpanel > :first-child { margin-top: 0; }
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .tablist label { transition: color 0.15s ease, background 0.15s ease; }
}
.tabset > input:nth-of-type(1):checked ~ .tabpanels > .tabpanel:nth-of-type(1),
.tabset > input:nth-of-type(2):checked ~ .tabpanels > .tabpanel:nth-of-type(2),
.tabset > input:nth-of-type(3):checked ~ .tabpanels > .tabpanel:nth-of-type(3),
.tabset > input:nth-of-type(4):checked ~ .tabpanels > .tabpanel:nth-of-type(4),
.tabset > input:nth-of-type(5):checked ~ .tabpanels > .tabpanel:nth-of-type(5),
.tabset > input:nth-of-type(6):checked ~ .tabpanels > .tabpanel:nth-of-type(6),
.tabset > input:nth-of-type(7):checked ~ .tabpanels > .tabpanel:nth-of-type(7),
.tabset > input:nth-of-type(8):checked ~ .tabpanels > .tabpanel:nth-of-type(8) { display: block; }
.tabset:has(> input:nth-of-type(1):checked) .tablist label:nth-of-type(1),
.tabset:has(> input:nth-of-type(2):checked) .tablist label:nth-of-type(2),
.tabset:has(> input:nth-of-type(3):checked) .tablist label:nth-of-type(3),
.tabset:has(> input:nth-of-type(4):checked) .tablist label:nth-of-type(4),
.tabset:has(> input:nth-of-type(5):checked) .tablist label:nth-of-type(5),
.tabset:has(> input:nth-of-type(6):checked) .tablist label:nth-of-type(6),
.tabset:has(> input:nth-of-type(7):checked) .tablist label:nth-of-type(7),
.tabset:has(> input:nth-of-type(8):checked) .tablist label:nth-of-type(8) { color: var(--brand-tint-text); background: var(--surface); border-color: var(--line); border-bottom-color: var(--surface); margin-bottom: -1px; }
.tabset > input:focus-visible ~ .tablist label { outline: 2px solid var(--focus); outline-offset: 2px; }

/* A polished comparison table: sticky head, highlighted "us" column, tabular
   figures, numbers right-aligned where a cell is purely a number. */
.cmp-table-wrap { margin: var(--space-6) 0; overflow: auto; border: 1px solid var(--line); border-radius: var(--radius-m); max-height: 80vh; }
.cmp-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--step--1); font-variant-numeric: tabular-nums; }
.cmp-table caption { text-align: left; font-weight: 650; padding: var(--space-3) var(--space-4); }
.cmp-table th, .cmp-table td { text-align: left; padding: var(--space-4); border-bottom: 1px solid var(--line); vertical-align: top; }
.cmp-table thead th { position: sticky; top: 0; z-index: 1; background: var(--surface); font-weight: 650; color: var(--text); border-bottom: 2px solid var(--line-strong); }
.cmp-table tbody th[scope="row"] { font-weight: 600; color: var(--text); background: var(--surface); }
.cmp-table col.cmp-us, .cmp-table .cmp-us-cell { background: var(--brand-tint); }
.cmp-table thead th.cmp-us-cell { color: var(--brand-tint-text); }
.cmp-table td.num, .cmp-table th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cmp-check { display: inline-flex; width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); margin-right: var(--space-2); vertical-align: -0.15em; color: var(--brand-tint-text); }
.cmp-check svg { width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }

/* Verdict card: three plain-labelled calls, each with a kind marker, not a row of empty checkboxes.
   The markup stays <aside class="card" data-verdict> with <li data-bullet> (pinned by the compare tests),
   so the marker is a CSS ::before shape keyed off the kind, with no extra child elements. */
.card[data-verdict] { border-radius: var(--radius-l); }
.card[data-verdict] h2 { font-size: var(--step-1); }
.verdict-list { list-style: none; margin: var(--space-4) 0 0; padding: 0; display: grid; gap: var(--space-4); }
.verdict-list li { position: relative; padding-left: calc(38 * var(--unit)); line-height: 1.5; }
.verdict-list li::before { content: ""; position: absolute; left: 0; top: 0; width: calc(26 * var(--unit)); height: calc(26 * var(--unit)); border-radius: 50%; }
.verdict-list li[data-bullet="pick"]::before { background: var(--brand-tint); }
.verdict-list li[data-bullet="caveat"]::before { background: var(--status-trial-bg); }
.verdict-list li[data-bullet="stay"]::before { background: var(--surface-sunken); border: 1px solid var(--line); }
/* The check tick for the "pick" marker, drawn with two borders (no extra element). */
.verdict-list li[data-bullet="pick"]::after { content: ""; position: absolute; left: calc(9 * var(--unit)); top: calc(6 * var(--unit)); width: calc(7 * var(--unit)); height: calc(12 * var(--unit)); border-right: 2px solid var(--brand-tint-text); border-bottom: 2px solid var(--brand-tint-text); transform: rotate(40deg); }
.verdict-list li[data-bullet="caveat"]::after { content: "!"; position: absolute; left: 0; top: 0; width: calc(26 * var(--unit)); height: calc(26 * var(--unit)); display: flex; align-items: center; justify-content: center; font-weight: 700; color: var(--status-trial-text); }
.verdict-list li[data-bullet="stay"]::after { content: ""; position: absolute; left: calc(11 * var(--unit)); top: calc(11 * var(--unit)); width: calc(4 * var(--unit)); height: calc(4 * var(--unit)); border-radius: 50%; background: var(--text-muted); }
.verdict-list strong { display: block; }

/* Tool shell: the tool leads, full width, with a designed result area above the form. */
.tool-shell { margin-top: var(--space-7); }
.tool-card { padding: var(--space-6); border: 1px solid var(--line); border-radius: var(--radius-l); background: var(--surface); box-shadow: var(--shadow-1); }
@media (width >= 760px) { .tool-card { padding: var(--space-8); } }
.tool-result { border: 1px solid var(--brand); border-radius: var(--radius-m); background: var(--brand-tint); padding: var(--space-5); margin-bottom: var(--space-6); }
.tool-result h2 { margin: 0 0 var(--space-2); font-size: var(--step-1); }
.tool-result[data-tone="warning"] { border-color: var(--status-trial-dot); background: var(--status-trial-bg); }
.tool-result[data-tone="danger"] { border-color: var(--status-danger-dot); background: var(--status-danger-bg); }
.tool-note { color: var(--text-muted); font-size: var(--step--1); margin-top: var(--space-4); }

/* Friendly error pages: an illustration, the message, a search and the top links. */
.error-page { display: grid; gap: var(--space-7); align-items: center; padding: var(--space-8) 0; }
@media (width >= 900px) { .error-page { grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr); gap: var(--space-10); } }
.error-copy h1 { margin: 0 0 var(--space-3); }
.error-copy .lead { color: var(--text-muted); font-size: var(--step-1); max-width: 46ch; margin: 0 0 var(--space-5); }
.error-search { display: flex; gap: var(--space-3); flex-wrap: wrap; margin-bottom: var(--space-6); }
.error-search .field { flex: 1 1 calc(220 * var(--unit)); margin: 0; }
.error-links { display: flex; flex-wrap: wrap; gap: var(--space-3); list-style: none; margin: 0; padding: 0; }
.error-visual { display: flex; justify-content: center; }
.error-visual svg { width: 100%; max-width: calc(320 * var(--unit)); height: auto; }
.error-glyph { color: var(--brand); }

/* Help article: the doc grid with a sticky "On this page", step cards, related
   article cards and a designed "was this helpful". */
.article-head { margin-bottom: var(--space-7); }
.article-meta { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: center; color: var(--text-muted); font-size: var(--step--1); }
.article-meta .badge { font-weight: 600; }
.article-body.prose { max-width: none; }
.article-body.prose ol { counter-reset: step; list-style: none; padding: 0; display: grid; gap: var(--space-4); }
.article-body.prose ol > li { counter-increment: step; position: relative; padding: var(--space-5) var(--space-5) var(--space-5) calc(60 * var(--unit)); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); box-shadow: var(--shadow-1); margin: 0; }
.article-body.prose ol > li::before { content: counter(step); position: absolute; left: var(--space-5); top: var(--space-5); display: inline-flex; align-items: center; justify-content: center; width: calc(30 * var(--unit)); height: calc(30 * var(--unit)); border-radius: var(--radius-s); background: var(--brand-tint); color: var(--brand-tint-text); font-family: var(--font-display); font-weight: 650; font-size: var(--step--1); }
.feedback-card { border: 1px solid var(--line); border-radius: var(--radius-l); background: var(--surface); box-shadow: var(--shadow-1); padding: var(--space-6); display: flex; flex-wrap: wrap; gap: var(--space-4) var(--space-6); align-items: center; justify-content: space-between; }
.feedback-card h2 { margin: 0; font-size: var(--step-1); }
.feedback-card .inline-form { display: flex; gap: var(--space-3); margin: 0; }

/* No raw browser controls (owner review 2026-10-14): the file-picker button and
   the date field get the styled treatment wherever a tool uses them. */
input[type="file"] { font: inherit; color: var(--text-muted); max-width: 100%; }
input[type="file"]::file-selector-button { font: inherit; font-weight: 600; margin-right: var(--space-3); padding: var(--space-2) var(--space-4); min-height: var(--tap-min); border: 1px solid var(--line-input); border-radius: var(--radius-s); background: var(--surface); color: var(--text); cursor: pointer; }
input[type="file"]::file-selector-button:hover { border-color: var(--brand); color: var(--brand-tint-text); }
input[type="date"]:not(.app-main input) { width: 100%; min-height: var(--tap-min); padding: var(--space-2) var(--space-3); border: 1px solid var(--line-input); border-radius: var(--radius-s); background: var(--surface); color: var(--text); font: inherit; }

/* The integrations hub: each registry entry is a card. The markup stays
   <li data-app><a href> (pinned by INT-080), so the card is styled on the <li>. */
.integrations-list { list-style: none; margin: 0; padding: 0; }
.integrations-list li { position: relative; display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-5) calc(84 * var(--unit)) var(--space-5) var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); box-shadow: var(--shadow-1); }
.integrations-list li > a:first-child { display: inline-flex; align-items: center; gap: var(--space-3); font-family: var(--font-display); font-weight: 650; font-size: var(--step-1); color: var(--text); text-decoration: none; }
.integrations-list li > a:first-child .tile-icon { width: calc(40 * var(--unit)); height: calc(40 * var(--unit)); }
.integrations-list li > a:first-child:hover .integrations-name { color: var(--brand-tint-text); }
.integrations-list .badge { position: absolute; top: var(--space-5); right: var(--space-5); }
.integrations-list p { flex: 1 1 auto; margin: 0; color: var(--text-muted); font-size: var(--step--1); line-height: 1.5; padding-right: 0; }
.integrations-list .hub-card-foot { margin-top: auto; }
.integrations-list li:hover, .integrations-list li:focus-within { border-color: var(--brand); box-shadow: var(--shadow-2); }

/* ==================== UX v4 dashboard (unit ux4-app2) ====================
   A dashboard useful at a glance: a glance row of stat tiles, a "Needs attention" list with one
   action each, recent codes as proper cards (the preview contained), and the setup checklist as a
   designed card. The right rail is a slim support column. Tokens only; px rule holds. */
.home-main { display: grid; gap: var(--space-7); align-content: start; min-width: 0; }

/* Glance tiles. Three to four across on wide screens, stacking on phones. */
.stat-tiles { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(200 * var(--unit))), 1fr)); }
.stat-tile { display: grid; gap: var(--space-2); align-content: start; padding: var(--app-panel-pad, var(--space-5)); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); }
.stat-tile.is-warn { border-color: color-mix(in srgb, var(--meter-warn) 55%, var(--line)); background: color-mix(in srgb, var(--meter-warn) 8%, var(--surface)); }
.stat-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); margin: 0; }
.stat-label { font-weight: 650; font-size: var(--step--1); color: var(--text-muted); }
.stat-go { font-size: var(--step--1); white-space: nowrap; }
.stat-figure { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-2); margin: 0; }
.stat-number { font-family: var(--font-display); font-size: var(--step-3); font-weight: 750; line-height: 1; font-variant-numeric: tabular-nums; }
.stat-sub { font-size: var(--step--1); color: var(--text-muted); }
.stat-trend { display: inline-flex; align-items: center; gap: var(--space-1); padding: 2px var(--space-2); border-radius: var(--radius-pill); font-size: var(--step--2); font-weight: 700; font-variant-numeric: tabular-nums; }
.stat-trend.is-up { background: var(--brand-tint); color: var(--brand-tint-text); }
.stat-trend.is-down { background: var(--status-trial-bg); color: var(--status-trial-text); }
.stat-sub, .stat-trend { white-space: nowrap; }
.stat-meter { margin-top: var(--space-1); }
.stat-meter meter.meter { height: calc(6 * var(--unit)); }
.stat-clear { display: flex; align-items: center; gap: var(--space-2); font-weight: 650; color: var(--text-muted); }
.stat-tick { position: relative; flex: none; width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); border-radius: 50%; background: var(--brand-fill); }
.stat-tick::after { content: ""; position: absolute; left: calc(5 * var(--unit)); top: calc(5 * var(--unit)); width: calc(8 * var(--unit)); height: calc(4 * var(--unit)); border-left: 2px solid var(--on-brand); border-bottom: 2px solid var(--on-brand); transform: rotate(-45deg); }
.week-bars.mini { height: calc(40 * var(--unit)); margin-top: var(--space-1); gap: 2px; }

/* Needs attention: one calm card, one action per row. */
.home-attention { padding: var(--space-5); border: 1px solid color-mix(in srgb, var(--meter-warn) 45%, var(--line)); border-radius: var(--radius-m); background: var(--surface); }
.home-attention > h2 { margin: 0 0 var(--space-3); font-size: var(--step-1); font-family: var(--font-text); font-weight: 700; letter-spacing: 0; }
.attn-list { list-style: none; margin: 0; padding: 0; display: grid; }
.attn-item { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--space-2) var(--space-3); padding: var(--space-3) 0; border-top: 1px solid var(--line); }
.attn-item:first-child { border-top: 0; }
.attn-dot { flex: none; width: calc(10 * var(--unit)); height: calc(10 * var(--unit)); border-radius: 50%; background: var(--meter-warn); }
.attn-item[data-attn="blocked"] .attn-dot, .attn-item[data-attn="broken"] .attn-dot { background: var(--danger-solid); }
.attn-item[data-attn="off"] .attn-dot { background: var(--text-muted); }
.attn-body { min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-3); }
.attn-name { font-weight: 650; color: var(--text); text-decoration: none; overflow-wrap: anywhere; }
a.attn-name:hover { text-decoration: underline; }
.attn-reason { font-size: var(--step--1); color: var(--text-muted); }
.attn-action { margin: 0; white-space: nowrap; }
.attn-more { padding-top: var(--space-3); border-top: 1px solid var(--line); font-size: var(--step--1); }
@media (width < 600px) { .attn-item { grid-template-columns: auto minmax(0, 1fr); } .attn-action { grid-column: 2; justify-self: start; } }

/* Recent codes as proper cards: the preview, name, one status line and this-week scans. */
/* Equal-width cards that fill the row (auto-fit collapses empty tracks so the row's cards stretch). */
.recent-cards { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(210 * var(--unit))), 1fr)); }
.rc-card { display: grid; gap: var(--space-3); align-content: start; padding: var(--app-panel-pad, var(--space-4)); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); transition: border-color var(--dur-hover) var(--ease-out), box-shadow var(--dur-hover) var(--ease-out); }
@media (hover: hover) { .rc-card:hover { border-color: var(--brand); box-shadow: var(--shadow-1); } }
.rc-link { display: block; }
.rc-proof { display: grid; place-items: center; aspect-ratio: 1; max-width: calc(140 * var(--unit)); margin-inline: auto; padding: var(--space-3); background: var(--surface-raised); border: 1px solid var(--line); border-radius: var(--radius-s); }
.rc-proof .code-thumb-svg, .rc-proof svg { width: 100%; height: auto; display: block; }
.rc-body { display: grid; gap: var(--space-2); min-width: 0; }
/* The name on one line with an ellipsis, so cards keep equal heights and never overflow. */
.rc-name { display: block; min-width: 0; font-weight: 700; color: var(--text); text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: var(--leading-snug); }
.rc-name:hover { text-decoration: underline; }
/* One compact status line: the shared mode and state badges rendered as plain inline text (their
   dot and shape markers kept), joined by a middot, so Home stays on the shared components (UX-025). */
.rc-status { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0; min-width: 0; font-size: var(--step--1); color: var(--text-muted); }
.rc-status .mode-badge.is-compact, .rc-status .badge.is-compact { min-height: 0; padding: 0; border: 0; border-radius: 0; background: none; color: var(--text-muted); font-weight: inherit; gap: var(--space-1); white-space: normal; }
.rc-sep { flex: none; color: var(--text-muted); }
.rc-stat { display: flex; align-items: center; gap: var(--space-2); margin: 0; font-size: var(--step--1); color: var(--text-muted); }
.rc-scans strong { font-variant-numeric: tabular-nums; color: var(--text); }
@media (prefers-reduced-motion: reduce) { .rc-card { transition: none; } }

/* The setup checklist as a designed card in the main column (prompt shows a progress bar; the payer
   help variant is a quiet disclosure). */
.home-main > .home-checklist { padding: var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); }
.home-main > .home-checklist > :first-child { margin-top: 0; }
.home-main > .home-checklist h2 { font-size: var(--step-1); font-family: var(--font-text); font-weight: 700; letter-spacing: 0; }

/* ==================== UX v4 codes list (unit ux4-app2) ====================
   A compact sticky bulk bar that appears only with a selection (main actions + More), one header row
   for the scan columns instead of a label per row, calmer denser rows. Tokens only. */

/* Bulk bar: hidden until something is selected (JS on); no-JS keeps it visible so the form still works. */
.js .bulk-bar:not(.has-selection) { display: none; }
.bulk-bar { flex-wrap: nowrap; align-items: center; gap: var(--space-3) var(--space-4); }
.bulk-bar.has-selection { background: var(--brand-tint); box-shadow: var(--shadow-1); }
.bulk-count { flex: none; margin: 0; font-weight: 700; color: var(--brand-tint-text); white-space: nowrap; }
.bulk-count:empty { display: none; }
.bulk-buttons { flex: 1 1 auto; gap: var(--space-2); }
.bulk-bar .bulk-keys { flex: 1 1 100%; }
/* "More" opens a panel of the less-used actions (Bring back, Star, Move to, Tag, Change domain). */
.bulk-more { position: relative; }
.bulk-more > summary { list-style: none; }
.bulk-more > summary::-webkit-details-marker { display: none; }
.bulk-more > summary::after { content: " \25BE"; }
.bulk-more[open] > summary::after { content: " \25B4"; }
.bulk-more-panel { position: absolute; right: 0; z-index: 3; margin-top: var(--space-2); display: grid; gap: var(--space-3); width: max-content; max-width: min(92vw, calc(360 * var(--unit))); padding: var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface-raised); box-shadow: var(--shadow-2); }
.bulk-more-panel > .button { justify-self: start; }
.bulk-more-panel .bulk-with { display: grid; gap: var(--space-3); }
.bulk-more-panel .bulk-with .field { flex: none; margin: 0; }
@media (width < 760px) { .bulk-bar { flex-wrap: wrap; } .bulk-buttons { flex-basis: 100%; } .bulk-more-panel { right: auto; left: 0; } }

/* The list header row: select-all and the three scan-column labels, aligned to the rows below. */
.code-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: 0 0 var(--space-3); margin-bottom: var(--space-2); border-bottom: 1px solid var(--line); }
.code-head-all { min-height: var(--tap-min); align-items: center; gap: var(--space-2); font-weight: 600; color: var(--text-muted); }
.code-head-name { display: none; }
.scans-head { display: none; }
/* The header row only earns its space where it carries the scan-column labels (the wide list). In the grid
   and on narrow list widths it holds just the select-all, so it is hidden to keep the first card close to
   the toolbar (selection there is per card). */
.code-head.is-grid-head { display: none; }
@media (width < 1100px) { .code-head { display: none; } }
@media (width >= 1100px) {
  .code-head { gap: var(--space-4); }
  .code-head-name { display: block; flex: 1 1 auto; font-size: var(--step--1); font-weight: 650; color: var(--text-muted); }
  .code-head-all .code-head-all-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .scans-head { display: flex; gap: var(--space-5); flex: none; }
  .scans-head > span { min-width: calc(50 * var(--unit)); text-align: right; font-size: var(--step--1); color: var(--text-muted); }
  /* With the header carrying the labels, the per-row labels in the list recede from view (kept for assistive
     tech); the grid tiles keep their own labels since they have no header row. */
  .code-list:not(.is-grid) .code-scans dt { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}
/* The list header's select-all follows the per-row checkbox: it shows on hover, focus or an active selection. */
.code-head-all { opacity: 0; transition: opacity var(--dur-hover) var(--ease-out); }
[data-bulk]:hover .code-head-all, [data-bulk]:focus-within .code-head-all, [data-bulk].has-selection .code-head-all { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .code-head-all { transition: none; } }

/* "Not downloaded yet" is a subtle download glyph with a tooltip, not a line of text. */
.code-print-none { display: inline-flex; align-items: center; }
.print-icon { display: inline-block; width: calc(13 * var(--unit)); height: calc(13 * var(--unit)); border-bottom: 1.5px solid currentColor; position: relative; opacity: 0.55; }
.print-icon::before { content: ""; position: absolute; left: 50%; top: 0; width: 1.5px; height: calc(7 * var(--unit)); background: currentColor; transform: translateX(-50%); }
.print-icon::after { content: ""; position: absolute; left: 50%; top: calc(4 * var(--unit)); width: calc(5 * var(--unit)); height: calc(5 * var(--unit)); border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: translate(-50%, 0) rotate(45deg); }

/* ==================== UX v4 editor settings (unit ux4-app2) ====================
   Each settings group is a titled card; on/off settings are switches; a sticky save bar appears when a
   form changes (no-JS keeps it visible). Tokens only. */
.setting-card { display: grid; gap: var(--space-4); padding: var(--space-5); margin-bottom: var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface); }
.setting-card > h3 { margin: 0; font-size: var(--step-1); }
.setting-card > .field, .setting-card > .inline-fields { margin: 0; }
.setting-card.panel-block + .setting-card.panel-block { padding-top: var(--space-5); border-top: 1px solid var(--line); }
/* Consistent field widths inside cards: single-line controls do not stretch across the whole column. */
.setting-card input:where([type="text"], [type="url"], [type="number"], [type="datetime-local"], [type="password"]), .setting-card select { max-width: calc(560 * var(--unit)); }
.setting-card .inline-fields input { max-width: none; }
.setting-form { display: block; }
.setting-action { margin: var(--space-2) 0 0; }

/* Styled on/off switch (label.check.switch): shape and colour both change with state. */
.check.switch { align-items: center; gap: var(--space-3); font-weight: 500; }
.check.switch input[type="checkbox"] { appearance: none; -webkit-appearance: none; position: relative; flex: none; width: calc(44 * var(--unit)); height: calc(24 * var(--unit)); margin: 0; border: 0; border-radius: var(--radius-pill); background: var(--line-strong); cursor: pointer; transition: background-color var(--dur-hover) var(--ease-out); }
.check.switch input[type="checkbox"]::after { content: ""; position: absolute; top: calc(2 * var(--unit)); left: calc(2 * var(--unit)); width: calc(20 * var(--unit)); height: calc(20 * var(--unit)); border-radius: 50%; background: var(--surface-raised); box-shadow: var(--shadow-1); transition: transform var(--dur-hover) var(--ease-out); }
.check.switch input[type="checkbox"]:checked { background: var(--brand); }
.check.switch input[type="checkbox"]:checked::after { transform: translateX(calc(20 * var(--unit))); }
@media (prefers-reduced-motion: reduce) { .check.switch input[type="checkbox"], .check.switch input[type="checkbox"]::after { transition: none; } }

/* Sticky save bar: one per settings form, shown when the form is dirty (JS); always shown without JS. */
.save-bar { position: sticky; bottom: var(--space-2); z-index: 2; display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--space-3) var(--space-4); margin: var(--space-2) 0 var(--space-5); padding: var(--space-3) var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface-raised); box-shadow: var(--shadow-2); }
.save-bar-text { margin: 0; margin-right: auto; }
.js form[data-save-bar]:not(.is-dirty) .save-bar { display: none; }
@media (prefers-reduced-motion: no-preference) { form[data-save-bar].is-dirty .save-bar { animation: save-in 220ms cubic-bezier(0.2, 0.8, 0.2, 1) both; } @keyframes save-in { from { opacity: 0; transform: translateY(calc(6 * var(--unit))); } to { opacity: 1; transform: none; } } }
.gate-leads-link { margin: var(--space-4) 0 0; }

/* Disclosure controls in the rules editor get a chevron, never the browser's bare triangle (same fix as
   Home's Setup steps). The library's "New folder" is a plain "+" text button instead (see .side-add). */
.rule-template > summary, .rule-extend > summary {
  list-style: none; display: inline-flex; align-items: center; gap: var(--space-2);
  min-height: var(--tap-min); color: var(--link); font-weight: 650; cursor: pointer;
}
.rule-template > summary::-webkit-details-marker, .rule-extend > summary::-webkit-details-marker { display: none; }
.rule-template > summary::before, .rule-extend > summary::before {
  content: ""; flex: none; width: calc(7 * var(--unit)); height: calc(7 * var(--unit));
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(-45deg);
  transition: transform var(--dur-hover) var(--ease-out);
}
.rule-template[open] > summary::before, .rule-extend[open] > summary::before { transform: rotate(45deg); }
@media (prefers-reduced-motion: reduce) { .rule-template > summary::before, .rule-extend > summary::before { transition: none; } }

/* Leads inbox (05 LNK-056): a real data table at a comfortable width, left-aligned, not squeezed into a
   narrow confirmation column. */
.leads-page { max-width: calc(880 * var(--unit)); }
.table-scroll { overflow-x: auto; }
.data-table { width: 100%; border-collapse: collapse; margin: var(--space-3) 0 var(--space-5); font-size: var(--step--1); }
.data-table th, .data-table td { padding: var(--space-3) var(--space-4); text-align: left; vertical-align: top; border-bottom: 1px solid var(--line); white-space: nowrap; }
.data-table thead th { font-weight: 650; color: var(--text-muted); border-bottom: 2px solid var(--line-strong); }
.data-table tbody tr:hover { background: var(--surface-sunken); }
.data-table .check { margin: 0; }

/* Account settings pages (rendered in the shared layout): submit buttons sit at their natural width,
   and the workspace list is not a raw bulleted list. */
.card form.stack > button[type="submit"]:not(.block),
.card form.stack > .button:not(.block) { justify-self: start; }
.card ul.stack { list-style: none; padding-left: 0; }

/* Editor tabs that still use plain stacked forms (Tracking, scan alerts): the primary save sits at its
   natural width, left-aligned, not a full-width bar. */
.editor-panel form.stack > button[type="submit"]:not(.block),
.editor-panel form.stack > .button:not(.block),
.editor-panel form.panel-block > button[type="submit"]:not(.block),
.editor-panel form.panel-block > .button:not(.block) { justify-self: start; }

/* ==================== signup-nudge (unit r6-guides) ====================
   The slide-up sign-up prompt (views/partials/signup-nudge.ejs) on guides, tools and use-case pages.
   Fixed to the bottom, about a tenth of the viewport, under the phone generator bar (z 40) and the
   toasts (z 50). Hidden until the script reveals it; it slides in from below, or simply appears under
   reduced motion. No layout shift: it is fixed and out of flow. Tokens only; the px rule holds. */
.signup-nudge {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 35;
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: var(--space-3);
  min-height: 10vh;
  padding: var(--space-3) var(--gutter) calc(var(--space-3) + env(safe-area-inset-bottom));
  background: var(--surface-raised);
  border-top: 1px solid var(--line-strong);
  box-shadow: var(--shadow-3);
  transform: translateY(110%);
  transition: transform 240ms var(--ease-out);
}
.signup-nudge.is-in { transform: translateY(0); }
.signup-nudge[hidden] { display: none; }
.signup-nudge-text { margin: 0; min-width: 0; font-weight: 600; font-size: var(--step-0); line-height: var(--leading-snug); }
.signup-nudge-go { flex: none; margin-left: auto; white-space: nowrap; }
.signup-nudge-close { flex: none; display: grid; place-items: center; width: var(--tap-min); height: var(--tap-min); padding: 0; border: 0; border-radius: var(--radius-s); background: transparent; color: var(--text-muted); cursor: pointer; }
.signup-nudge-close:hover { background: var(--surface-sunken); color: var(--text); }
.signup-nudge-close svg { width: calc(18 * var(--unit)); height: calc(18 * var(--unit)); fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
@media (width < 600px) {
  .signup-nudge-go { margin-left: 0; }
  .signup-nudge-text { font-size: var(--step--1); }
}
@media (prefers-reduced-motion: reduce) {
  .signup-nudge { transition: none; transform: none; }
}

/* ==================== size calculator + tool form patterns (unit r6-guides) ====================
   Owner review 2026-10-14: the size tool and the embedded guide calculator become a compact centred card
   with a short "cm" input, a select sized to its text at the normal size, a spaced button, and a result
   that previews the code scaled to the computed width with the size in mm. Shared .input-affix and
   .auto-select patterns fix the crude full-width inputs and tiny selects on the other tool pages too.
   Tokens only; the px rule holds. */
.size-tool { max-width: calc(760 * var(--unit)); margin-inline: auto; }
.size-form { display: grid; gap: var(--space-4); }
.size-form > h2 { margin: 0; font-size: var(--step-1); }
.size-form-row { display: flex; flex-wrap: wrap; align-items: end; gap: var(--space-4) var(--space-5); }
.size-field { flex: 0 0 auto; }
.size-field .input-affix { width: calc(132 * var(--unit)); max-width: 100%; }
.size-content { flex: 0 0 auto; min-width: 0; }
.size-go { flex: none; align-self: end; }
.size-poster { margin-top: var(--space-4); margin-bottom: 0; }

/* A number input with a unit suffix shown inside the control. */
.input-affix { position: relative; display: inline-flex; align-items: center; width: 100%; }
.input-affix > input { width: 100%; padding-right: calc(38 * var(--unit)); }
.input-affix-suffix { position: absolute; right: var(--space-3); color: var(--text-muted); font-size: var(--step--1); pointer-events: none; }

/* A select sized to its longest option, at the normal text size (no shrunken dropdown). */
.auto-select { width: auto; max-width: 100%; min-width: 0; font-size: var(--step-0); }

/* The result: a scaled preview beside the figure in mm and the plain line. */
.size-result { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-5); }
.size-result-text { flex: 1 1 calc(280 * var(--unit)); min-width: 0; }
.size-result-text h2 { text-wrap: balance; }
.size-hint { margin: var(--space-1) 0 0; }
.size-result-text > :first-child { margin-top: 0; }
.size-result-text > :last-child { margin-bottom: 0; }
.size-preview { flex: none; margin: 0; display: grid; justify-items: center; gap: var(--space-2); }
.size-preview-code { display: grid; place-items: center; padding: var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--fixed-white); color: var(--paper-ink); }
.size-preview .qr-glyph { display: block; width: calc(64 * var(--unit)); height: calc(64 * var(--unit)); }
.size-preview[data-scale="xs"] .qr-glyph { width: calc(46 * var(--unit)); height: calc(46 * var(--unit)); }
.size-preview[data-scale="s"] .qr-glyph { width: calc(62 * var(--unit)); height: calc(62 * var(--unit)); }
.size-preview[data-scale="m"] .qr-glyph { width: calc(84 * var(--unit)); height: calc(84 * var(--unit)); }
.size-preview[data-scale="l"] .qr-glyph { width: calc(106 * var(--unit)); height: calc(106 * var(--unit)); }
.size-preview[data-scale="xl"] .qr-glyph { width: calc(128 * var(--unit)); height: calc(128 * var(--unit)); }
.size-preview-cap { font-family: var(--font-display); font-weight: 650; font-size: var(--step-0); color: var(--text-muted); font-variant-numeric: tabular-nums; }
@keyframes size-pop {
  from { transform: scale(0.72); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}
@media (prefers-reduced-motion: no-preference) { .size-preview-code { animation: size-pop 320ms var(--ease-out) both; } }

/* Shared tool-form tidy: short-value controls keep a sensible width and buttons are not glued to a field.
   The embed options (two selects and an accent colour) sit in a wrapping row, each sized to its content. */
.embed-options { display: flex; flex-wrap: wrap; align-items: end; gap: var(--space-4) var(--space-5); }
.embed-options .field { margin: 0; }
.embed-color { width: calc(72 * var(--unit)); min-height: var(--tap-min); padding: var(--space-1); }
.embed-options .button { align-self: end; }

/* ==================== guides: summary card + sticky "On this page" (unit r6-guides) ====================
   Owner review 2026-10-14: guides read as a scannable experience. The key answer (the GEO block) becomes a
   summary card at the top, and a sticky rail lists the page's own sections so a reader jumps instead of
   wading. Scoped to guides via [data-xp-key="guide"] and the .guide-toc the guide model emits. */
.xp-hero[data-xp-key="guide"] .home-answer {
  max-width: none;
  margin-top: var(--space-5);
  padding: var(--space-5) var(--space-6);
  border: 1px solid var(--line);
  border-left: calc(4 * var(--unit)) solid var(--brand);
  border-radius: var(--radius-m);
  background: var(--surface);
  box-shadow: var(--shadow-1);
  color: var(--text);
  font-size: var(--step-0);
  line-height: 1.55;
}
@media (width < 760px) {
  .xp-hero[data-xp-key="guide"] .home-answer { font-size: var(--step--1); padding: var(--space-4) var(--space-5); }
}

.guide-toc { position: sticky; top: var(--bar-height); z-index: 5; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); margin: var(--space-6) 0; padding: var(--space-3) var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-m); background: var(--surface-raised); box-shadow: var(--shadow-1); }
.guide-toc-title { margin: 0; font-size: var(--step--1); font-weight: 700; color: var(--text-muted); white-space: nowrap; }
.guide-toc-list { display: flex; flex-wrap: wrap; gap: var(--space-2); list-style: none; margin: 0; padding: 0; min-width: 0; }
.guide-toc-link { display: inline-block; padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill); font-size: var(--step--1); font-weight: 600; color: var(--text-muted); text-decoration: none; white-space: nowrap; }
.guide-toc-link:hover, .guide-toc-link.is-active { background: var(--brand-tint); color: var(--brand-tint-text); }
.guide-toc-link[aria-current] { background: var(--brand-tint); color: var(--brand-tint-text); }
@media (width < 760px) {
  .guide-toc { position: static; flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .guide-toc-list { flex-wrap: nowrap; }
}
.field > .snip-copy { justify-self: start; margin-top: var(--space-2); }
