/* The free guide's styles: the app's index.css + ui.css and guide/guide.css, only the rules these pages use (bin/guide-export.mjs). */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* Palette: the approved "Clients to Win" prototype (Eric 2026-09-08). One place.
   Change a colour here and the whole site changes. */
:root {
  --bg: #F4F4F0;
  --bg-secondary: #FFFFFF;
  --bg-tertiary: #ECECE6;
  --surface: #FFFFFF;
  --surface-hover: #ECECE6;
  --field-surface: #FFFFFF;
  --field-padding-block: clamp(6px, 0.65em, 10px);
  --field-padding-inline: clamp(8px, 1em, 14px);
  --field-radius: 12px;
  --control-radius: 10px;
  --control-padding-block: 10px;
  --control-padding-inline: 14px;
  --control-selected: var(--accent-1-soft);
  --control-selected-border: var(--accent-1-line);
  --border: #E2E2DB;
  --border-subtle: rgba(0, 0, 0, 0.05);
  --text-primary: #121315;
  --text-secondary: #62645E;
  --text-tertiary: #9A9B94;
  /* DESIGN step 10 (2026-09-09): the violet is DEAD. `--accent` survives only as an alias
     because `Influencers.jsx` (step 9, the Create seat) still reads it — pink, not lime, so its
     white-on-accent buttons stay readable until they convert. Delete these three lines the
     day Influencers.jsx no longer reads the old name; `ui.test.mjs` insists on it. */
  --accent: var(--accent-2);
  --accent-hover: var(--accent-2);
  --accent-light: var(--accent-2-soft);
  --shadow-sm: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
  --shadow-md: 0 4px 16px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.04);
  --shadow-lg: 0 12px 40px rgba(0,0,0,0.10), 0 4px 8px rgba(0,0,0,0.04);
  --radius-sm: 10px;
  --radius-md: 14px;
  --radius-lg: 16px;
  --radius-xl: 20px;
  --nav-h: 56px;
}

/* Dark is violet-black, not grey (Eric 2026-09-09: "more on the tone of dark
   purple", like the landing page). Every dark grey below carries a little blue-
   violet; the ground also gets the dot grid and two glows (body::before). */
[data-theme="dark"] {
  --bg: #0B0A14;
  --bg-secondary: #15131F;
  --bg-tertiary: #1E1B2B;
  --surface: #15131F;
  --surface-hover: #1E1B2B;
  --field-surface: #1A1826;
  --border: rgba(255,255,255,0.09);
  --border-subtle: rgba(255,255,255,0.06);
  /* Light grey, not bright white (Eric, 2026-09-24: "the bright white is disturbing the eyes
     when we are in dark mode … close to white, but light gray"). Was #F4F3F7. */
  --text-primary: #CFCDD8;
  --text-secondary: #A6A3B3;
  --text-tertiary: #6E6B7C;
  --accent: var(--accent-2);
  --accent-hover: var(--accent-2);
  --accent-light: var(--accent-2-soft);
  --control-selected: var(--accent-1-soft);
  --control-selected-border: var(--accent-1-line);
  --shadow-sm: 0 1px 3px rgba(0,0,0,0.5), 0 1px 2px rgba(0,0,0,0.4);
  --shadow-md: 0 4px 16px rgba(0,0,0,0.6), 0 2px 4px rgba(0,0,0,0.4);
  --shadow-lg: 0 12px 40px rgba(0,0,0,0.7), 0 4px 8px rgba(0,0,0,0.4);
}

@keyframes cs-pulse {
  0%, 100% { opacity: 0.5; }
  50%       { opacity: 1;   }
}
@keyframes cs-shimmer {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%);  }
}
@keyframes cs-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

html, body {
  height: 100%;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif;
  color: var(--text-primary);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overscroll-behavior: none;
}

/* The ground is alive (Eric 2026-09-09): a faint dot grid over the whole page,
   and in dark two soft violet glows so the dark side reads purple, never grey.
   Fixed behind everything, so it never scrolls and costs nothing.
   Only `html` carries the colour — it propagates to the canvas, under the glow.
   `body` stays clear: a body that paints its own colour is one viewport tall
   (height: 100%) and hid the glow for the first screen (Eric 2026-09-09:
   "when I go to the top of the page it's flat"). */
html { background: var(--bg); }
body { background: transparent; }
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(rgba(20, 20, 10, 0.08) 1px, transparent 1px),
    radial-gradient(60% 50% at 8% -8%, rgba(217, 255, 60, 0.22), transparent 70%);
  background-size: 28px 28px, 100% 100%;
}

[data-theme="dark"] body::before {
  background-image:
    radial-gradient(rgba(255, 255, 255, 0.06) 1px, transparent 1px),
    radial-gradient(60% 50% at 8% -8%, rgba(139, 92, 246, 0.24), transparent 70%),
    radial-gradient(50% 45% at 100% 0%, rgba(236, 72, 153, 0.10), transparent 70%),
    radial-gradient(55% 45% at 50% 112%, rgba(99, 70, 200, 0.18), transparent 70%);
  background-size: 28px 28px, 100% 100%, 100% 100%, 100% 100%;
}

/* ── THE BUTTON CURSOR CONVENTION (task 275) ────────────────────────────────
   One place decides what a button's cursor says. Change these two rules and
   every button in the app changes with them — do NOT re-state a cursor inline.

     enabled  -> pointer      "you can click this"
     disabled -> not-allowed  "you cannot click this, and here is why"

   Measured 2026-08-18, before this rule existed: the nine disabled buttons on
   /influencers showed THREE different cursors — default (1), pointer (5) and
   not-allowed (3) — and the disabled "Save Brand" button showed a hand, which
   tells the owner a dead control is clickable. `not-allowed` is the value the
   repo had already chosen in task 266 for the disabled Regenerate button.

   `[aria-disabled="true"]` is covered too: a control kept focusable for screen
   readers is still not clickable, and must not claim otherwise.            */
button {
  font-family: inherit;
  cursor: pointer;
  border: none;
  outline: none;
  background: none;
}
/* cursor lives in the convention block above; this rule owns the fade only */

/* Marks the measured-best model, and the recommended resolution, on a generation review card.
   Deliberately NOT a border: the selected state already draws one, and a second border reads as
   "already selected" (owner decision, task 226 Q2).
   Upright, not rotated — the 45deg version shipped in task 226 and the owner rejected it on sight:
   "in 45deg, it's ugly. Put it straight, but top right." (task 228 Q1). */

/* V3-116: the focus ring is the lime line (DESIGN.md §5), not the legacy violet. */

input {
  font-family: inherit;
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}

/*
 * One field surface for every route and theme. The priority is intentional:
 * several established forms use inline transparent fills, while onboarding
 * previously supplied its own important focus fill. Non-text controls retain
 * their native/semantic visuals. `data-field-surface="native"` is the explicit
 * escape hatch for a future control whose fill itself communicates state.
 */
/*
 * The in-field ✦ star (`ui.css` `.ui-improve-field`, `padding-right: 40px`) reserves a column so typed text never sits
 * under the star. The rule above is `!important` and far more specific, so that 40px never applied: every starred box
 * had 14px and its text ran under the star (measured 2026-10-03, Topic Studio Add picture: text right edge 854px, star
 * left edge 838px). A custom property is not part of that fight, so the reserve is given through one.
 */

/*
 * Magnifier in `.ui-search` — same pattern as the Improve star. Without a start reserve,
 * the placeholder starts under the glass (Eric 2026-10-06, Generations: looked like a double “S”).
 */

/*
 * FINDINGS row 2 (ENGINE 2026-09-22): the `padding-inline !important` above sets BOTH sides,
 * so it beat `.ui-select { padding-right: 36px }` in ui.css and every kit dropdown drew its
 * arrow on top of the selected text (measured: padding-right 14px, arrow at calc(100% - 18px)).
 * `.ui-select` is the ONLY selector in the kit with `appearance: none`, i.e. the only one that
 * draws its own arrow, so the restore is scoped to it — a native select keeps its own spacing.
 */

input:focus {
  border-color: var(--accent-1-line) !important;
  box-shadow: 0 0 0 4px var(--accent-1-soft, var(--accent-light));
}

a {
  text-decoration: none;
  color: inherit;
}

::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: rgba(0,0,0,0.15);
  border-radius: 3px;
}

/* view-transition overrides are injected dynamically in theme.jsx */

@keyframes theme-btn-press {
  0%   { transform: scale(1) rotate(0deg); }
  25%  { transform: scale(0.72) rotate(-20deg); }
  100% { transform: scale(1) rotate(0deg); }
}

@keyframes hf-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(236,72,153,0.0), 0 4px 24px rgba(139,92,246,0.25); }
  50%       { box-shadow: 0 0 0 6px rgba(236,72,153,0.12), 0 4px 24px rgba(139,92,246,0.40); }
}

@keyframes hf-float {
  0%, 100% { transform: translateY(0px); }
  50%       { transform: translateY(-3px); }
}

/* ── Responsive grids ── */


/* ── Orb animations (shared across Landing + Influencers empty state) ── */
@keyframes orb1 {
  0%, 100% { transform: translate(0,0) scale(1); }
  33%       { transform: translate(55px,-45px) scale(1.07); }
  66%       { transform: translate(-35px,38px) scale(0.93); }
}
@keyframes orb2 {
  0%, 100% { transform: translate(0,0) scale(1); }
  50%       { transform: translate(-45px,55px) scale(1.11); }
}
@keyframes orb3 {
  0%, 100% { transform: translate(0,0) scale(1); }
  40%       { transform: translate(35px,-55px) scale(0.90); }
  70%       { transform: translate(-55px,22px) scale(1.08); }
}

@keyframes progress-slide {
  from { background-position: 100% 0; }
  to   { background-position: -100% 0; }
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* ── Nav mobile ── */
@media (max-width: 640px) {
  :root { --nav-h: 96px; }
}




/*
 * THE site-wide UI layer — v3 "Studio" (Eric, 2026-09-08).
 *
 * Dark-first, near-black neutral greys, one electric yellow-green for every
 * action. Pink highlights, orange attention, green success. Rounded-rectangle
 * controls, lozenge badges. Sora / Manrope / IBM Plex Mono.
 *
 * Spec:  STUDIO-V3/PROJECT/DESIGN.md
 * Demo:  public/design.html  →  http://localhost:<LOCALHOST_PORT>/design.html
 * Prototype: claude.ai/code/artifact/171f72b3-92c1-47a7-ae6e-e06edee11997 ("Selling Kit")
 *
 * THE RULE: no page, no component, invents its own title, label, field, button
 * or card. If a variant is missing, add it HERE — then it changes everywhere at
 * once. Local `style={{…}}` is layout only (width, gap, order). A colour, a
 * radius, a font size or a border inside a page file is a bug.
 *
 * Sections: 0 tokens · 1 text · 2 buttons · 3 fields · 4 cards · 5 rows
 *           6 chrome (step rail) · 7 overlays · 8 page anatomy · 9 motion
 */

/* ── 0. Tokens ─────────────────────────────────────────────────────────────
   Greys read the app tokens in index.css (one palette, one place). The action
   colour is `--accent-1` — NOT the legacy `--accent` (violet), which only old,
   unconverted pages still use and which V3-116 retires. Dark is defined twice
   on purpose: for the un-stamped system theme and for the explicit stamp. */
:root {
  /* Spoken words (Eric 2026-10-18): a chat bubble that pops — dark on the light theme, light gray on the dark one. */
  --stage: #0B0A14; /* the always-dark ground of a header picture (.ui-flow-hero), both themes */
  --say-bg: #26252F;
  --say-ink: #F4F4F0;
  /* A Save INSIDE a box (Eric 2026-10-21: "lime color on white is barely visible"): the opposite of its box. A light
     field gets a dark button with light words; the speech bubble is dark here, so its Save stays lime. The field
     tokens change ONLY with data-theme="dark", the same as index.css `--field-surface`. */
  --field-save-bg: #15141C;
  --field-save-ink: #F4F4F0;
  --field-save-mark: var(--accent-1);
  --say-save-bg: var(--accent-1);
  --say-save-ink: var(--on-accent);
  --say-save-mark: var(--on-accent);
  /* Words that go to someone else — an email, a DM, a reply (Eric 2026-10-21): paper that pops against the page,
     dark on the light theme, light gray on the dark one. `.is-paper` reads these. */
  --paper-bg: #24232C;
  --paper-ink: #F2F2EE;
  --paper-muted: #B4B3BF;
  --paper-edge: #3B3A46;
  --paper-edge-hover: #5A5966;
  /* A Save inside the paper is its opposite (FieldSave, #1035): dark paper here, so lime — as the speech bubble. */
  --paper-save-bg: var(--accent-1);
  --paper-save-ink: var(--on-accent);
  --paper-save-mark: var(--on-accent);
  --ink: var(--text-primary);
  --muted: var(--text-secondary);
  --faint: var(--text-tertiary);
  --raised: var(--bg-tertiary);
  --sunken: #ECECE6;
  --border-2: #D2D2C9;
  --border-lit: #FFFFFF;

  /* Accent 1 · lime — every action. Fill is the same in both themes and always
     carries black text; the text/line variants keep it readable on light. */
  --accent-1: #D9FF3C;
  --on-accent: #111214;
  --accent-1-text: #4F6B00;
  --accent-1-line: #86B300;
  /* The "you picked this" hairline: the lime line at 80%, so a dashed 1px stays delicate (Eric, 2026-09-09). */
  --pick-line: color-mix(in srgb, var(--accent-1-line) 80%, transparent);
  /* Picked MEDIA — 3px solid border + 2px soft outline at 50% lime (Eric 2026-09-23).
     Soft uses outline (not box-shadow) so overflow:hidden can clip the picture to the
     same radius without eating the outer ring. Chips / segs keep `--pick-line`. */
  --pick-media-soft: color-mix(in srgb, var(--accent-1) 50%, transparent);
  --accent-1-soft: rgba(160, 205, 20, 0.2);
  --accent-glow: rgba(217, 255, 60, 0.28);
  /* Accent 2 · pink — highlights, promos, the default-card edge. Never a button. */
  --accent-2: #F0357B;
  --accent-2-soft: rgba(240, 53, 123, 0.14);
  /* Craft wait diagonal sweep — diffused white at the old pink opacity (Eric 2026-09-23).
     One token: GenWait + CraftWait both use `.ui-craft-shimmer`. */
  --craft-sweep: rgba(255, 255, 255, 0.13);
  /* Accent 3 · orange — attention: needs permission, saving, due. */
  --accent-3: #E8641F;
  --accent-3-soft: rgba(232, 100, 31, 0.14);
  /* Just landed — blue, so it can only mean "look here, this just changed" (orange = working). */
  --landed-1: #0EA5E9;
  --landed-2: #2563EB;
  --warn: var(--accent-3);
  --warn-soft: var(--accent-3-soft);
  /* Semantic */
  --good: #1F9D5A;
  --good-soft: rgba(31, 157, 90, 0.14);
  --bad: #D6454B;
  --bad-soft: rgba(214, 69, 75, 0.12);

  --chip: #E6E6DF;
  --glass: rgba(20, 20, 10, 0.04);
  --glass-line: rgba(20, 20, 10, 0.08);
  --field-bg: #FFFFFF;
  /* Tones: the light side is never flat white — cards carry a soft tint of one accent. */
  --tone-lime: #F3F8DA;
  --tone-lime-line: #DCE6B4;
  --tone-pink: #FBE9F0;
  --tone-pink-line: #F1CBDA;
  --tone-orange: #FCEEE1;
  --tone-orange-line: #F3D3B8;
  --tone-green: #E6F5EA;
  --tone-green-line: #C3E4CD;
  /* THE TEN STEPS · Eric's ten colors (docs/UGC-NEW-STEPS/ugc-steps.html, 2026-10-11), the same in both themes: every
     surface that belongs to a step reuses these and nothing else — never a hex outside this list. `.ui-step-N` maps one to `--step`. */
  --step-1: #D94B55; --step-1-soft: rgba(217, 75, 85, 0.12); --step-1-line: color-mix(in srgb, #D94B55 45%, transparent); /* red */
  --step-2: #DD7C32; --step-2-soft: rgba(221, 124, 50, 0.12); --step-2-line: color-mix(in srgb, #DD7C32 45%, transparent); /* orange */
  --step-3: #D5A028; --step-3-soft: rgba(213, 160, 40, 0.12); --step-3-line: color-mix(in srgb, #D5A028 45%, transparent); /* gold */
  --step-4: #B9B52C; --step-4-soft: rgba(185, 181, 44, 0.12); --step-4-line: color-mix(in srgb, #B9B52C 45%, transparent); /* olive */
  --step-5: #72A83E; --step-5-soft: rgba(114, 168, 62, 0.12); --step-5-line: color-mix(in srgb, #72A83E 45%, transparent); /* green */
  --step-6: #289C64; --step-6-soft: rgba(40, 156, 100, 0.12); --step-6-line: color-mix(in srgb, #289C64 45%, transparent); /* emerald */
  --step-7: #189B91; --step-7-soft: rgba(24, 155, 145, 0.12); --step-7-line: color-mix(in srgb, #189B91 45%, transparent); /* teal */
  --step-8: #228FB9; --step-8-soft: rgba(34, 143, 185, 0.12); --step-8-line: color-mix(in srgb, #228FB9 45%, transparent); /* sky */
  --step-9: #416FC8; --step-9-soft: rgba(65, 111, 200, 0.12); --step-9-line: color-mix(in srgb, #416FC8 45%, transparent); /* blue */
  --step-10: #8159C4; --step-10-soft: rgba(129, 89, 196, 0.12); --step-10-line: color-mix(in srgb, #8159C4 45%, transparent); /* violet */
  --step-glow-a: 22%; --step-glow-b: 6%; --step-paper: #FFFFFF;
  --scrim: rgba(12, 12, 10, 0.5);
  --inv: #121315;
  --inv-ink: #F4F4F0;
  --shadow-1: 0 1px 2px rgba(20, 20, 10, 0.05), 0 6px 18px rgba(20, 20, 10, 0.07);
  --shadow-2: 0 18px 50px rgba(20, 20, 10, 0.2);

  --font-head: "Sora", "Manrope", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Manrope", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, Menlo, monospace;

  /* Shapes: rounded rectangles for controls, lozenges for badges. */
  --r-btn: 12px;
  --r-field: 12px;
  --r-chip: 10px;
  --r-tag: 8px;
  --r-lozenge: 6px;
  --r-card: 16px;
  --r-panel: 20px;
  --r-badge: 12px;
  --r-pill: 999px;
  --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-5: 20px; --s-6: 24px; --s-7: 32px; --s-8: 48px;
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);

  /* v1/v2 names kept as aliases so nothing breaks while pages convert. */
  --accent-soft: var(--accent-1-soft);
  --r-btn-pill: var(--r-pill);
  --ui-head: var(--font-head);
  --ui-sans: var(--font-body);
  --ui-mono: var(--font-mono);
  --ui-radius-card: var(--r-card);
  --ui-radius-field: var(--r-field);
  --ui-accent: var(--accent-1-text);
  --ui-accent-2: var(--accent-2);
  --ui-accent-soft: var(--accent-1-soft);
  --ui-good: var(--good);
  --ui-good-soft: var(--good-soft);
  --ui-warn: var(--warn);
  --ui-warn-soft: var(--warn-soft);
  --ui-bad: var(--bad);
  --ui-raised: var(--raised);
  --ui-border2: var(--border-2);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --say-bg: #E4E4EA;
    --say-ink: #15141C;
    --paper-bg: #ECECEF;
    --paper-ink: #1D1D22;
    --paper-muted: #55555E;
    --paper-edge: #CFCFD6;
    --paper-edge-hover: #A3A3AD;
    --paper-save-bg: #15141C;
    --paper-save-ink: #F4F4F0;
    --paper-save-mark: var(--accent-1);
    --sunken: #07060D;
    --border-2: rgba(255, 255, 255, 0.16);
    --border-lit: rgba(255, 255, 255, 0.24);
    --accent-1-text: #D9FF3C;
    --accent-1-line: #D9FF3C;
    --accent-1-soft: rgba(217, 255, 60, 0.13);
    --accent-glow: rgba(217, 255, 60, 0.22);
    --accent-2: #FF4D8D;
    --accent-2-soft: rgba(255, 77, 141, 0.16);
    --accent-3: #FF8A3D;
    --accent-3-soft: rgba(255, 138, 61, 0.16);
    --landed-1: #38BDF8;
    --landed-2: #60A5FA;
    --good: #3DDC84;
    --good-soft: rgba(61, 220, 132, 0.14);
    --bad: #FF5C5C;
    --bad-soft: rgba(255, 92, 92, 0.14);
    --chip: #272433;
    --glass: rgba(255, 255, 255, 0.05);
    --glass-line: rgba(255, 255, 255, 0.09);
    --field-bg: #1A1826;
    /* A Save inside a box, system dark: the speech bubble is light here → the dark button. A normal field stays white
       until the app stamps data-theme="dark" (index.css `--field-surface`), so its Save stays dark (Codex #1035). */
    --say-save-bg: #15141C;
    --say-save-ink: #F4F4F0;
    --say-save-mark: var(--accent-1);
    --tone-lime: #191D14;
    --tone-lime-line: #2C341C;
    --tone-pink: #21141F;
    --tone-pink-line: #3B2033;
    --tone-orange: #211716;
    --tone-orange-line: #3B2A22;
    --tone-green: #121D1A;
    --tone-green-line: #1C342B;
    /* THE TEN STEPS · Eric's ten colors (docs/UGC-NEW-STEPS/ugc-steps.html, 2026-10-11), the same in both themes: every
       surface that belongs to a step reuses these and nothing else — never a hex outside this list. `.ui-step-N` maps one to `--step`. */
    --step-1: #D94B55; --step-1-soft: rgba(217, 75, 85, 0.16); --step-1-line: color-mix(in srgb, #D94B55 45%, transparent); /* red */
    --step-2: #DD7C32; --step-2-soft: rgba(221, 124, 50, 0.16); --step-2-line: color-mix(in srgb, #DD7C32 45%, transparent); /* orange */
    --step-3: #D5A028; --step-3-soft: rgba(213, 160, 40, 0.16); --step-3-line: color-mix(in srgb, #D5A028 45%, transparent); /* gold */
    --step-4: #B9B52C; --step-4-soft: rgba(185, 181, 44, 0.16); --step-4-line: color-mix(in srgb, #B9B52C 45%, transparent); /* olive */
    --step-5: #72A83E; --step-5-soft: rgba(114, 168, 62, 0.16); --step-5-line: color-mix(in srgb, #72A83E 45%, transparent); /* green */
    --step-6: #289C64; --step-6-soft: rgba(40, 156, 100, 0.16); --step-6-line: color-mix(in srgb, #289C64 45%, transparent); /* emerald */
    --step-7: #189B91; --step-7-soft: rgba(24, 155, 145, 0.16); --step-7-line: color-mix(in srgb, #189B91 45%, transparent); /* teal */
    --step-8: #228FB9; --step-8-soft: rgba(34, 143, 185, 0.16); --step-8-line: color-mix(in srgb, #228FB9 45%, transparent); /* sky */
    --step-9: #416FC8; --step-9-soft: rgba(65, 111, 200, 0.16); --step-9-line: color-mix(in srgb, #416FC8 45%, transparent); /* blue */
    --step-10: #8159C4; --step-10-soft: rgba(129, 89, 196, 0.16); --step-10-line: color-mix(in srgb, #8159C4 45%, transparent); /* violet */
    --step-glow-a: 34%; --step-glow-b: 10%; --step-paper: #FBF8FF;
    --scrim: rgba(0, 0, 0, 0.65);
    --inv: #F4F4F0;
    --inv-ink: #0E0F11;
    --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.35);
    --shadow-2: 0 24px 70px rgba(0, 0, 0, 0.65);
  }
}

:root[data-theme="dark"] {
  --say-bg: #E4E4EA;
  --say-ink: #15141C;
  --paper-bg: #ECECEF;
  --paper-ink: #1D1D22;
  --paper-muted: #55555E;
  --paper-edge: #CFCFD6;
  --paper-edge-hover: #A3A3AD;
  --paper-save-bg: #15141C;
  --paper-save-ink: #F4F4F0;
  --paper-save-mark: var(--accent-1);
  --sunken: #07060D;
  --border-2: rgba(255, 255, 255, 0.16);
  --border-lit: rgba(255, 255, 255, 0.24);
  --accent-1-text: #D9FF3C;
  --accent-1-line: #D9FF3C;
  --accent-1-soft: rgba(217, 255, 60, 0.13);
  --accent-glow: rgba(217, 255, 60, 0.22);
  --accent-2: #FF4D8D;
  --accent-2-soft: rgba(255, 77, 141, 0.16);
  --accent-3: #FF8A3D;
  --accent-3-soft: rgba(255, 138, 61, 0.16);
  --landed-1: #38BDF8;
  --landed-2: #60A5FA;
  --good: #3DDC84;
  --good-soft: rgba(61, 220, 132, 0.14);
  --bad: #FF5C5C;
  --bad-soft: rgba(255, 92, 92, 0.14);
  --chip: #272433;
  --glass: rgba(255, 255, 255, 0.05);
  --glass-line: rgba(255, 255, 255, 0.09);
  --field-bg: #1A1826;
  /* A Save inside a box, dark theme: a dark field (index.css `--field-surface: #1A1826`) keeps the lime button; the
     light speech bubble gets the dark one. */
  --field-save-bg: var(--accent-1);
  --field-save-ink: var(--on-accent);
  --field-save-mark: var(--on-accent);
  --say-save-bg: #15141C;
  --say-save-ink: #F4F4F0;
  --say-save-mark: var(--accent-1);
  --tone-lime: #191D14;
  --tone-lime-line: #2C341C;
  --tone-pink: #21141F;
  --tone-pink-line: #3B2033;
  --tone-orange: #211716;
  --tone-orange-line: #3B2A22;
  --tone-green: #121D1A;
  --tone-green-line: #1C342B;
  /* THE TEN STEPS · Eric's ten colors (docs/UGC-NEW-STEPS/ugc-steps.html, 2026-10-11), the same in both themes: every
     surface that belongs to a step reuses these and nothing else — never a hex outside this list. `.ui-step-N` maps one to `--step`. */
  --step-1: #D94B55; --step-1-soft: rgba(217, 75, 85, 0.16); --step-1-line: color-mix(in srgb, #D94B55 45%, transparent); /* red */
  --step-2: #DD7C32; --step-2-soft: rgba(221, 124, 50, 0.16); --step-2-line: color-mix(in srgb, #DD7C32 45%, transparent); /* orange */
  --step-3: #D5A028; --step-3-soft: rgba(213, 160, 40, 0.16); --step-3-line: color-mix(in srgb, #D5A028 45%, transparent); /* gold */
  --step-4: #B9B52C; --step-4-soft: rgba(185, 181, 44, 0.16); --step-4-line: color-mix(in srgb, #B9B52C 45%, transparent); /* olive */
  --step-5: #72A83E; --step-5-soft: rgba(114, 168, 62, 0.16); --step-5-line: color-mix(in srgb, #72A83E 45%, transparent); /* green */
  --step-6: #289C64; --step-6-soft: rgba(40, 156, 100, 0.16); --step-6-line: color-mix(in srgb, #289C64 45%, transparent); /* emerald */
  --step-7: #189B91; --step-7-soft: rgba(24, 155, 145, 0.16); --step-7-line: color-mix(in srgb, #189B91 45%, transparent); /* teal */
  --step-8: #228FB9; --step-8-soft: rgba(34, 143, 185, 0.16); --step-8-line: color-mix(in srgb, #228FB9 45%, transparent); /* sky */
  --step-9: #416FC8; --step-9-soft: rgba(65, 111, 200, 0.16); --step-9-line: color-mix(in srgb, #416FC8 45%, transparent); /* blue */
  --step-10: #8159C4; --step-10-soft: rgba(129, 89, 196, 0.16); --step-10-line: color-mix(in srgb, #8159C4 45%, transparent); /* violet */
  --step-glow-a: 34%; --step-glow-b: 10%; --step-paper: #FBF8FF;
  --scrim: rgba(0, 0, 0, 0.65);
  --inv: #F4F4F0;
  --inv-ink: #0E0F11;
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.35);
  --shadow-2: 0 24px 70px rgba(0, 0, 0, 0.65);
}

/* ── 1. Text roles — seven sizes, no eighth ────────────────────────────── */
/* A title with its small lime icon beside it: every section head carries one. */
/* On a control, the ≈ $ matches the label — never a muted second voice (Eric 2026-09-26). */
/* A link is not an action. Lime belongs on `.ui-primary` only (Eric, 2026-09-19).
   The colour is the page's own ink: white in the dark theme, near-black on light. */
/* Soft blue “add under a field” cue — pops past grey hint copy without stealing lime (Eric 2026-10-03). */
/* Boxed quick-add under a field — everything inside is one job (Eric 2026-10-03). */
/* Visually hidden, still read and still focusable — the radio behind a styled control. */

/* ── 2. Buttons — one family, four voices, rounded rectangles ─────────────
   Order: primary → secondary → tertiary → danger. One primary per screen.
   `ui-primary` alone is enough; `ui-btn` is the shared base for new voices. */
.ui-primary,
.ui-secondary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 38px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.2;
  border-radius: var(--r-btn);
  border: 1px solid transparent;
  padding: 9px 16px;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.15s var(--ease), box-shadow 0.15s, filter 0.15s;
}

.ui-primary {
  background: var(--accent-1);
  color: var(--on-accent);
  font-weight: 700;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), 0 6px 22px var(--accent-glow);
}

.ui-primary:hover { filter: brightness(1.05); transform: translateY(-1px); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), 0 10px 28px var(--accent-glow); }
.ui-secondary { background: var(--raised); border-color: var(--border-2); color: var(--ink); }
.ui-secondary:hover { background: var(--chip); }
/* Lime secondary — lime edge/fill cue, label stays ink (white on dark). Never lime text in a button (Eric 2026-10-03). */
/* Orange-yellow secondary — Copy on My prompt. Never lime (one `.ui-primary`). */
/* An icon button CENTRES ITS OWN CONTENT, on every element, with or without a base button class.
   Eric, 2026-09-22, about a "⋯" sitting in the top-left of its box: "every button text should
   have padding equal top, bottom, left, and right … This should be a CSS constant normal
   behavior." It was not: this class set only a size, and the centring lived in the base list
   above (`.ui-primary, .ui-secondary, …`). A `<summary class="ui-btn-icon">` — the kit's own
   `.ui-menu` trigger — or any bare `<button class="ui-btn-icon">` got none of it.
   `lib/uiKitButtons.test.mjs` holds this rule to account. */
/* "Make my words better" — pink sparkle. Eric 2026-09-11: under the field at its left.
   Eric 2026-10-01: NEW standard — star **inside** the field, top far-right
   (`.ui-improve-field` + `.ui-improve-field-btn`); padding keeps text off the button.
   `.ui-improve-row` still holds Undo · notice under the field. */
/* In-field Improve (Eric 2026-10-01) — one composition for input + textarea. */
/* Solid wash behind the star so tall glyphs do not show through. */
/* Character cap inside the box, bottom far-right (Eric 2026-10-05). Star stays top-right. */
/* ✓ Save INSIDE a box, bottom far-right (`FieldSave` in primitives.jsx; Eric 2026-10-21). Its colours are the opposite
   of the box: dark with light words on a light box, lime on a dark box (`--field-save-*`; the speech bubble flips the
   other way, `--say-save-*`). Every Save that sits inside a box uses it — never a lime `.ui-primary` there. */

/* ── V3-161 · the tooltip ────────────────────────────────────────────────────
   Eric, 2026-09-11: site-wide instant tip via shell/tooltip.js. One fixed node on body. */
/* For an anchor near the RIGHT edge: grow leftwards instead. */
/* Tap-to-open on phones (Eric 2026-09-23 — Choose ≈$ “why pay again”). */
.ui-primary:focus-visible,
.ui-secondary:focus-visible { outline: 2px solid var(--accent-1-line); outline-offset: 2px; }

/* ── 3. Fields — one label style, sized to content ────────────────────────
   A field is as wide as what goes in it: `ui-field-sm` (320) for a link or a
   number, `ui-field-md` (520) for a sentence, full width only for a text area. */
/* A field whose text OVERRIDES the chips above it says so with a dashed lime edge — the
   same "you picked this" line `.ui-chip[aria-pressed]` uses (Photo studio: type any
   location and the twelve presets stop applying). */
/* Words that go to someone else read as the paper they land on (Eric 2026-10-21, Brand Hunter then Trend Radar:
   "every time we have text that we're going to copy and give to a user or someone (a company) … a light background
   … on the light theme, we do the opposite"): light gray on the dark theme, dark on the light one (`--paper-*`).
   On a field, or on a read-only note (`.ui-note.is-paper`). Not speech: that is `.ui-say`. */
/* The fill goes through `--field-surface`: index.css paints every field with it `!important` (one field surface). */
/* The ✦ star and the count sit on the paper: their wash is the paper too, never a dark square on it, and their ink and
   edge are the paper's (the theme's own `--muted` / `--border-2` vanish on it). */
/* Auto-expand with the text (Eric 2026-09-26). CSS `field-sizing` where supported;
   `Textarea` in shell/primitives.jsx does the scrollHeight fallback. Opt out with
   `.ui-textarea-fixed` (manual resize + scroll). Cap so a modal cannot runaway. */
/* A label with its control under it. Three pages were writing `display: grid` inline on
   `.ui-field` because the kit only ever defined its two widths (DESIGN 2026-09-10). */
/* The affix input carries data-field-surface="native" so index.css leaves its padding alone. */

/* Chips = a choice (one or many). Tags = words the user typed, removable.
   Pills = a state you read. Badges = an icon holder. Never swap them. */

/* A chip inside a small picture card. The outfit picture cards are ~180px wide
   and carry one chip per clothing piece the scan found, so the full-size chip
   wrapped to one per line. (Eric 2026-09-11: the picture cards must read like
   the product cards — four or five per row on a PC.) */

/* A segment takes buttons OR links. A tab that changes what you see is a button; a tab
   that changes the page you are on is a link, and must be one — the admin rail is real
   navigation, so it has to be middle-clickable and readable by a screen reader as links.
   Both look identical, which is the point (Eric 2026-09-09: same look, admin and user). */
/* Option switcher / exact-one-of: hug the buttons (left cluster). A grid parent (.ui-fields)
   would otherwise stretch the track full-bleed while the labels stay tiny on the left —
   Eric 2026-10-03 forever rule. `.is-full` still fills a narrow slot when needed. */
/* A row of tool chips (view Original · Clean 1 · Pores, then the action). Was `.ui-step-rail`: a toolbar, never a step
   rail — renamed 2026-10-18 so the one step look (`MicroTabs`) owns every "step" name. */

/* Breadcrumb — always at the top of a subsection so people can step back (Eric 2026-10-06). */
/* Where you are in a choice (Eric, 2026-09-09: "a fine dashed border on the
   selected pill, and ten percent of the green"): a dashed lime hairline and a
   10% lime tint. The line is 1px and 80% lime (`--pick-line`) — delicate, not a
   frame. State chips (`.is-on`) stay solid — this is only for a choice. */

/* A yes/no. The knob is the state; the lime track means on. */

/* A setting that opens a picker: small label, the value, a chevron. */

/* A number with − and +: a count you nudge, never type. */
/* The inline tag input carries data-field-surface="native" so index.css leaves it alone. */

/* ── 4. Cards — one card, variants are modifiers ──────────────────────────
   Feature cards get the lit hairline, the corner glow and a lift: spend them on
   the objects a page is about, never on every block. */

/* Tones — a card takes one soft tint; its badge and eyebrow take the same hue.
   Use them on rails, notes and side cards so a page is never one flat colour. */
/* A badge, then the words: the words sit beside the badge and take the room. With two children,
   space-between threw a short title to the far right (Social Autopilot account cards, 2026-10-18). */
/* A card is a column, and a column stretches its children: a lone pill or badge in a card
   became a full-width bar on AI models, Categories and Languages (session 05). */
/* In a disclosure row on a phone the name and the state matter; the mono id waits inside. */
/* Everything in a foot or an action row sits on one centre line, 32px tall — a word beside a button is centred on the button (Eric, 2026-09-09). */
/* The destructive act of a card sits alone on the right of its foot, away from Open (DESIGN step 5, 2026-09-09). */
/* A media strip inside a card keeps the card's inner corners. */

/* Eric 2026-09-11: two ways to do ONE thing are ONE slot, stacked — "put them one on top of
   the other… there's too much separation between each one." `.is-ways` turns the add slot into
   a container of `.ui-add-way` rows: the slot keeps the dashed frame and the hover belongs to
   each row, so the box never lights up as a whole for a click that lands on one half of it. */
/* Captioned two-way add (Twin Photos empty tiles — Eric 2026-09-26).
   Name + hint stay INSIDE the dashed frame. Add and Paste are equal centred
   rows. Never aspect-ratio this card: a 1:1 hole is shorter than caption + two
   ways, so align-content:center spilled the title out the top and parked Paste
   on the bottom curve. The box sizes to its stack wherever it drops. */
/* Twin Generate wait lives inside the dashed rounded add tile (Eric 2026-10-01).
   No absolute sharp square over the dots — GenWait / craft tile inherits the panel radius. */
/* A badge that carries a step's number instead of an icon (Photo studio's eight questions):
   the kit's mono, tabular, so 1 and 8 sit on the same width. */
/* The shape of a picture, drawn beside its name in a chip: the frame IS the ratio, so
   9:16 and 16:9 are told apart before the words are read (Photo studio, step 8). */

/* ── Know-page parts (V3-116 step 2) — a page about one thing ──────────────
   Its mark beside the title, its state pills on the right, a meta row with
   lime icons, and the doors in as chips. Then the accordion, the bullet list,
   the hairline stack and the thumb card for what we read about them. */ /* the lead grows; a button never stretches to fill a column (Eric 2026-09-09, "Download all is way too big") */

/* A chip may be a link (a door in): same look. `is-off` = a door we do not have. */

/* Accordion: hairline rows inside a card; the chevron turns when open. */
/* Closed panels may carry `hidden` (React) instead of unmounting — hide them in the kit. */

/* `.is-tiles` — a MODIFIER of the same accordion, never a second `.ui-acc` (session 05 rule).
   The hairline rows become one soft box per row with a gap between them, for a checklist where
   every row is one fact rather than a chapter. Eric, 2026-09-16: *"maybe like a kind of a small
   background for each accordions... In that case, we don't need two columns."*
   The head then reads KEY, colon, VALUE, with the verdict mark alone on the right in the
   `.ui-acc-sum` slot the kit already reserves there. A row that failed tints its own box, so the
   misses are findable down the column without reading a word. */
/* The pair the head carries: the key is the bold half, the value the quiet one. */
/* Inside an open tile: the finding in bold, then what was asked, indented under it. There is
   NO second disclosure in here — Eric, 2026-09-16: one click shows everything the line knows. */

/* V3-204 — a picture that keeps its OWN ratio, so it never sits in a band of empty box.
   Eric, 2026-09-16: *"remove the gap top and bottom… make it fitting maximum the height of
   nine sixteen. We should not have a gap like that."*
   `.ui-fitbox` and `.ui-thumb-media.is-contain` both letterbox on purpose — they fix the BOX
   and let the picture float inside it, which is right for a slot whose size must not move.
   A table row is not that slot: the seed renders 3:4 while the box was 9:16-ish, so every row
   carried a black band above and below. Here the picture sets the height and `max-height` is
   the 9:16 ceiling, so a taller picture is capped instead of stretching the row.
   As a button it is the door to the ONE viewer — never a second lightbox. */

/* ── Photo studio shell (DESIGN 2026-09-10) — page root, two columns, receipt,
   step foot, mode bar. Layout only; pages compose ui-* inside. ───────────── */
/* One screen (Eric 2026-09-11): the seven closed rows ARE the list — no second list, no rail, no
   modes. A row's value turns orange when it blocks Generate. On a phone the aside goes first as one
   strip: the two pictures left, Surprise me + Generate right, the rows under. */
/* `.is-mini`: the same two pictures at half the width, side by side, never stacked — a tap opens
   each whole in the viewer. The medal, the captions and the tools shrink with them. */

/* A bullet list with lime markers; a hairline stack; a thumb card. */
/* A picture that always goes (FINDINGS 133): a lock + its reason, as tall as the Send tick row so every card lines up. */
/* Video Studio Picture step (FINDINGS 133): the start photo on the left, the two picture groups on the right. */
/* Step flows (FINDINGS 133, Eric 2026-10-16): the Back / Next bar sits at the bottom of the screen on every step, so
   the mouse never moves. The flow is at least one screen tall, so a short step still puts the bar at the bottom. */
/* `MicroNav` floats by default (src/components/MicroSteps.jsx — the one owner). Outside a step card it is a bar of its
   own; inside `.ui-stepflow` (the `MicroFlow` card) it is the card's bottom edge, as on the Videos page. */
/* Its top twin: the step rail spans the card edge to edge too, so nothing scrolling under it peeks out at its sides. */
/* PINNED (Eric 2026-10-18: "the Back and Next buttons are stuck at the bottom of the screen always", site-wide). Once
   mounted, `MicroNav` draws the bar in <body> at the screen bottom, lined up with its card (left + width set inline);
   an empty spot of the same size stays in the card. Sticky could never pass the card's own bottom, so at the end of a
   page the bar stopped ~80 px up — under the lifted toasts. It keeps the card-edge look (Eric 2026-10-18: "NOT a
   separate rounded floating box"): the card's side borders, a top line, the card's bottom corners. Layer 440: over
   the page, under the modals (500). */
/* When something comes after the step card (a History row), the box that scrolls keeps the bar's height free at its
   end (MicroNav marks it): that row scrolls above the bar, never under it. The window: <body> padding. */
/* A page whose step card is last ends at that card: the pinned bar covers its spot, so no gap shows between the card
   and the bar (the page's own 90 px of bottom room was wider than the bar). */
/* "Next opens the next step at its top" (`useStepTop`): the step's top lands under the sticky app bar. */
/* A thumb that IS the act: clicking it picks that thing, so it is a button, not a card
   with a button in it (LAW § the collection — picking is the act). */
/* A model card's glyph (Eric 2026-10-16, FINDINGS 137): one film icon on a soft tile, one colour per maker. */
/* `.ui-thumb-body` is defined ONCE, under Detail parts (a second, older rule here was fully overridden — session 06). */

/* ── Pick-list parts (V3-116 step 3 = V3-097) — a shortlist builder ─────────
   Tools row (search, filter chips, city, select-all, sort by fit), compact
   56px rows (mark · name · rating · doors · fit · know · keep / skip / more),
   a details/summary menu, and the bulk bar that appears when rows are checked. */
.ui-check { width: 16px; height: 16px; margin: 0; flex: none; accent-color: var(--accent-1); cursor: pointer; }
/* Force the next tools onto a new flex line (Generations: search wide on row 1, influencer before media on row 2). */
/* A small icon button for a line of text (the eye beside a status). */

/* ── The nav (V3-116 step 4) ────────────────────────────────────────────────
   One bar for every page: glass over the ground, a hairline under it, the mark
   in lime, the links as quiet pills that go solid with a lime underline when
   you are there. On the landing page the bar sits on the hero, so it swaps its
   own tokens to the light-on-dark set — nothing else in here knows.

   Stack (Eric 2026-10-01): the bar — and every menu that drops out of it — sits
   ABOVE `.ui-modal-wrap` (500). The modal law still starts the sheet below the
   bar (`inset: var(--nav-h)`); without this the Library / Create menus painted
   under the scrim the moment they hung past the bar's bottom edge. Toasts stay
   at 1000 so a process card can still cover the page. */

/* A dropdown under a nav control: the menu panel, its rows, its head and rule. */
/* The peek (Eric, 2026-09-12: "put an eye, and when we click on the eye, we can have a
   tooltip with the information in it, but also copyable"). A tooltip cannot be copied
   — it takes no pointer and dies with the hover — so this is its own part: a click
   opens it, the text can be selected, and one small Copy sits in its head. Same
   <details> shape as .ui-menu, so it needs no script to open and close. */
/* A status line with an eye beside it: the words, then the eye, 4px apart (Eric, 2026-09-12:
   "too tight to the Re-scan word"). The eye is a SIBLING of the <p>, never inside it — a
   thumb's <p> clips its overflow, so a panel opened inside it is invisible (measured). */
/* Inside a thumb the panel starts at the eye's own line and grows UPWARD, as tall as the words
   need — never cut, never scrolled (Eric, 2026-09-12: "starting from the eye, going up, and if
   it's long we want to read all the text completely"). The thumb clips its overflow for its
   rounded corners, so while a peek is open that one thumb stops clipping and rises above its
   neighbours. And a thumb's <p> is clamped to two lines — the peek's text is not a caption. */
/* On a phone a popover is the wrong part: every peek becomes a sheet at the bottom (rule 17). */
/* Long copy (Prompt Vision description — Eric 2026-09-23): width up to 560px (never
   wider than the screen), height hugs the words with normal padding, centred on the
   screen; only scrolls when the copy is taller than the window. */

@media (max-width: 640px) {
  /* Five groups on a 390 screen: the Steps button ran 24px past the edge (measured 2026-10-11). Tighter, and never clipped. */
  /* Previews made it six groups for a signed-in user (Eric 2026-10-18): the menu arrows go on a phone (the open
     menu shows the state), and a menu opens full width under the bar instead of running off the right edge
     (measured: Previews' menu ended at 465px on a 390px screen). */
}
/* Six groups on a 360px phone (signed in: Home first): 30px too wide at 6px a side. 3px a side fits (measured 2026-10-18). */
/* 641–859px: one row, but the brand words ran under Home (800px: words ended at 193px, Home began at
   155px; 641px: the avatar sat 6px past the edge — session 10 drive, 2026-10-13). Keep the mark, drop
   the words, tighten the links. From 860px the words fit again. */

/* The sign-in wall: one feature card, centred under the nav. */

/* The bulk bar: inverse, fixed at the bottom, persistent while rows are checked. */

/* Pills are lozenges: a state you read, never something you click. */
/* A pill that is a link (Eric 2026-10-21: an influencer's handle as an orange badge that opens it in a new tab). */
/* FINDINGS 129 (Eric 2026-10-16): a problem the person must see now — solid red, white text. */
/* On a photo tile (Clean refs are often white): dark chip + light ink in BOTH themes — never theme `--inv` (Eric 2026-09-26). */
/* Bigger pill for a stats row read at a glance (Eric 2026-10-17, Admin → Interested users). Same colours, larger type. */
/* Numbered pick on a photo stack — circle + Select button (Eric 2026-10-08). */
/* Select = same height as the circle; 95% solid blue + white (finger/mouse target). */
/* `.ui-note` is defined ONCE, under Detail parts; the writer block is `pre.ui-note` there (session 06 found this rule doubled). */

/* ── 5. Rows — the settings table and the list row ───────────────────────
   `.ui-card.ui-form` holds `.ui-row`s: question left (250px), answer right,
   a hairline between rows. This replaces every stacked form on the site. */
/* The label sits 10px down to meet a 42px field's centre line; a short control (a pill,
   a switch, a seg) is centred in that same 42px, so label and control share one line
   (Eric, 2026-09-09). A tall control grows down from there. */
/* A control is as wide as itself (a switch, a seg, a pill); a group of them fills the row. */
/* A list row that is a button (a job in a batch): the same row, a hand, a lit hover. */
/* `.ui-grid-2` is two columns and `.ui-grid-3` is three — the name is the count.
   Three becomes two under 900px; both become one under 640px. */

/* ── 6. Chrome — the step rail (StepRail.jsx keeps its class names) ──────── */
/* A step rail sticks as a second header row, flush under the bar above it (Eric 2026-10-18: "it goes right below the
   header … rather than overlapping the text"). The window scrolls on most pages, so the default stop is under the
   app bar. A pane that scrolls on its own (`.ui-scroll-pane`, the influencer pages) stops it at the pane's top edge:
   sticky counts from inside the pane's padding, so the stop is minus that padding (`--pane-pad-top`). */

/* Tabs line up at the top, so every name sits on one straight line; a note hangs under its own name (Eric 2026-10-19:
   a tab with a note under it, centred, rose above the others and "crooks the line"). */
/* THE ONE STEP STRIP (`MicroTabs`, Eric 2026-10-18: the Videos look, site-wide). The states it adds to the rail: a
   task with a missing field or an old result (orange `!`), a done task's answer in two or three words, and a strip
   that does not stick (the tasks inside a card, under the page's own rail — one sticky row, never two). */
/* The note sits on its own line under the name (Eric 2026-10-18: one row was cramped and cut it with an ellipsis), on
   ONE line (Eric 2026-10-21): the chip grows to the note's own width, never to a fixed one (2026-10-20: a 30ch
   max-width made a short name 30ch wide). Only a note wider than the whole screen ends in "…" (`max-width: 100%`). */
/* Ad Studio's six numbers, one even row from 860px up (Eric 2026-10-20: the same space between each number, and
   the last number was falling onto its own line). The name under a step hangs in the rail's padding so it cannot
   widen the chip or push the label onto a second line. */
/* A rail with no numbers (`numbered={false}`) draws no empty box: the name alone, a box only for ✓ or `!`. */
/* A chip with a number and no name (a lesson's screens: 1 · 2 · 3 · 4, the title on hover) is a square, even padding. */

/* Under 900px: Business bottom tab bar only (V3-095) — the prospects rail alone (`.is-tabbar`). Every other rail
   (Topic Studio's, now drawn by MicroTabs inside the same `.business-shell`) stays a top row: as a bottom bar it would
   sit on the pinned Back / Next bar (Codex plan review, 2026-10-18). Never apply to `.ui-studio`. */

/* Photo studio in-page rail stays in document flow on every width. */

/* ── 6b. The steps — ONE LOOK, site-wide (Eric 2026-10-18): the `.step-rail` chips, drawn by `MicroTabs` alone
   (MicroSteps.jsx; DESIGN.md § 7.6, design.html §9c). The old `.ui-steps` line and `.is-row` chips are gone. */

/* ── 7. Overlays — drawer, scrim, toast ──────────────────────────────────
   Editing happens in the drawer so the page stays a page. */
/* A drawer is a dialog: its scrim and panel sit ABOVE the page's floating bars (pinned Back/Next 440, the next bar
   440, the bulk bar 450, a page peek 460) and BELOW a modal (500) — FINDINGS 201: the pinned Next bar covered the
   drawer's footer buttons on every page with a drawer. */

/* The confirm modal (V3-116): one shell for every "are you sure / this costs $"
   moment. Eyebrow (lime; red when destructive) + title + one line, the body,
   then Cancel (tertiary) and the one primary. `.ui-total` is the money line. */
/* THE MODAL LAW — Eric, 2026-09-14: *"That should be a primitive convention for every modal. All
   the modals should act the same way. They need to be inside the content body, below the header,
   and always be able to be closed."*

   Three rules, and they live HERE so no screen can get them wrong on its own:
   1. A modal starts where the nav ends. `inset: 0` put a sheet's own top edge — and its close
      button — underneath the fixed nav, which is exactly how the Seed board became impossible to
      close. `--nav-h` is the nav's own height (56px, 96px under 640px), so this is right on every
      device without a single media query here.
   2. The sheet is a COLUMN with its own scroller: `.ui-modal-hd` and `.ui-modal-ft` keep their
      height, `.ui-modal-bd` is the only part that scrolls. A sheet that scrolls as one block
      carries its close button off the screen the moment its content is tall.
   3. Its height is measured against the space BELOW the nav, never the whole viewport, or a tall
      sheet runs off the bottom by exactly the nav's height. */
/* "There is more below", and only while it is true — V3-161, Eric 2026-09-14: *"Some user may not
   know that we can scroll… As soon as they scroll down, it needs to disappear."* It sticks to the
   bottom of the modal body, ignores the mouse entirely, and fades rather than jumping. Part of the
   modal primitive, because every `.ui-modal-bd` is a scroller and every one of them can hide
   content under its own bottom edge. */
@keyframes ui-scroll-cue-nudge { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(3px); } }

/* ── Working — the button is the status (LAW § Spend UX · DESIGN.md §4.1) ──
   A priced button has three states and nothing else says "running":
   buy = lime with the price · working = orange, a spinner and the seconds ·
   done = the check. `.ui-spin` turns any icon into the spinner. */
@keyframes ui-spin { to { transform: rotate(360deg); } }

/* ── Loading — one "page is loading" block, never a private spinner ──────
   `.ui-loading` › the spin icon + one line; `.is-page` when it stands in for
   a whole page (tall, centred). `.ui-secs` inside it prints the seconds. */

/* ── Generation wait tile (Eric 2026-09-20 → 2026-09-24) ───────────────────
   The one placeholder while a picture is being made: dark field (same as the
   page hole), left→right white sweep, slow star. No purple / pink wash —
   Eric 2026-09-24. Aspect via --ui-gen-ratio (default 3/4). Stagger via
   --ui-gen-i (0, 1, 2…). Live React path is CraftWait / GenWait → `.ui-craft-*`;
   `.ui-gen-wait-*` is the retired CSS twin. */
@keyframes ui-gen-shimmer {
  0% { transform: translateX(-120%); }
  100% { transform: translateX(120%); }
}
@keyframes ui-gen-spin { to { transform: rotate(360deg); } }
/* The sweep used to be a 55% slab fading to CSS `transparent` (black at alpha 0).
   That black edge sat as a vertical cut down the middle of the tile. Fade the
   same violet to alpha 0, and blur it, so the light dies out instead of stopping. */
/* Eric 2026-09-20: peak was reading too white — drop opacity a notch, keep the sweep.
   Eric 2026-09-23: sweep is diffused white (same as `.ui-craft-shimmer`), not violet/pink. */
/* Tile grids only — never `.ui-craft-status` (that card is a flex stack: time · label · %). */

/* ── Dot — a 7px light beside a word: connected, off, attention ──────────
   Replaces every private StatusDot. Default = faint (off). */

/* ── Home & media parts (DESIGN 2026-09-09, roadmap §10 step 4 · §7 item 3) ──
   Everything the Home page draws, named once: a four-column grid, a row of
   pills, a card you click, a big number, the greeting that stays while you
   scroll, a media thumb with a play badge, the ideas reel, the row of faces,
   the funnel. Gallery, Generations and Projects reuse them. */

/* A card you click (a project, a tile): same card, a hand, a lit hairline on hover. */
/* A tiny link (Clear prompt, Change, Open ad) is half the size of the text it sits in. */

/* The big number of a stat card: mono, tabular. `.is-ghost` = not yet real. */

/* The greeting: name + the one next step beside it. A plain block in the flow, stacked like
   every other row — no sticky, no range, no guessed height (Eric 2026-09-09: "it is not good to
   play with the height; stacked, with div"). */

/* A media thumb: a picture or a video, square / tall / wide, with a play badge. */
/* Full picture, never cropped: the tile letterboxes on the gradient instead (Eric 2026-09-09). */
/* White letterbox for product / packshot photos that already sit on white
   (Eric 2026-10-03): seamless with the picture; dark theme still uses this
   paper plane so the product edge reads clean. Pair with `.is-contain`. */
/* A whole-picture slot: the Seed and every influencer card.
   The box is 9:16 because that is what the Seed renders at, and the media is
   ALWAYS `contain`, never `cover`. Owner rule, 2026-09-13 (V3-146): if a ratio
   ever drifts again the picture letterboxes inside the box, it is never cut. */
/* Profile Seed, Close-up, and Soul sheet: the picture in view sets the box.
   A 3:4 Seed, a square Close-up, and a 16:9 sheet each keep their own shape,
   the field radius clips that shape, and the picture is contained, never cut.
   The plain `.ui-fitbox` stays 9:16 for a list card that must not move. */

/* The reel: tall cards you scroll sideways; the one in front plays. */

/* The faces: round faces with a name, and the dashed one that adds.
   Padding keeps the picked-media ring from being clipped by the scroll row. */
/* max-width: a row inside a flex column (align-items: flex-start) grew to its faces and pushed the page sideways on a
   phone — six showroom faces made Product Ad Studio 528 px wide at 390 (2026-10-19). Capped, the row scrolls inside. */
/* A face pick with a separate View under the name (Photo studio outfits — Eric 2026-09-23 A).
   Picture selects; View opens MediaViewer. Hit area ≥44px for a thumb. */

/* The funnel: five stages as small bars. */

/* A video in the wide modal. */

/* ── Rhythm — every stack has a gap; nothing is ever glued (Eric, 2026-09-09) ──
   The only gaps are --s-1…--s-8. A stacked form is `.ui-fields`: 16px between
   fields, 24px before its action row. `.ui-form` is the ROW TABLE only
   (`.ui-card.ui-form` › `.ui-row`); on a bare <form> it means a stack and gets
   the same gap, so the old sign-in mistake cannot come back. Safety net: inside
   any box that has no gap of its own, a field after a field and an action row
   after anything still get their space. */
/* ── Rule 13 — a field brings its own gap (Eric, 2026-09-11: "everything is stacked
   together, glued together… every time we add an input it should already come with
   a gap") ──
   MINIMUM gaps, from the class alone, wherever a field lands — a panel, a plain <div>, a
   card body. A block of the field family keeps --gap-field (12px) from WHATEVER sits
   before it, and whatever block sits after it keeps the same; a line that belongs to the
   field above — the improve star, a hint, an error — and a bare label over its control keep
   --gap-field-line (6px); an action row keeps --s-4. Only in a vertical stack: never inside a
   kit box that lays things side by side or already has a gap (the list is READ from this
   file: every flex row, inline-flex, columned or gapped grid), and never inside a page's own
   inline flex/grid, so a gap is never doubled and a row is never bent. A hidden sibling
   between two blocks (a file input, a template) does not break the pair. Zero specificity —
   every part sits in :where(), even the :not() — so an explicit layout still wins. Measured 2026-09-11 on Photos › Face: seven blocks at 0px
   from each other, the star glued to the field; after: 12 / 12 / 6 / 12 / 12. */
:root { --gap-field: var(--s-3); --gap-field-line: 6px; }/* align-items: start — a taller sibling (hint + “Add…”) must not stretch the other
   column’s `.ui-select` (Eric 2026-10-03: never two dropdowns of different heights). */
/* A secret that is not a login (an API key, a token): a TEXT input the browser
   masks with dots. Never `type="password"` — a password manager keys off that,
   decorates the field and its neighbours, and ignores the opt-out flags. */

/* ── Card lead — title + one line, left of the pill in `.ui-card-top` ── */

/* ── Meter — a quantity against its limit (storage, quota, budget) ────────
   `.ui-meter-row` (two ends) above `.ui-meter` › `i`; the fill width comes
   from `--ui-meter` on the element. `.is-warn` orange, `.is-bad` red. */
/* A meter that draws a shape, not a score, takes the page hue (Look v2: the lime stays for the one action): the part
   that matters in the strong hue, the rest soft. */

/* "How many?" as a slider. The lime is the kit's, so the browser's own blue never appears.
   (DESIGN 2026-09-10, Photo studio step 8.) */

/* ── The count — pick one of N, as numbered dots (Eric, 2026-09-11: "ten dots from one to ten
   guide us to press the correct number"). A slider hides the target; a dot IS the target.
   Same shape as the step number: a dashed grey square-ish disc, the picked one solid lime. ── */

/* "This one is still being made" as a tile, so a picture that does not exist yet keeps its
   place in the row: the spinner, the percent in mono, what it is doing, how long it has
   taken, and the meter pinned to the bottom. (DESIGN 2026-09-10, Photo studio props.) */

/* Craft wait — generate placeholders, site-wide (Eric 2026-09-20 → 2026-09-24).
   .ui-making stays the small dashed "still being made" chip. .ui-craft-* is the
   full image-generation wait: dark hole, angled white sweep, spinning star, timer.
   No purple / pink field (Eric 2026-09-24). */
@keyframes ui-craft-shimmer {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(250%); }
}
@keyframes ui-craft-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
/* Placeholder tile with the same centered status card as `.ui-craft-wait` (Eric 2026-09-23). */
/* Status card is the loader — hide the spinning star so wait holes share one look. */
/* Pre-generate Result hole — image icon only; no glow · timer · % (Eric 2026-10-01). */
/* Provider preview: hole hugs the picture (parent is `.ui-fitbox.is-natural`). Status card floats centered. */
/* ONE wait status card sitewide — time · label · % · bar (Eric 2026-10-11). */
/* Fixed `.ui-nav` covers the top of the viewport. Any `scrollIntoView({ block: 'start' })`
   target without this margin lands under the nav (Create Seed wait, Eric 2026-09-24). */
/* One Seed option is a portrait card, not a full-bleed 9:16 column (Create count=1
   used to paint a tile taller than the viewport and slide under the sticky nav). */

/* Product slots: the things the influencer holds or wears. One column each, 100px wide, so the
   picture, the holding/wearing choice and "save as product" line up down the row.
   Class names stay `.ui-prop*` (kit contract); the user-facing word is Product.
   (DESIGN 2026-09-10, Photo studio step 7.) */
/* An add card sized to sit in a row of 100px slots, not to fill a grid cell. */
/* A two-way choice that must fill the thing above it. */

/* What you just made: the pictures of one run, centred, never wider than the room they
   would need at their own size. A picture still being made keeps its place at its real
   shape, so the row does not jump when it arrives. (DESIGN 2026-09-10, Photo studio.) */
/* The making tile, filling a result's frame instead of its own 100px square. */

/* The admin section rail: the kit's `.ui-seg`, sitting in PageShell's rail slot, made of
   links rather than buttons. It replaced a 220px sidebar with its own shell and its own
   pre-kit tokens — the reason admin read as a different product (Eric 2026-09-09). It
   wraps rather than scrolls: eight sections must all be reachable without a swipe. */

/* The disclosure: a <details> that looks like the rest of the kit. Admin uses one per
   namespace to keep a long page scannable; the summary is a row you can click, the body
   sits inside the same card. No JavaScript, so it works before hydration. */
/* The title row wraps: a long name + address + pill on one unbreakable line pushed the whole phone page 87px sideways
   (Brand Hunter drafts, 390, 2026-10-18). */
/* Bigger chevron so the fold reads as a control; open title+chevron = accent-3 orange (attention), not more lime (Eric 2026-09-26). */

/* Mark / promo accordion — pink accent-2 open AND closed. Never lime hover.
   Twin Studio "Why pay for Clean?" (Eric 2026-09-26): catch the eye without looking like a spend. */

/* A list beside an editor: pick on the left, edit on the right, and stack on a narrow
   screen. `minmax(0, …)` on both tracks is what stops a long template from pushing the
   PAGE sideways — a grid track is content-sized by default, so an unbreakable string wins
   unless the track is told it may shrink. Caught in the browser: the page scrolled, not
   the panel. */
/* DESIGN 2026-09-09 (session 05): this used to be a SECOND `.ui-split` rule, which silently
   turned the Know page, Pitch setup, Project detail and Projects home (main + 320px rail)
   into a 260px main column with a wide rail. A variant is a modifier, never a redefinition. */
/* The list stays on screen and scrolls inside its own box while the editor is the page. */
/* The grids inside the list size to their content by default (an auto track is max-content), so a
   260px list carried 294px of rows and the phone page scrolled sideways. Tell them they may shrink. */

/* An item in such a list: the whole item is the target, and the one you are on takes the
   same dashed lime hairline a chosen segment does. (Not `.ui-pick-row`, which is the
   prospects Pick list row — a second rule under that name broke it, session 05.) */

/* A number with its unit: the field grows, the unit select keeps its own width, one line.
   (Storage quotas had them in a button row; the select shrank under its own chevron.) */

/* Text the machine wrote: a template, a preview, a payload. Monospace, wrapping, scrolling
   inside its own box so a long line never widens the page. */

/* ── The table part (§7 item 2) ─────────────────────────────────────────────
   A REAL <table>, because every admin page was hand-rolling a grid of divs with
   its own `gridTemplateColumns` — and then writing role="table" and role="row"
   on it by hand, which is markup asking to be a table. A real one gives the
   screen reader all of that for free, and sizes its own columns, so a page never
   declares a column template again. Eight admin pages must not invent eight
   tables (roadmap §7 item 2).

   Shape:  .ui-table-wrap > table.ui-table > thead/tbody
   Cells:  .is-num  right, tabular figures · .is-break  a long id may wrap
           .is-tight  a column that should stay as narrow as its content · .is-center  centred text */
/* The last column usually holds the action; keep it hugging the right edge. */
/* The action column stays pinned to the right edge; the other columns scroll under it (Eric 2026-10-14). */
.ui-table tbody tr.is-graded:not(:hover) td.is-act { background: linear-gradient(color-mix(in srgb, var(--row-tone) 7%, transparent), color-mix(in srgb, var(--row-tone) 7%, transparent)), var(--surface); }

/* ── Table row verdict — V3-198 ─────────────────────────────────────────────
   A row that has been CHECKED carries a whisper of its verdict's tone behind it
   and a 3px bar of that tone on its left edge. Eric, 2026-09-16: *"that will be
   nice also to have in a small greenish background or any color that fits all
   the rows that has been scanned. So we know visually which one has been
   scanned."* An unchecked row is left plain, so "checked" is the thing that
   stands out rather than the other way round.

   One tone variable per verdict, set on the row; the three rules below never
   name a colour, so a new verdict needs one line, not four. Tones are the
   palette's existing three — never a new colour. */

/* The verdict word and its mark sit on one line and stay together when the cell narrows. */

/* ── The market part (V3-116 step 7, Eric's B 2026-09-09) ───────────────────
   A niche card that can be read at a glance: a shape icon that says what kind of
   market it is, a 1-5 need scale in dots, the pay range drawn on ONE scale shared
   by every card, and the sub-niches as chips with the gems marked. Nothing here is
   a colour a page chose — the shape tones are the kit's accents. */
/* ONE lime per card, and it is the smallest thing on it (Eric 2026-09-09: "it's way too
   bright to have too much lime… one lime into the box card and two other tones"). The
   shape is told by the GLYPH, never by five different bright colours — that was the glare. */
/* The need scale is ORANGE, the palette's attention tone — "needs permission, saving, due".
   A market that needs video is exactly that, so the colour is the meaning, not a choice. */

/* The pay band: the same 0 -> board ceiling scale on every card, so two cards can be
   compared by eye. Left and width come in as data on the element. */
/* The pay band is PINK, the palette's highlight tone — and pink is explicitly never a
   button, which is right: a range is something to notice, not something to press. */

/* A card you can open. The whole card is the target — never a "read more" link tucked in a
   corner — so the hand appears wherever the eye already is. The lift is small on purpose:
   fifty of these on one screen, and anything bigger turns the grid into a trampoline. */

/* ── One market in depth (step 7b) ─────────────────────────────────────────
   The three facts at the top, then the ideas: one line each, a star on the left,
   and the goal it serves on the right. A list, not cards — the point is to scan
   forty of them fast. */
/* 3px, not the kit list's usual 6: forty-eight rows read as one scannable column, but
   they are never glued. Eric 2026-09-09, and the rule was already written — every stack
   has a gap. `gap: 0` here was my own violation of it. */
/* Owner canned notes on Clean pay modal — mark accent so they stand apart from system chips. */

/* ── Detail parts — inside an open section (DESIGN.md §7.5) ─────────────
   Eric, 2026-09-09: "too much text pasted together… titles strong, the
   description inside a small box with a very soft background… icon and logo
   on one row with the title… labels bold white up to the colon." */
/* The writer block (a pitch, a prompt, a JSON) is the same note as a <pre>: mono, line for line. It was a second `.ui-note` rule
   before session 06, and its mono font leaked into every description note on the Know page — one name, one definition. */
/* Long recipe values (prompts) sit under the label as a full-width wrapping note —
   a flex row was clipping mid-line in the Generations drawer (Eric 2026-10-05). */
/* Last Generate modal: each recipe line is one row; the list scrolls (Eric 2026-10-05). */

/* Compact pay stack — last Generate modal (Eric 2026-10-05). Raised rows like a
   small instrument panel: provider on top, then model, then short segs, then a
   full-width lime Generate. Not a second primary elsewhere on the sheet. */
/* Lit words (a search hit inside the words people say): a soft accent wash; the text keeps its own colour. */
/* A tile you can pick (a provider, a route): the dashed lime hairline says "you picked this",
   the dot says whether it is ready. `.ui-tile-head` = dot + name on one line. */
/* A tile whose pick IS a picture (outfit link sheets) wears the media double ring, not the dash. */ /* already chosen elsewhere — not busy */
/* A field in a toolbar takes room up to its own size; on its own it would shrink to its text (the outfit board's picker, session 06). */

/* A strip of pictures you can pick from — the photo history, and any future "these are the
   ones you made". A tile is `.ui-shot.is-tile`: fixed height, its own width from its shape,
   the kit's picked line when `aria-pressed`. (DESIGN 2026-09-10, Photo studio.) */

/* The tick that says "this one is picked". It shows on hover as an empty ring, so a
   picture tells you it can be picked before you pick it. */

/* The one or two actions that sit ON a picture — bottom left, on a scrim so they read on
   any photograph. Same shape as `.ui-thumb-tools`, but inside the picture, not under it. */
/* A tiny worded action on a picture — two short words stacked, because a 96px tile has no
   room for a line of text and an icon alone does not say what it does. */
/* The action that moves her forward (Create video) is lime always, not only under the cursor (Eric 2026-09-11). */

/* A floating bigger look at the picture under the cursor. It is a magnifier, not a modal:
   it never traps focus and it dies on mouseleave. */

/* Two pictures that answer the two questions of a shot — who, and where. They stay the same
   size as each other and stack on a phone. (DESIGN 2026-09-10, Photo studio.) */
/* A clip in the same frame fills it like the picture does (the `.ui-thumb-media video` rule, in a 9:16 frame). */

/* A name written ON a picture, on the dark that keeps it readable over any photograph. */
/* On a big framed picture the actions move to the TOP: the bottom belongs to the caption,
   and at 5px from the bottom a download button sat on top of the name (measured on Photo
   studio, 2026-09-10). The scene keeps its top-right for the pose medallion, so its actions
   take the left; a picture with no medallion puts them on the right with `.is-end`. */

/* The stand-in art for a place we have no photograph of: the icon, the name, the hour. */

/* Text pinned to a fixed number of lines, with the whole of it one tap away. `.ui-clamp`
   has NO padding of its own: `overflow: hidden` clips at the padding box, so padding here
   would leave the top of the next line showing. */
/* `lh` = the element's own line height: a fixed em budget cut the second line in half wherever the line height was
   not 1.2 (Brand Hunter cards, line-height 1.5, 2026-10-18). */

/* The pose, worn on the picture like a medal: the stick figure, and its name under it. */
/* An image in a modal, whole and contained — never cropped (Eric, 2026-09-09). */
/* A picture in the viewer is CONTAIN — never cut (Eric, 2026-09-11).
   `object-fit: contain` was already here and was not the problem: the height was
   measured against the VIEWPORT while the picture lives inside the modal, which is
   shorter. Measured on a 1440x900 window: the image box came out 720px tall inside a
   671px body, so `.ui-modal { overflow: hidden }` ate the rest and a 896x1200 portrait
   read as a square crop. The budget is now the modal's own — its max height less its
   head (82), foot (65), body padding (36) and slack for a foot that wraps on a phone.
   Measured with no clipping at 1440x900, 1280x720, 1024x640 and 390x844.
   `max-height: 100%` does NOT work here and was tried: `.ui-modal-bd` is `flex: 1 1 auto`,
   so its height is not definite and the percentage resolves to none — the image came back
   1216px tall, worse than the bug. */
/* The budget below is the MODAL's own height, so it moves whenever `.ui-modal` moves — 2026-09-14
   the modal law subtracted the nav, and a budget left on a bare viewport would now overflow the
   sheet by exactly the nav's height. */
/* A picture you can open. The cursor is the magnifier, the same one on the
   finished frame (`.ui-result[data-ready="true"]`). It beats the hand on
   `button.ui-thumb`. Eric, 2026-09-19: every picture that opens uses this. */

/* Batch preview (Generations): prev / count / next sit over the bottom of the picture. DESIGN rule 16:
   a control over a picture is above the picture; the scrim token keeps it readable on any frame. */
/* The X on a thing you can drop without a confirm (a pulled image): a red
   disc top-right, 28px — a finger can hit it, it does not hide the image
   (Eric, 2026-09-09). Coarse pointers get 32px.
   And it is ALWAYS on top of the picture (Eric, 2026-09-12, the outfit
   pictures: "right now it hides, it's clipped because of the image"). Inside
   .ui-thumb-media the stack is fixed site-wide — video 1 · img 2 · pill 3 ·
   tools 4 · X 5 — so a control over a picture never loses to the picture.
   DESIGN.md rule 16; guard in ui.test.mjs. */
/* Tiny strip thumbs: hang a bit past the corner so the picture stays readable (Eric 2026-10-04). */

/* Every button that spends is lime (Eric, 2026-09-09: "all the pay buttons
   need to be green"). The price inside it is the mark: any secondary,
   tertiary, menu item or bulk-bar item that carries a `.ui-price` wears the
   primary's look. Only the primary's glow is reserved for the one primary. */

/* A button never touches the text above or below it (Eric, 2026-09-09: "make
   sure there is always a gap above and below buttons"). Grids and forms
   already space their children; everywhere else the rule adds 12px. */

/* "Again" — buying a thing we already have lives at the bottom of its
   section: a hairline, the tertiary with its price, and when it was loaded.
   Never at the top; the chip up there is for the first time (DESIGN.md §4.1). */

/* Process toast — a stack at the top right (or the bottom right for long
   jobs), one card per job. `.is-working` wears the orange snake — one light
   running round the border — and the seconds; `.is-good` is green and leaves
   after 5 s; `.is-bad` is red and stays until ×. AppNotice.jsx renders it. */
@property --ui-ang { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
@keyframes ui-snake { to { --ui-ang: 360deg; } }
@keyframes ui-toast-in { from { opacity: 0; transform: translateY(-6px); } }
/* Above nested modals (Twin Lab 950 · Generate 1000) so process toasts stay visible — Eric 2026-10-01. */
/* A step page's floating Back / Next bar is never covered: the bottom toasts start above it (Eric 2026-10-18, A: "make
   sure that the Next is always available, even if there are 1, 2, 3 toast notifications"). The bar is pinned to the
   screen bottom; `MicroNav` writes its measured height on <html> as `--ui-stepnav-h` — the stack starts 12 px above. */
/* The older fixed Next bar (`NextBar.jsx`, prospect pages): the stack starts above it — the bar's own bottom offset
   (16 px; 80 px at ≤ 900 px, over the phone's tab rail) + its folded height (`--ui-nextbar-h`, set on <body>) + 12 px. */

/* Just landed (Eric, 2026-09-25). When a job finishes, the part it wrote is opened, brought
   into view and wears a BLUE light running clockwise round its border for 3 s, then fades.
   Orange is "working" (the toast above); blue is "look here, this just changed". It is its own
   fixed layer that follows the part (`landOn()` in utils/landOn.js), so it never borrows the
   part's ::before/::after — the speech bubble's tail and the accordion's chevron live there. */
@keyframes ui-landed-fade { 0%, 75% { opacity: 1; } 100% { opacity: 0; } }

/* The business shell starts under the fixed app bar: nav height + 24px. Without
   it the sticky rail slid over the head's 32px gap and the eyebrow touched the line. */
/* The wall inside the shell already carries the shell's top padding. */

/* ── The deck parts (DESIGN session 06, roadmap §10 step 9 — this seat's slice) ──
   What the Create flow's parts (components/create-video/*) needed that the kit did
   not have. Each one is a modifier on a part that already exists, never a second
   definition (session 05's lesson), and each is measured on design.html §9d. */
/* A notice: one or two lines in a tinted box — the note takes a tone like a card does. */
/* The action of a one-line notice sits on its right; in a stacked note a link or a button keeps its own width. */
/* The words as written (a speech): line for line, in ink. */
/* A field beside its button: the field takes the room, the button keeps its own. */
/* In a foot or an action row, the quiet way back sits on the left and the actions on the right. */
/* A foot with nothing to go back to (the first question of a wizard) keeps its one action at the end. */
/* A link that is a button can be disabled; a lone link in a card keeps its own width (a card is a column). */
/* A tile is a grid, and a grid stretches its children: a pill in it keeps its width (session 05's bar, again). */
/* A face / sheet / thumb you picked wears the MEDIA double ring (3px solid + 2px soft outline).
   Soft is outline so overflow:hidden can clip the picture to the SAME radius as the border —
   box-shadow + overflow:visible left dark corner holes (Eric 2026-09-23). */
/* Picture tiles that are the pick itself (identity Soft Editorial, beat cards, thumb-picks).
   Faces are excluded — their ring sits on `.ui-face-disc`, not the button. */
/* A face is a person, so it is a disc. An OUTFIT is a whole body, and a disc crops the
   clothes off it — `.is-tall` makes the same picker a standing rectangle, framed from the
   top. (DESIGN 2026-09-10, Photo studio step 6.) */
/* V3-123 → 2026-09-24 evening — store sheet is a 3:4 premium flat-lay (no human).
   Contain, nothing cut. Same width rhythm as the tall card so a row of both lines up. */
/* A pill on a picture (the camera word on a beat): top-left, above the media. */
/* A card you select that is neither a link nor a button (a beat) says so with a role, and gets the hand and the focus ring. */
/* A card that IS the section (the wizard's one question) carries the section title at its own size — `.ui-card > h2` would shrink it to a card title. */

/* ── 8. Page anatomy — header → rail → gap → title → sections ────────────
   BusinessPage.jsx owns this order. 32px under the rail, 32px under the
   title, 48px between sections. A page never paints a title under the bar. */
/* The shell owns the column: centred, 1120px wide, 24px at the sides, and the
   room under the fixed app bar. A page never adds its own (Eric, 2026-09-09:
   Settings sat on the left edge and under the bar — the shell had none of this). */
.ui-page {
  width: 100%;
  max-width: calc(1120px + 2 * var(--s-6));
  margin: 0 auto;
  padding: calc(var(--nav-h) + var(--s-6)) var(--s-6) 90px;
  display: flex;
  flex-direction: column;
  color: var(--ink);
  font-family: var(--font-body);
}
/* Inside the business shell the wrapper already gives the nav room and the sides. */

/* The topbar stacks like every row: no backing, no sticky (Eric 2026-09-09: a bare bar with no
   padding behind "← Boards" looked ugly). Only the Create step rail keeps a sticky, backed bar. */

/* ── The collection — any page about many things (Eric, 2026-09-09: "when we
   have a huge list of any items… cards or rows… a switcher with two icons…
   on rows a checkbox column, check all at the top and beside it Action").
   `.ui-collection` › `.ui-card-flat.ui-collection-tools` (check-all + count ·
   the Action menu · the page's own search / filters · `.ui-seg.ui-view` on the
   right, cards = the rounded squares, rows = the lines) › then a `.ui-grid-3`
   of cards OR `ul.ui-list` › `li.ui-collection-row`. The same items, two shapes;
   the choice is remembered per collection. */ /* only the switcher: no empty box (Eric 2026-09-09) */ /* a .ui-card is a column; the tools row is a row */
/* The same row inside the confirm modal: the exact things about to go, each with its face and its name. */

/* A media grid in justified rows (Gallery): the page sizes each tile (layout
   only, inline width / height); the kit gives the row, the skeleton and the
   tools that appear on a thumb when you hover, focus or pick it. */
/* History / strip placeholders while a photo or video is still arriving (Eric 2026-10-05).
   Minimal pulse + tiny center loader — never “Generating 12%” text inside a 60px thumb.
   The words live on the bottom-right process toaster (`showAppProcess`). Photos + Videos share this. */
@keyframes ui-skeleton-spin {
  to { transform: rotate(360deg); }
}
@keyframes ui-skeleton-pulse {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 0.9; }
}
@keyframes ui-skeleton-shimmer {
  0% { background-position: 120% 0; }
  100% { background-position: -120% 0; }
}
/* A file that is really gone (not slow, not undecoded): the attention tone, so it reads as
   a fact about the file and never as a broken page. DESIGN 2026-09-09, Eric option A. */

/* A mosaic: four cells of a board's first pictures (Inspiration). */ /* a portrait keeps its face: crop from the top (Eric 2026-09-09) */

/* A masonry: same width per column, natural height, the whole picture — never a crop
   (Eric 2026-09-09: 9:16, 16:9 or 1:1, "we see always the full image"). CSS columns, no script;
   items run down each column. */
/* A tab strip is the segment control, one row above the sections. */

/* A native fold (details/summary) that wears the accordion head; a scrolling code note. */

/* ── 9. Motion ────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .ui-primary, .ui-secondary { transition: none; }
  .ui-primary:hover { transform: none; }
}

/* ── T6 · the public hero (Landing) ─────────────────────────────────────────────
   The signed-out first screen: always dark, the site ground behind it, six floating
   portrait cards as decoration (behind the words, no pointer, hidden under 860px), the
   words in the middle, one primary. The cards are decoration outside the flow on purpose:
   they never push or cover a word — the vignette and z-order keep the words on top. */
@keyframes ui-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
@keyframes ui-ping { 0% { transform: scale(1); opacity: 0.35; } 80%, 100% { transform: scale(2.4); opacity: 0; } }
@keyframes ui-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-18px); } }
@keyframes ui-sway { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(5px); } 75% { transform: translateX(-4px); } }
@keyframes ui-appear { from { opacity: 0; } to { opacity: var(--o, 0.44); } }

/* ── THE ONE VIEWER — a page's own act, on the viewer's dark glass ───────────────────
   Eric 2026-09-12: one modal for every picture, site wide. A page may add its own act
   (Use this outfit, Create video, Reuse, Delete) beside Download. It must not bring a
   page-coloured button onto a black overlay, so the kit buttons are re-dressed here in
   the same glass as Download, once, for every page. The viewer itself is
   src/components/ImageInspectionLightbox.jsx. */

/* ── V3-157 · more ways in, folded under the door they belong to ─────────────
   Eric, 2026-09-11: *"add a small arrow at the right in the Ways in, and that
   will mean that for the phone number there's more phone numbers, and it's
   going to expand and show all the phone numbers."*

   The arrow carries the COUNT. An arrow alone does not say how many are behind
   it, and the count is the whole reason to press. It sits left of the ⋯ menu,
   so the row's last control is still the one that was always last.

   It points where the content will appear — down folded, up open — the same
   honesty rule as `.ui-nextbar-chev` (rule 15). */
/* The nested list is a row of the same list, so it inherits the rail's width
   rules — including `minmax(0, 1fr)`, which is what keeps a phone from
   scrolling sideways. */
/* The name under the number. It wraps: "Jill Loveless - Stylist /Owner" does
   not fit beside a phone number on a 390px screen, and truncating the person
   is worse than a second line. */


/* V3-204 — a picture that keeps its OWN ratio, so it never sits in a band of empty box.
   Eric, 2026-09-16: *"remove the gap top and bottom… make it fitting maximum the height of
   nine sixteen. We should not have a gap like that."*
   `.ui-fitbox` and `.ui-thumb-media.is-contain` both letterbox on purpose — they fix the BOX
   and let the picture float inside it, which is right for a slot whose size must not move.
   A table row is not that slot: the seed renders 3:4 while the box was 9:16-ish, so every row
   carried a black band above and below. Here the picture sets the height and `max-height` is
   the 9:16 ceiling, so a taller picture is capped instead of stretching the row.
   As a button it is the door to the ONE viewer — never a second lightbox. */


/* ── 13. The "what to do next" bar (V3-136) ──────────────────────────────
   Eric, 2026-09-10: *"the user should have a floating 'what to do next' at the
   bottom… always his way out when he doesn't understand what to do next."*

   Folded it is one line: badge, eyebrow, the step, the chevron. Open it adds
   the reason and the one button that does it. It is centred, not full-bleed,
   so on a wide screen it reads as a guide and not as a second nav.

   The page keeps the FOLDED height clear, never the open one — a gap that grew
   when the bar opened would jump the page under the cursor mid-read. */

/* V3-155 · two colours, two meanings (DESIGN.md rule 15). Lime = PRESS THIS.
   Pink = LOOK HERE. The bar used to wear a lime hairline over the page ground,
   which made it the fourth lime thing on a Know page that already had seven —
   so it blended into the very noise it exists to cut through. It now gets a
   full pink ground and a solid pink line; the button INSIDE it stays lime,
   because the button is still the thing you press. Pink is the guide's colour
   and nothing else on the page may use it, or it dilutes exactly as lime did. */

/* The whole line is the handle: a chevron alone is a 16px target on a phone. */
/* V3-155 · the chevron was backwards. The bar is pinned to the BOTTOM and
   opens upward, so folded must point UP ("there is more, up here") and open
   must point DOWN ("press to put it away"). It said the opposite. */

/* The kit shows the bar in the flow of `design.html`, where a fixed element
   would float over the page it documents (rule 6: it must be seeable). */

/* On a wide screen the bar is 720px in the middle, so the fixed feedback bubble
   in the bottom-right corner is beside it. Under 900px the bar spans the width
   and would sit on top of that bubble (measured 2026-09-10: it occupies the
   bottom 24-68px), so the guide moves up to clear it — and that same offset
   clears a bottom tab rail on any page that ever grows one. */
/* On a phone the eyebrow is the one word the step already says. */

/* V3-160 · two-letter language/country code badge */


/* =====================================================================================
   THE TEN STEPS — the road index (/steps) and its chapter pages. docs/UGC-NEW-STEPS/00-BRAINSTORM.md.
   The look of the index is Eric's design, docs/UGC-NEW-STEPS/ugc-steps.html (2026-10-11): one roadmap of ten
   glowing cards, two columns, each card owns one color and one illustration (top right). The hue comes ONLY from
   `.ui-step-N` → `--step`; the pieces read `--step`, `--step-soft`, `--step-line`. Buttons stay lime.
   ===================================================================================== */
.ui-step-1 { --step: var(--step-1); --step-soft: var(--step-1-soft); --step-line: var(--step-1-line); }
.ui-step-2 { --step: var(--step-2); --step-soft: var(--step-2-soft); --step-line: var(--step-2-line); }
.ui-step-3 { --step: var(--step-3); --step-soft: var(--step-3-soft); --step-line: var(--step-3-line); }
.ui-step-4 { --step: var(--step-4); --step-soft: var(--step-4-soft); --step-line: var(--step-4-line); }
.ui-step-5 { --step: var(--step-5); --step-soft: var(--step-5-soft); --step-line: var(--step-5-line); }
.ui-step-6 { --step: var(--step-6); --step-soft: var(--step-6-soft); --step-line: var(--step-6-line); }
.ui-step-7 { --step: var(--step-7); --step-soft: var(--step-7-soft); --step-line: var(--step-7-line); }
.ui-step-8 { --step: var(--step-8); --step-soft: var(--step-8-soft); --step-line: var(--step-8-line); }
.ui-step-9 { --step: var(--step-9); --step-soft: var(--step-9-soft); --step-line: var(--step-9-line); }
.ui-step-10 { --step: var(--step-10); --step-soft: var(--step-10-soft); --step-line: var(--step-10-line); }

/* The header button — the one animated thing in the bar (Eric: "it needs to stand out"). */
@keyframes ui-steps-pulse { 0% { transform: scale(1); opacity: 0.9; } 70% { transform: scale(1.18, 1.45); opacity: 0; } 100% { transform: scale(1.18, 1.45); opacity: 0; } }

/* The index: eyebrow, the gradient title, one line, the ten-color rail, then the grid. */

/* The card: glow from the top right, a fine dot texture, number pill, title, the art, one promise, three chips, the foot. */

/* The illustrations: every fill and stroke is driven by --step; "paper" is the one light fill. */

/* The chapter page: side menu · lesson · the Do panel. */
/* Soft buttons (Eric 2026-10-11): a border in the neighbour step's hue at 50%, a faint fill, never a solid block. */

/* The side menu — ONE vertical section navigation, for every page that has chapters (Eric: one primitive, never a near-copy). */

/* The lesson reader (StepLesson.jsx): one screen at a time inside the one step card (MicroFlow · MicroTabs · MicroNav,
   2026-10-18), the "Go deeper" link, the checkpoint, the honesty line. docs/UGC-NEW-STEPS/02-CARD-PLAN.md §1. */

/* A done card on the index: the tick replaces the number in the pill, the rest of the card is untouched. */

/* Every screen has its icon and one running example (Dani); every chapter head says what the person gets. */

/* PICTURE IN — the one box a picture comes in by: Choose · ⌘V Paste · My pictures, drop anywhere on it
   (Eric 2026-10-12 night; STUDIO-V3/PROJECT/PICTURE-IN-PRIMITIVE.md). `PictureIn.jsx` owns the behaviour. */

/* ── Spoken words: .ui-say (Eric 2026-10-18) ───────────────────────────────
   Anything a person will say out loud sits in a chat bubble, so the eye finds it first. The bubble flips
   with the theme (--say-bg / --say-ink): light gray on dark, dark on light. Its title sits above it, in
   capitals, a little bigger, after a speech-bubble icon. */
/* The editable bubble: a picked idea's words, changed in place (a text box draws no ::before, so its wrapper wears the tail). */
/* With the Improve star, the wrapper also holds the Undo row under the box (Eric 2026-10-19: after Improve the point
   fell under Undo), so the tail sits on the star's own box instead: `.ui-improve-field` holds only the text box. */
/* One shot of a plan (`components/ShotRow.jsx`, Eric 2026-10-18: the one shape for every shot plan, site-wide):
   the number and the seconds on one line, then WHAT HAPPENS (plain box) and WORDS SAID (the bubble above). */ /* from · to · s stay on one line, even at 390 */

/* ── Preview bar (FUTURE-FEATURES, Eric 2026-10-18: "a red bar: Preview coming up soon") ────────
   The red band a "coming soon" page wears at the top of its head: sticky under the nav, wraps on a
   phone, the kit's bad red, white words. One `.ui-tertiary` link inside ("Tell me when it is ready"). */

/* ── Flow look (FUTURE-FEATURES Look v2, Eric 2026-10-18: "stunning") ─────────────────────────────
   Generic parts for every step flow; the page sets its hue once with `.ui-step-N` (DESIGN § 2.6) and
   every part reads `--step`. One writer (the design seat). Shown in /design.html § 13.
   · `.ui-flow-hero`   the 21:9 header picture in the `head` slot, under the red PreviewBar: 200 px tall at
                       ≥ 900 px, its own ratio under 640; a 1 px line and a glow in the hue; the title block
                       sits ON it at desktop (top-left, white, over a fade) and under it on a phone (theme ink).
   · `.ui-flow-block`  a block of a step, in the /steps card look (Eric 2026-10-19: "a similar look for the boxes"):
                       the paper, two glows and a dot grid in the corner, a line in the hue, a solid hue icon
                       square, chips tinted in the hue. A box of fields, not a button: no hover lift. Role tints
                       win over the page hue (pink = idea, orange = suggestion, green = done; `data-role="settings"`
                       = gray).
   · Next = the kit's own `.ui-secondary.is-accent` (not done) → `.ui-primary` (done). Never `disabled`. */
/* `--hero-focus` (FlowHero `focus`): where the picture's objects stand, so the phone crop keeps them (page 02: 78%). */
/* The words sit at the TOP (Eric 2026-10-18: at the bottom they sat on the lime line); the fade darkens the top. */
@media (max-width: 899px) { /* Codex plan check 2026-10-18: keep the picture tall on a phone too; the crop shows its middle */
}
/* One column that never grows past the block: a long unbreakable child (a pill, a chip row) wraps or scrolls inside,
   never pushes the block's words out of the box (FINDINGS 210, page 06 on a phone). */
/* The /steps card's dot grid, fading out from the top-right corner (same recipe as `.ui-stepcard::before`). */
/* Chips in a block take the hue, as the /steps card chips; a picked chip keeps the kit's lime pick. */
/* A long hint drops under the title when the row is short (a phone), never squeezing the title into a column. */
/* Settings stay quiet: a plain icon square, never a white glyph on gray (Codex look 2026-10-19: 2.47:1 in dark). */

/* ── Calendar (FUTURE-FEATURES 02 Social Autopilot, 2026-10-18) ─────────────────────────────────
   The whole planning window as week rows, Monday first (no month navigation). A day is a button when it holds a
   post: date, a picture, the time (mono), one icon per platform, and the status as a word + icon + colour
   (`data-status`: planned = neutral, approval = orange "needs you", posted = green, failed = red; lime only marks
   the selected day — DESIGN §2). Phone (≤ 720 px): a list of the post days with full dates (`.ui-cal-full`). */

/* ── Brand Portal (FUTURE-FEATURES 07, 2026-10-18) ─────────────────────────────────────────────────────────────────
   The brand's page, drawn inside a demo: a dashed edge the demo's own bar, steps and buttons never cross, a top line
   with the tab (the user's monogram, never our icon) and the address. And the one diagonal word a preview video wears
   (Eric 2026-10-18: one big word, 30%, seen — the video stays clear). The real word is written into the MP4. */

/* ── Photo Fix (FUTURE-FEATURES 08, 2026-10-18) ────────────────────────────────────────────────────────────────────
   The brush: an SVG over the photo, its viewBox the photo's own pixels, so a dab sits where it was painted at any
   width. `touch-action: none` only on the LIVE layer (Codex review): a finger paints there and scrolls everywhere else.
   The face box is dashed; the paint is one layer at 50%, so overlapping dabs read as one area. */

/* ── THE AD WALL (Creative Scout, SURFACE 2026-10-20) — a wall of 9:16 ads. Each tile opens on press and plays, muted,
   under the pointer or the keyboard focus (the video is mounted only then); the words sit on a dark fade at the foot.
   `.ui-adwall` › `article.ui-ad` › `button.ui-ad-media` (poster + the lazy video + `.ui-ad-cue`) ·
   `.ui-ad-top` (pills) · `button.ui-ad-save` · `.ui-ad-foot` (h5 · `.ui-ad-meta` · `.ui-ad-say` · a chip).
   `.is-on` = the media double ring (DESIGN.md § Picked media). Reduced motion: no zoom (the tile mounts no video). */
/* A phone (the wall is ~258 px wide there): two tiles a row, as a feed. */

/* The decode stage: the player beside the words (`.ui-decode-stage`); the words as a list that lights the line being
   said (`.ui-said-lines` › li › `button.ui-said-line` `.is-past` / `.is-now`); the ad on a clock — the hook, the
   product in view, the ask, one lane each, the playhead across them (`.ui-clock` › `.ui-clock-lane` ›
   `button.ui-clock-mark` (+ `.is-absent`, a span) + `i.ui-clock-head`; `.ui-clock-ticks` = 0:00 … the end). */

/* The free guide's own styles, moved out of the app (src/styles/ui.css) on 2026-10-22: the guide lives only on
   ugcviralstudio.com/guide. bin/guide-export.mjs adds this file to index.css + ui.css and keeps the rules its pages use. */
/* ── THE GUIDE (Eric 2026-10-21): the free public know-how guide, /:locale/guide. Left: the module menu, one
   rounded card per module, folded or open, sticky beside the lesson. Right: the lesson in its module's hue
   (`ui-step-N` on the page). Phone (≤900px): the menu is a sticky bar that opens the same list. ── */
.ui-guide { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: var(--s-7); align-items: start; }
.ui-guide-side { position: sticky; top: calc(var(--nav-h) + var(--s-4)); max-height: calc(100vh - var(--nav-h) - var(--s-6)); overflow-y: auto; display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-3); padding: 2px; scrollbar-width: thin; }
.ui-guide-brand { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--r-card); background: linear-gradient(135deg, var(--step-soft), transparent 70%), var(--surface); }
.ui-guide-brand-mark { flex: none; width: 36px; height: 36px; border-radius: 11px; display: grid; place-items: center; background: var(--step); color: #fff; box-shadow: 0 8px 20px -8px var(--step); }
.ui-guide-brand-text { display: grid; gap: 1px; line-height: 1.2; }
.ui-guide-brand-text b { font-family: var(--font-head); font-size: 15px; color: var(--ink); }
.ui-guide-brand-text small { font-size: 12px; font-weight: 600; color: var(--muted); }
.ui-guide-phonebar { display: none; }
.ui-guide-menu { display: grid; gap: 8px; }
.ui-guide-mod { border: 1px solid var(--border); border-radius: var(--r-card); background: var(--surface); overflow: hidden; transition: border-color 0.15s, box-shadow 0.15s; }
.ui-guide-mod.is-current { border-color: var(--step-line); box-shadow: 0 10px 26px -18px var(--step); }
.ui-guide-mod-head { width: 100%; display: flex; align-items: center; gap: 12px; padding: 10px 12px; margin: 0; border: 0; background: none; color: var(--ink); font: inherit; text-align: left; cursor: pointer; transition: background 0.15s; }
.ui-guide-mod-head:hover { background: var(--chip); }
.ui-guide-mod-head:focus-visible { outline: 2px solid var(--step-line); outline-offset: -2px; border-radius: var(--r-card); }
.ui-guide-mod-icon { flex: none; width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center; background: var(--step-soft); color: var(--step); transition: background 0.15s, color 0.15s; }
.ui-guide-mod.is-current .ui-guide-mod-icon { background: var(--step); color: #fff; }
.ui-guide-mod-text { flex: 1; min-width: 0; display: grid; gap: 1px; }
.ui-guide-mod-text small { font-size: 10.5px; font-weight: 800; letter-spacing: 0.09em; text-transform: uppercase; color: var(--step); }
.ui-guide-mod-text b { font-size: 14px; font-weight: 700; line-height: 1.3; }
.ui-guide-mod-chev { flex: none; display: grid; color: var(--faint); transition: transform 0.2s var(--ease); }
.ui-guide-mod.is-open .ui-guide-mod-chev { transform: rotate(90deg); }
.ui-guide-mod-list { list-style: none; margin: 0; padding: 0 8px 8px; display: grid; gap: 2px; }
.ui-guide-mod-list a { display: flex; align-items: flex-start; gap: 10px; padding: 8px 10px; border-radius: 10px; color: var(--muted); font-size: 13.5px; font-weight: 600; line-height: 1.35; text-decoration: none; transition: background 0.15s, color 0.15s; }
.ui-guide-mod-list a:hover { background: var(--chip); color: var(--ink); }
.ui-guide-mod-list a.on { background: var(--step-soft); color: var(--ink); box-shadow: inset 3px 0 0 var(--step); }
.ui-guide-mod-list a:focus-visible { outline: 2px solid var(--step-line); outline-offset: 1px; }
.ui-guide-mod-num { flex: none; min-width: 32px; height: 22px; padding: 0 6px; border-radius: 7px; display: grid; place-items: center; background: var(--chip); color: var(--muted); font-family: var(--font-head); font-size: 11.5px; font-weight: 800; font-variant-numeric: tabular-nums; }
.ui-guide-mod-list a.on .ui-guide-mod-num { background: var(--step); color: #fff; }

.ui-guide-main { min-width: 0; }
.ui-guide-lesson { max-width: 760px; display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-6); padding-bottom: var(--s-8); }
.ui-guide-hero { position: relative; overflow: hidden; padding: var(--s-7) var(--s-7) var(--s-6); border-radius: var(--r-panel); border: 1px solid var(--step-line); background: radial-gradient(120% 140% at 100% 0%, var(--step-soft), transparent 60%), linear-gradient(160deg, var(--step-soft), transparent 55%), var(--surface); }
.ui-guide-hero::after { content: ''; position: absolute; right: -70px; top: -70px; width: 230px; height: 230px; border-radius: 50%; background: var(--step); opacity: 0.12; pointer-events: none; }
.ui-guide-eyebrow { position: relative; z-index: 1; display: inline-flex; align-items: center; gap: 8px; padding: 5px 12px; border-radius: var(--r-pill); background: var(--step); color: #fff; font-size: 12px; font-weight: 700; letter-spacing: 0.04em; }
.ui-guide-title { position: relative; z-index: 1; margin: 14px 0 0; font-family: var(--font-head); font-size: clamp(26px, 3.2vw, 38px); line-height: 1.15; letter-spacing: -0.02em; color: var(--ink); text-wrap: balance; }
.ui-guide-meta { position: relative; z-index: 1; margin: 10px 0 0; color: var(--muted); font-size: 14px; font-weight: 600; }

.ui-guide-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-6); font-size: 18px; line-height: 1.7; color: var(--ink); }
.ui-guide-sec { display: grid; grid-template-columns: minmax(0, 1fr); gap: 18px; }
.ui-guide-sec.is-tint { padding: 26px 28px; border: 1px solid var(--step-line); border-radius: var(--r-panel); background: linear-gradient(160deg, color-mix(in srgb, var(--step) 10%, var(--surface)), color-mix(in srgb, var(--step) 4%, var(--surface))); }
.ui-guide-sec.is-tint .ui-guide-quote { background: var(--surface); }
.ui-guide-body p { margin: 0; }
.ui-guide-body strong { font-weight: 800; }
.ui-guide-h2 { display: flex; align-items: center; gap: 12px; margin: 6px 0 0; font-family: var(--font-head); font-size: clamp(21px, 2.2vw, 26px); line-height: 1.25; letter-spacing: -0.01em; color: var(--ink); }
.ui-guide-h2::before { content: ''; flex: none; width: 6px; height: 1.1em; border-radius: 3px; background: var(--step); }
.ui-guide-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 10px; }
.ui-guide-list li { position: relative; padding-left: 30px; }
.ui-guide-list li::before { content: ''; position: absolute; left: 6px; top: 0.62em; width: 9px; height: 9px; border-radius: 50%; background: var(--step); box-shadow: 0 0 0 4px var(--step-soft); }
.ui-guide-list.is-numbered { counter-reset: guide; }
.ui-guide-list.is-numbered li { counter-increment: guide; padding-left: 40px; }
.ui-guide-list.is-numbered li::before { content: counter(guide); left: 0; top: 0.18em; width: 26px; height: 26px; border-radius: 8px; display: grid; place-items: center; box-shadow: none; color: #fff; font-family: var(--font-head); font-size: 13px; font-weight: 800; line-height: 1; }
.ui-guide-quote { margin: 0; padding: 20px 24px 20px 26px; border-radius: var(--r-card); border-left: 5px solid var(--step); background: var(--step-soft); font-family: var(--font-head); font-size: 20px; font-weight: 600; line-height: 1.55; }
.ui-guide-quote p { margin: 0; }
.ui-guide-quote p + p { margin-top: 8px; }
.ui-guide-quote cite { display: block; margin-top: 10px; font-family: var(--font-body); font-size: 14px; font-style: normal; font-weight: 800; color: var(--step); }
.ui-guide-quote.is-sample { border: 1px dashed var(--step-line); border-left: 5px solid var(--step); background: var(--surface); font-family: var(--font-body); font-size: 16px; font-weight: 500; }

.ui-guide-figure { margin: 0; overflow: hidden; border: 1px solid var(--border); border-radius: var(--r-card); background: var(--sunken); }
.ui-guide-figure img { display: block; width: 100%; height: auto; }
.ui-guide-video { margin: 6px 0; display: grid; justify-items: center; gap: 12px; }
.ui-guide-phone { width: min(300px, 78vw); aspect-ratio: 9 / 16; padding: 8px; border-radius: 36px; background: var(--stage); box-shadow: 0 30px 60px -28px var(--step), 0 0 0 1px var(--border-2); }
.ui-guide-phone video { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 28px; background: var(--stage); }
.ui-guide-video figcaption { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: 13px; font-weight: 700; }
.ui-guide-gallery { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.ui-guide-gallery .ui-guide-figure { box-shadow: var(--shadow-1); transition: transform 0.2s var(--ease), box-shadow 0.2s; }
.ui-guide-gallery .ui-guide-figure:hover { transform: translateY(-3px); box-shadow: var(--shadow-2); }

.ui-guide-videos { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.ui-guide-videos .ui-guide-phone { width: 100%; max-width: 260px; }
.ui-guide-videos figcaption { color: var(--muted); font-size: 13px; font-weight: 600; line-height: 1.45; text-align: center; }
.ui-guide-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }
.ui-guide-stat { display: grid; gap: 4px; align-content: start; padding: 16px 18px; border: 1px solid var(--step-line); border-radius: 14px; background: var(--surface); }
.ui-guide-stat b { font-family: var(--font-head); font-size: clamp(24px, 3vw, 32px); line-height: 1.1; letter-spacing: -0.02em; color: var(--step); }
.ui-guide-stat span { color: var(--muted); font-size: 14px; line-height: 1.4; }
.ui-guide-compare { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.ui-guide-compare-col { --opt: var(--good); padding: 16px 18px; border: 2px solid var(--opt); border-radius: 14px; background: color-mix(in srgb, var(--opt) 7%, var(--surface)); }
.ui-guide-compare-col.is-left { --opt: var(--bad); }
.ui-guide-compare-col h3 { margin: 0 0 10px; color: var(--opt); font-family: var(--font-head); font-size: 16px; line-height: 1.3; }
.ui-guide-compare-col ul { margin: 0; padding: 0 0 0 18px; display: grid; gap: 6px; font-size: 15.5px; line-height: 1.5; }
.ui-guide-compare-col li::marker { color: var(--opt); }
.ui-guide-note { display: flex; gap: 10px; align-items: flex-start; margin: 0; padding: 12px 16px; border: 1px dashed var(--border-2); border-radius: 12px; background: var(--sunken); color: var(--muted); font-size: 15px; line-height: 1.5; }
.ui-guide-note > .ic { flex: none; margin-top: 3px; color: var(--step); }
.ui-guide-path { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.ui-guide-path li > a { display: flex; align-items: center; gap: 12px; padding: 10px 14px; border: 1px solid var(--border); border-radius: 14px; background: var(--surface); color: var(--ink); font-size: 16px; line-height: 1.4; text-decoration: none; transition: border-color 0.15s, background 0.15s; }
.ui-guide-path li > a:hover { border-color: var(--step-line); background: var(--step-soft); }
.ui-guide-path-num { flex: none; width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center; background: var(--step); color: #fff; font-family: var(--font-head); font-size: 14px; font-weight: 800; }
.ui-guide-path-icon { flex: none; display: grid; color: var(--step); }

.ui-guide-flow { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; padding: 20px 16px; border: 1px solid var(--border); border-radius: var(--r-card); background: var(--sunken); }
.ui-guide-flow-step { display: flex; align-items: center; }
.ui-guide-flow-card { display: grid; justify-items: center; gap: 8px; min-width: 124px; padding: 16px 14px; border: 1px solid var(--step-line); border-radius: 14px; background: var(--surface); font-size: 15px; text-align: center; }
.ui-guide-flow-icon { width: 44px; height: 44px; border-radius: 13px; display: grid; place-items: center; background: var(--step-soft); color: var(--step); }
.ui-guide-flow-arrow { display: grid; justify-items: center; gap: 4px; padding: 0 10px; color: var(--step); }
.ui-guide-flow-arrow em { padding: 2px 8px; border-radius: var(--r-pill); background: var(--good-soft); color: var(--good); font-size: 11px; font-style: normal; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; }

.ui-guide-choice { display: grid; gap: 14px; padding: var(--s-6); border: 1px solid var(--border); border-radius: var(--r-panel); background: var(--surface); box-shadow: var(--shadow-1); }
.ui-guide-choice-title { margin: 0; font-family: var(--font-head); font-size: 22px; color: var(--ink); }
.ui-guide-options { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
/* Always red for "by hand", green for "on autopilot" (Eric 2026-10-21). */
.ui-guide-option { --opt: var(--good); display: flex; align-items: flex-start; gap: 12px; padding: 16px; border: 2px solid var(--opt); border-radius: 14px; background: color-mix(in srgb, var(--opt) 8%, var(--surface)); color: var(--ink); font-size: 16px; line-height: 1.5; cursor: pointer; transition: background 0.15s, box-shadow 0.15s, transform 0.15s var(--ease); }
.ui-guide-option.is-hand { --opt: var(--bad); }
.ui-guide-option strong { color: var(--opt); }
.ui-guide-option:hover { transform: translateY(-1px); box-shadow: 0 10px 24px -16px var(--opt); }
.ui-guide-option.on { background: color-mix(in srgb, var(--opt) 22%, var(--surface)); box-shadow: 0 0 0 3px color-mix(in srgb, var(--opt) 30%, transparent); }
.ui-guide-option .ui-check { width: 20px; height: 20px; margin-top: 3px; accent-color: var(--opt); }
.ui-guide-option:has(:focus-visible) { outline: 2px solid var(--opt); outline-offset: 2px; }
.ui-guide-choice-note { margin: 0; color: var(--faint); font-size: 13px; }

.ui-guide-pager { display: flex; gap: 12px; align-items: stretch; }
.ui-guide-prev,
.ui-guide-next { display: flex; align-items: center; gap: 14px; min-height: 76px; padding: 14px 18px; border-radius: var(--r-card); color: var(--ink); text-decoration: none; transition: background 0.15s, transform 0.15s var(--ease), box-shadow 0.15s; }
.ui-guide-prev { flex: none; border: 2px solid var(--border-2); background: var(--raised); }
.ui-guide-prev:hover { background: var(--chip); transform: translateY(-1px); }
.ui-guide-next { --next: var(--step-10); flex: 1; min-width: 0; justify-content: space-between; border: 2px solid var(--next); background: color-mix(in srgb, var(--next) 12%, var(--surface)); box-shadow: 0 14px 30px -22px var(--next); }
.ui-guide-next:hover { background: color-mix(in srgb, var(--next) 20%, var(--surface)); transform: translateY(-1px); }
.ui-guide-prev:focus-visible,
.ui-guide-next:focus-visible { outline: 2px solid var(--step-10); outline-offset: 2px; }
.ui-guide-next-text { display: grid; gap: 3px; min-width: 0; }
.ui-guide-next-text small { font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.ui-guide-next-text b { font-family: var(--font-head); font-size: 18px; line-height: 1.25; }
.ui-guide-next-go { flex: none; width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center; background: var(--next); color: #fff; }
.ui-guide-founder { display: grid; gap: 12px; padding: 18px 20px; border: 1px solid var(--border); border-radius: var(--r-card); background: var(--surface); }
.ui-guide-founder-q { margin: 0; color: var(--ink); font-size: 16px; font-weight: 700; }
.ui-guide-founder-btns { display: flex; flex-wrap: wrap; gap: 10px; }
.ui-guide-sign { margin: 0; color: var(--muted); font-family: var(--font-head); font-size: 22px; font-weight: 700; }

@media (max-width: 900px) {
  .ui-guide { grid-template-columns: minmax(0, 1fr); gap: var(--s-4); }
  .ui-guide-side { top: calc(var(--nav-h) + 6px); z-index: 20; max-height: none; overflow: visible; padding: 0; }
  .ui-guide-brand { display: none; }
  .ui-guide-phonebar { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 48px; padding: 8px 14px; border: 1px solid var(--step-line); border-radius: var(--r-card); background: var(--surface); box-shadow: var(--shadow-2); color: var(--ink); font: inherit; font-size: 14px; font-weight: 700; text-align: left; cursor: pointer; }
  .ui-guide-phonebar > .ic { flex: none; color: var(--faint); transition: transform 0.2s var(--ease); }
  .ui-guide-side[data-phone-open="true"] .ui-guide-phonebar > .ic { transform: rotate(90deg); }
  .ui-guide-phonebar-num { flex: none; min-width: 34px; height: 26px; padding: 0 6px; border-radius: 8px; display: grid; place-items: center; background: var(--step); color: #fff; font-family: var(--font-head); font-size: 12px; font-weight: 800; }
  .ui-guide-phonebar-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ui-guide-menu { display: none; }
  .ui-guide-side[data-phone-open="true"] .ui-guide-menu { position: absolute; left: 0; right: 0; top: calc(100% + 6px); display: grid; max-height: 70vh; overflow-y: auto; padding: 10px; border: 1px solid var(--border-2); border-radius: var(--r-card); background: var(--raised); box-shadow: var(--shadow-2); }
  .ui-guide-hero { padding: var(--s-5); }
  .ui-guide-body { font-size: 17px; }
  .ui-guide-sec.is-tint { padding: 20px 18px; }
  .ui-guide-options { grid-template-columns: minmax(0, 1fr); }
  .ui-guide-compare { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 560px) {
  .ui-guide-flow, .ui-guide-flow-step { flex-direction: column; }
  .ui-guide-flow-arrow { padding: 8px 0; }
  .ui-guide-flow-arrow .ic { transform: rotate(90deg); }
  .ui-guide-gallery { gap: 8px; }
  .ui-guide-quote { font-size: 18px; }
  .ui-guide-prev { gap: 8px; padding: 14px 12px; }
  .ui-guide-prev .ui-guide-next-text small { display: none; }
  .ui-guide-next { padding: 14px 14px 14px 16px; }
  .ui-guide-next-text b { font-size: 16px; }
}


/* guide-export frame (bin/guide-export.mjs): the sales site has no app nav, so the guide brings its own bar,
   fixed and one row high at every width, like the app's .ui-nav. .ui-page keeps the app's own width and the room
   under the bar (--nav-h). */
:root { --nav-h: 56px; }
.gx-top { position: fixed; top: 0; left: 0; right: 0; z-index: 600; height: var(--nav-h); box-sizing: border-box; display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 0 max(16px, calc((100vw - 1120px) / 2)); background: color-mix(in srgb, var(--surface) 82%, transparent); backdrop-filter: blur(24px) saturate(1.6); -webkit-backdrop-filter: blur(24px) saturate(1.6); border-bottom: 1px solid var(--border); }
.gx-brand { display: inline-flex; align-items: center; gap: 10px; color: var(--ink); text-decoration: none; font-family: var(--font-display, Sora, sans-serif); }
.gx-brand img { border-radius: 8px; }
.gx-langs { display: inline-flex; gap: 6px; }
.gx-langs a { padding: 6px 10px; border-radius: 10px; border: 1px solid var(--border); color: var(--ink-2, var(--ink)); text-decoration: none; font-weight: 600; font-size: 13px; }
.gx-langs a[aria-current="page"] { color: var(--ink); border-color: var(--accent-1); }
.ui-guide-mod-list[hidden] { display: none; }
