/* Landing page styles. Theme tokens come from web/themes.css — see
   web/tests/landing-tokens.test.mjs for why nothing here may re-declare them.
   This file owns only the marketing-only tokens the landing page needs on top
   of the app's own --paper*, --ink*, --amber*, --rule, --ff-*, --glass-fill*
   token set: handwritten-annotation ("note"), inverted-panel/CTA, ambient
   "blob" gradients, and the extra glass layers beyond the two styles.css
   already defines.

   Ported from the design handoff's <helmet><style> block (lines 31-142 of
   design_handoff_dynamic_juno_landing 2/Dynamic Juno - Landing Page.dc.html),
   taking ONLY the marketing-only properties — never the theme-owned ones,
   which the app already defines correctly in web/themes.css / web/styles.css. */

:root {
  /* the handwritten annotation layer */
  --note:        oklch(58% 0.09 250);
  --note-2:      oklch(45% 0.11 250);
  --note-3:      oklch(52% 0.1 250);
  --note-line:   oklch(70% 0.09 250);
  /* secondary accent (Scholar surfaces) */
  --scholar:      oklch(52% 0.06 250);
  --scholar-line: oklch(85% 0.05 250);
  --scholar-soft: oklch(94% 0.03 250 / 0.8);
  /* shadows derive from --shade, never black */
  --shade: oklch(30% 0.02 70);
  /* glass beyond the two tokens styles.css already owns */
  --glass-fill-2: oklch(from var(--paper) l c h / 0.55);
  --glass-fill-3: oklch(from var(--paper) l c h / 0.7);
  --glass-hair:   oklch(100% 0 0 / 0.42);
  --glass-sheen:  oklch(100% 0 0 / 0.25);
  /* inverted panel + buttons */
  --panel-bg: var(--ink);      --panel-ink: var(--paper);
  /* Amber accent for text on the inverted panel. Marketing-only, like the rest
     of the --panel-* family. It has to be its own token because this panel is
     kept DARK in every theme (the dark-theme group below repoints --panel-bg at
     --paper-3), whereas --amber-on-ink follows --ink and therefore flips to a
     dark amber on obsidian/embers/pitch — correct for the tutorial tooltips,
     wrong here. Aliasing resolves per theme because :root and [data-theme] both
     match <html>, so this is not the bake-at-root relative-colour trap. */
  --panel-accent: var(--amber-on-ink);
  --panel-ink-2: oklch(from var(--paper) 78% 0.012 72);
  --panel-rule:  oklch(from var(--ink) 40% c h);
  --chip-ink: var(--paper);
  --cta-bg: var(--ink);        --cta-ink: var(--paper);
  --oncta-bg: var(--amber);    --oncta-ink: var(--paper);
  /* ambient blooms */
  --blob-a: oklch(62% 0.14 55); --blob-b: oklch(52% 0.08 105);
  --blob-c: oklch(55% 0.09 320); --blob-d: oklch(52% 0.08 240);
  --blob-op: .16;
  /* Task 9 (#try / agent drawer) compat aliases. hub.js is intentionally
     unmodified and its inline styles still reference the pre-revamp token
     vocabulary (accent, border, border-2, ink-4) instead of this page's
     amber/rule/rule-soft/ink-muted names. None of the four below are in
     landing-tokens.test.mjs's THEME_OWNED list (only the bare --ink,
     --ink-2, --ink-3, --ink-muted, --ink-faint, --amber names are guarded,
     not these) — they alias, never redeclare, real values, same pattern
     as every other token in this block. --accent doubles as the ambient
     fallback for [data-accent] elements outside a lifted subtree (e.g. the
     try-it reply's "Reply to {agent}" link); liftSpecialistAccents' own
     inline --accent, set directly on the element, still wins wherever it
     applies. */
  --accent:   var(--amber);
  --border:   var(--rule);
  --border-2: var(--rule-soft);
  --ink-4:    var(--ink-muted);
}

/* ---------- per-theme marketing-token overrides ----------
   Each block below reads theme-owned tokens (--paper*, --ink*, --amber*,
   --rule) via var() but never declares them — those stay owned by
   web/themes.css. manuscript has no marketing-only overrides in the
   prototype, so it inherits the :root values above unchanged. */

[data-theme="birch"] {
  --blob-a: oklch(52% 0.1 155); --blob-b: oklch(55% 0.08 120);
  --blob-c: oklch(52% 0.07 190); --blob-d: oklch(50% 0.07 160);
}

[data-theme="slate"] {
  --note: oklch(48% 0.1 25); --note-2: oklch(44% 0.13 28);
  --note-3: oklch(50% 0.12 26); --note-line: oklch(72% 0.1 28);
  --blob-a: oklch(52% 0.16 248); --blob-b: oklch(55% 0.1 210);
  --blob-c: oklch(52% 0.1 285); --blob-d: oklch(50% 0.09 240);
}

[data-theme="dusk"] {
  --shade: oklch(10% 0.01 55);
  --blob-a: oklch(73% 0.16 45); --blob-b: oklch(64% 0.18 12);
  --blob-c: oklch(55% 0.16 300); --blob-d: oklch(58% 0.17 335);
  --blob-op: .13;
}

/* Shared dark-theme group. --glass-border also drops to
   oklch(100% 0 0 / 0.14) on these themes in the prototype; since
   styles.css owns that token, we accept the light value here rather than
   shadowing it. Raise with the app's design owner if that's wrong. */
[data-theme="obsidian"], [data-theme="embers"], [data-theme="pitch"] {
  --shade: oklch(4% 0.02 50);
  --glass-hair: oklch(100% 0 0 / 0.08);
  --glass-sheen: oklch(100% 0 0 / 0.06);
  --panel-bg: var(--paper-3);  --panel-ink: var(--ink);
  /* --panel-bg is --paper-3 here, which is DARK on these themes, so the accent
     must stay the LIGHT --amber-2 (8.31 / 9.92 / 13.27:1) rather than following
     --amber-on-ink, which darkens for the light --ink band. */
  --panel-accent: var(--amber-2);
  --panel-ink-2: var(--ink-2); --panel-rule: var(--rule);
  --chip-ink: var(--paper-3);
  --cta-bg: var(--amber);      --cta-ink: var(--paper-3);
  --oncta-bg: var(--amber);    --oncta-ink: var(--paper-3);
  --note: oklch(74% 0.11 250); --note-2: oklch(81% 0.1 250);
  --note-3: oklch(77% 0.1 250); --note-line: oklch(58% 0.11 250);
  --blob-op: .17;
}

[data-theme="obsidian"] {
  --scholar: oklch(72% 0.1 250); --scholar-line: oklch(45% 0.1 250);
  --scholar-soft: oklch(30% 0.08 250 / 0.8);
  --note: oklch(78% 0.12 150); --note-2: oklch(84% 0.11 150);
  --note-3: oklch(80% 0.11 150); --note-line: oklch(58% 0.12 150);
  --blob-a: oklch(66% 0.22 254); --blob-b: oklch(60% 0.16 210);
  --blob-c: oklch(58% 0.18 300); --blob-d: oklch(62% 0.16 240);
}

[data-theme="embers"] {
  --scholar: oklch(74% 0.1 250); --scholar-line: oklch(46% 0.1 250);
  --scholar-soft: oklch(28% 0.08 250 / 0.85);
  --blob-a: oklch(70% 0.2 78); --blob-b: oklch(62% 0.19 40);
  --blob-c: oklch(55% 0.16 20); --blob-d: oklch(58% 0.14 100);
}

[data-theme="pitch"] {
  --scholar: oklch(72% 0.09 250); --scholar-line: oklch(44% 0.09 250);
  --scholar-soft: oklch(26% 0.07 250 / 0.85);
  --blob-a: oklch(70% 0.05 74); --blob-b: oklch(60% 0.04 120);
  --blob-c: oklch(58% 0.05 300); --blob-d: oklch(60% 0.05 240);
  --blob-op: .14;
}

/* ============================================================
   Fonts — self-hosted (Task 3 Step 4).
   All 5 families are variable fonts on Google's end: requesting
   several weights in one CSS2 query returned the SAME woff2 URL for
   every weight in a family (confirmed by fetching the real Google
   Fonts CSS with a desktop UA — see task-3-report.md). Each block
   below reproduces that: multiple discrete font-weight declarations
   pointing at one shared local file, exactly like Google's own CSS.
   Weights actually used by the page only (Caveat ships 400/500, not
   600 — nothing in the design calls for a 600 weight of it). ============================================================ */
@font-face { font-family: 'Newsreader'; font-style: normal; font-weight: 400; font-display: swap; src: url('fonts/newsreader-400.woff2') format('woff2'); }
@font-face { font-family: 'Newsreader'; font-style: normal; font-weight: 500; font-display: swap; src: url('fonts/newsreader-400.woff2') format('woff2'); }
@font-face { font-family: 'Newsreader'; font-style: italic; font-weight: 400; font-display: swap; src: url('fonts/newsreader-400-italic.woff2') format('woff2'); }
@font-face { font-family: 'Newsreader'; font-style: italic; font-weight: 500; font-display: swap; src: url('fonts/newsreader-400-italic.woff2') format('woff2'); }
@font-face { font-family: 'Inter Tight'; font-style: normal; font-weight: 400; font-display: swap; src: url('fonts/inter-tight.woff2') format('woff2'); }
@font-face { font-family: 'Inter Tight'; font-style: normal; font-weight: 500; font-display: swap; src: url('fonts/inter-tight.woff2') format('woff2'); }
@font-face { font-family: 'Inter Tight'; font-style: normal; font-weight: 600; font-display: swap; src: url('fonts/inter-tight.woff2') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url('fonts/jetbrains-mono.woff2') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 500; font-display: swap; src: url('fonts/jetbrains-mono.woff2') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 600; font-display: swap; src: url('fonts/jetbrains-mono.woff2') format('woff2'); }
@font-face { font-family: 'Caveat'; font-style: normal; font-weight: 400; font-display: swap; src: url('fonts/caveat.woff2') format('woff2'); }
@font-face { font-family: 'Caveat'; font-style: normal; font-weight: 500; font-display: swap; src: url('fonts/caveat.woff2') format('woff2'); }
@font-face { font-family: 'Cormorant Garamond'; font-style: normal; font-weight: 400; font-display: swap; src: url('fonts/cormorant-garamond-400.woff2') format('woff2'); }
@font-face { font-family: 'Cormorant Garamond'; font-style: normal; font-weight: 500; font-display: swap; src: url('fonts/cormorant-garamond-400.woff2') format('woff2'); }
@font-face { font-family: 'Cormorant Garamond'; font-style: italic; font-weight: 400; font-display: swap; src: url('fonts/cormorant-garamond-400-italic.woff2') format('woff2'); }

/* ============================================================
   Base / reset (prototype lines 143-152, minus the theme-shift
   transition rule — that lands in Task 4 alongside the JS that
   sets/removes data-theme-shift).

   home.html loads web/styles.css BEFORE themes.css (see task-3-report.md,
   plan defect #2): themes.css's own header says it must load AFTER
   styles.css and only overrides what changes per theme, so --ff-ui,
   --ff-mono, --glass-fill, --glass-border, --r-*, --z-*, --shadow-sm
   and the "paper" default theme's tokens all come from styles.css's
   bare :root and simply do not exist without that link. This file
   still declares none of them (the guard test forbids it) — it only
   RESETS/OVERRIDES a few, same as the prototype did against its own
   design-system bundle. font-size:16px below is one such override:
   styles.css sets body to calc(14px * var(--text-scale,1)) for the
   app shell; this page's clamp()/em sizing assumes the browser
   default of 16px, and landing.css loads last so it wins. ============================================================ */
html, body, #root { height: auto; min-height: 100%; }
body {
  margin: 0;
  background: var(--paper);
  font-family: var(--ff-ui);
  font-size: 16px;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}
/* styles.css paints a fixed full-viewport noise texture behind the app shell
   (mix-blend-mode:multiply). The prototype explicitly turns it off in favour
   of its own blob layer — themes.css only zeroes it on 5 of 8 themes, so
   without this it would still show through on paper/manuscript/birch. */
body::before { display: none; }
/* Bare element/pseudo selectors, NOT scoped under .landing — matches the
   prototype's own approach (its lines 146-148 are bare too) and is load-bearing
   here, not just style: a ".landing a" ancestor-scoped version has specificity
   (0,1,1), which beats every single-class component rule below it in the
   cascade (.landing-btn, .landing-link, .landing-cta__link, .landing-nav__login,
   .landing-drawer__login are all (0,1,0)) — that exact mistake shipped once
   during this task's own build and rendered every CTA button ink-on-ink
   (color fell through to inherited --ink against a --cta-bg button
   background), confirmed via getComputedStyle before this fix. Author-origin
   rules already beat the UA stylesheet's default link color/underline
   regardless of specificity, so scoping bought nothing and cost this. */
a { color: inherit; text-decoration: none; }
a:hover { color: var(--amber); }
::selection { background: oklch(from var(--amber) l c h / .22); }

/* Theme cross-fade (Task 4). Scoped to a 1300ms window via the data-theme-shift
   attribute — landing.js sets it, then clears it on a timer — rather than left on
   permanently, which would make every button press feel laggy. Gated behind
   prefers-reduced-motion in the JS that sets the attribute (it is simply never
   set), with a CSS-level backstop in the reduced-motion block below. */
html[data-theme-shift] *,
html[data-theme-shift] *::before,
html[data-theme-shift] *::after {
  transition: background-color 1100ms cubic-bezier(.4,0,.2,1),
              background-image 1100ms cubic-bezier(.4,0,.2,1),
              color            1100ms cubic-bezier(.4,0,.2,1),
              border-color     1100ms cubic-bezier(.4,0,.2,1),
              fill             1100ms cubic-bezier(.4,0,.2,1),
              stroke           1100ms cubic-bezier(.4,0,.2,1),
              box-shadow       1100ms cubic-bezier(.4,0,.2,1);
}

@keyframes djBloomA { 0%,100% { transform: translate(0,0) scale(1); } 50% { transform: translate(28px,-22px) scale(1.12); } }
@keyframes djBloomB { 0%,100% { transform: translate(0,0) scale(1.06); } 50% { transform: translate(-30px,18px) scale(0.94); } }
@keyframes djCaret  { 0%,100% { opacity: 1; } 50% { opacity: 0; } }
@keyframes djBounce { 0%,80%,100% { transform: translateY(0); opacity:.45 } 40% { transform: translateY(-4px); opacity:1 } }
/* Task 9: #try-result's entrance + the agent drawer's staged reveal
   (.drawer-step/.drawer-step--typing use per-instance animation-delay,
   already inline on the elements hub.js renders — these two keyframes
   supply only the name/duration/timing/fill-mode each rule needs). */
@keyframes djReveal { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: translateY(0); } }
@keyframes djTypingPulse { 0% { opacity: 0; transform: translateY(6px); } 22% { opacity: 1; transform: none; } 78% { opacity: 1; } 100% { opacity: 0; transform: translateY(-4px); } }

/* ============================================================
   Layout shell (prototype lines 237-246)
   ============================================================ */
.landing-page { position: relative; min-height: 100vh; background: var(--paper); overflow-x: clip; }

.landing-blobs { position: fixed; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
.landing-blob { position: absolute; border-radius: 50%; opacity: var(--blob-op); filter: blur(130px); }
.landing-blob--a { width: 640px; height: 640px; background: var(--blob-a); top: -200px; left: -140px; animation: djBloomA 15s ease-in-out infinite; }
.landing-blob--b { width: 520px; height: 520px; background: var(--blob-b); top: 8%; right: -160px; animation: djBloomB 19s ease-in-out infinite; }
.landing-blob--c { width: 520px; height: 520px; background: var(--blob-c); bottom: -10%; left: 12%; filter: blur(125px); animation: djBloomB 17s ease-in-out infinite; }
.landing-blob--d { width: 560px; height: 560px; background: var(--blob-d); bottom: -220px; right: 8%; filter: blur(135px); animation: djBloomA 21s ease-in-out infinite; }

.landing-stack { position: relative; z-index: 1; }

/* Task 10 (a11y sweep): anchor-jump targets clip under the 59px sticky nav
   without this — cosmetic only (headings stay clear of the fold), but every
   section root carries data-sec, so one selector covers every #hash link
   the nav/drawer/footer point at. */
[data-sec] { scroll-margin-top: 72px; }

/* Task 10 (a11y sweep): visible keyboard focus. Deliberately bare selectors,
   not `.landing a:focus-visible` etc. — the mobile drawer, theme dock and
   agent drawer are all rendered OUTSIDE .landing/.landing-page (see each of
   their own "containing-block" comments below), so a `.landing`-scoped
   selector would silently miss every focusable control in those three
   overlays. landing.css is only ever loaded by home.html (nothing else
   links it), so page-bare selectors are exactly as safe here as the `a`/
   `::selection` rules above already are — same reasoning, same file.
   Second deviation from the brief's own worked snippet: it also set
   border-radius:4px here, but that's a property of the ELEMENT, not the
   outline, and this rule's specificity beats every component class below
   it (`[role="radio"]:focus-visible` (0,2,0) > `.landing-dock__swatch`
   (0,1,0); `button:focus-visible` (0,1,1) > `.landing-btn` (0,1,0)) — so it
   was clobbering the swatch's 999px circle to a 4px square, and every
   button's own radius, for as long as it held focus. Confirmed via
   getComputedStyle(swatch).borderRadius flipping 999px -> 4px on focus.
   Outlines already follow the element's own border-radius automatically in
   every current browser, so dropping this line costs nothing and fixes it. */
a:focus-visible,
button:focus-visible,
[role="radio"]:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 2px;
}

/* Shared section-inner wrapper (prototype data-r="wrap", reused by types,
   studio, how, product and pricing — product layers .landing-product__wrap
   on top of it for its extra flex properties). */
.landing-wrap { max-width: 1180px; margin: 0 auto; padding: 84px 32px; }
.landing-section-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 40px; }
.landing-section-head__kicker { font-family: var(--ff-mono); font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--amber); margin-bottom: 14px; }
.landing-section-head__title { font-family: var(--ff-display); font-weight: 500; font-size: clamp(30px,3.6vw,46px); line-height: 1.05; letter-spacing: -0.018em; margin: 0; }
.landing-section-desc { font-size: 15.5px; line-height: 1.6; color: var(--ink-muted); max-width: 28em; margin: 0; text-wrap: pretty; }
.landing-caption { font-family: 'Caveat', cursive; font-size: 21px; line-height: 1.28; color: var(--note-2); margin: 0; }

/* Desktop/mobile copy swap (prototype data-only="d"/"m"). Desktop is the
   default; the 768px breakpoint below flips both. */
.landing-only-mobile { display: none; }

/* Shared hand-annotation note (Caveat + a small curved arrow SVG). Always
   rendered for now — the prototype's sc-if annotations toggle is a design-tool
   prop, not page behaviour, so there is nothing to make conditional. */
.landing-note { display: flex; align-items: flex-start; gap: 12px; margin-top: 14px; padding-left: 6px; }
.landing-note--end { justify-content: flex-end; padding-left: 0; padding-right: 4px; }
.landing-note__svg { width: 44px; height: 34px; flex: none; margin-top: 6px; }
.landing-note--end .landing-note__svg { width: 40px; height: 30px; margin-top: 4px; }
.landing-note__text { font-family: 'Caveat', cursive; font-size: 23px; line-height: 1.28; color: var(--note-2); transform: rotate(-1deg); margin: 0; }
.landing-note--end .landing-note__text { font-size: 20px; line-height: 1.26; text-align: right; transform: none; }
.landing-note__underline { text-decoration: underline; text-decoration-color: var(--note-line); text-underline-offset: 4px; }

/* Reusable pill buttons + underlined text links (prototype's repeated
   inline CTA style, e.g. lines 259, 286-287, 647-648). */
.landing-btn { display: inline-flex; align-items: center; gap: 7px; padding: 9px 16px;
  background: var(--cta-bg); color: var(--cta-ink); border-radius: 6px; font-size: 13.5px; font-weight: 500; }
.landing-btn--lg { padding: 14px 24px; border-radius: 7px; font-size: 15px; }
.landing-btn--onCta { background: var(--oncta-bg); color: var(--oncta-ink); }
.landing-link { display: inline-flex; align-items: center; gap: 7px; font-size: 15px; color: var(--ink-2);
  border-bottom: 1px solid var(--rule); padding-bottom: 2px; }

/* ============================================================
   Sticky nav (prototype lines 248-267)
   ============================================================ */
.landing-nav { position: sticky; top: 0; z-index: 40; background: var(--glass-fill);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border-bottom: 1px solid var(--glass-border);
  box-shadow: var(--glass-glow); }
.landing-nav__inner { display: flex; align-items: center; gap: 20px; padding: 14px 32px; max-width: 1180px; margin: 0 auto; }
.landing-nav__brand { position: relative; display: flex; align-items: center; gap: 9px; flex: none; white-space: nowrap; }
.landing-nav__logo { height: 16px; width: auto; display: block; flex-shrink: 0; }
.landing-nav__name { font-family: var(--ff-display); font-size: 18px; font-weight: 500; letter-spacing: -0.01em; }
.landing-nav__links { margin-left: 8px; display: flex; align-items: center; gap: 14px; font-size: 13.5px; color: var(--ink-2); white-space: nowrap; }
.landing-nav__actions { margin-left: auto; display: flex; align-items: center; gap: 16px; white-space: nowrap; flex: none; }
.landing-nav__login { font-size: 13.5px; color: var(--ink-2); }
.landing-burger { display: none; flex-direction: column; align-items: center; justify-content: center; gap: 4.5px;
  width: 38px; height: 38px; padding: 0; background: none; border: 1px solid var(--rule); border-radius: 8px; cursor: pointer; }
.landing-burger__bar { display: block; width: 16px; height: 1.6px; background: var(--ink); }

/* ============================================================
   Hero (prototype lines 268-340)
   ============================================================ */
.landing-hero { max-width: 1180px; margin: 0 auto; padding: 78px 32px 66px; display: flex; flex-wrap: wrap; gap: 56px; align-items: center; }
.landing-hero__text { flex: 1 1 440px; min-width: 320px; position: relative; }
.landing-hero__kicker { font-family: var(--ff-mono); font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-faint); margin-bottom: 22px; }
.landing-hero__title { font-family: var(--ff-display); font-weight: 500; font-size: clamp(40px,5.6vw,74px); line-height: 1.01; letter-spacing: -0.022em; margin: 0; }
.landing-hero__title-em { display: block; font-style: italic; color: var(--amber); font-size: clamp(58px,8.4vw,110px); line-height: 1; margin-top: 4px; }
.landing-hero__lead { font-size: clamp(16px,1.3vw,18.5px); line-height: 1.6; color: var(--ink-3); max-width: 31em; margin: 26px 0 0; text-wrap: pretty; }
.landing-hero__lead--mobile { font-size: 16.5px; line-height: 1.58; color: var(--ink-3); margin: 22px 0 0; text-wrap: pretty; }
.landing-hero__ctas { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; margin-top: 34px; }
.landing-hero__meta { font-family: var(--ff-mono); font-size: 11.5px; color: var(--ink-faint); margin-top: 26px; }
.landing-hero__demo { flex: 1 1 384px; min-width: 300px; position: relative; }

.landing-demo { background: var(--glass-fill); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border); border-radius: 13px;
  box-shadow: 0 2px 4px oklch(from var(--shade) l c h / .06), 0 30px 60px oklch(from var(--shade) l c h / .1);
  overflow: hidden; }
.landing-demo__bar { display: flex; align-items: center; gap: 9px; padding: 12px 16px; border-bottom: 1px solid var(--glass-hair); }
.landing-demo__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--amber); animation: djCaret 1.9s ease-in-out infinite; }
.landing-demo__label { font-family: var(--ff-mono); font-size: 10.5px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--ink-muted); }
.landing-demo__meta { margin-left: auto; font-family: var(--ff-mono); font-size: 10.5px; color: var(--ink-faint); }
.landing-demo__body { padding: 20px 18px; display: flex; flex-direction: column; gap: 16px; min-height: 248px; }
.landing-demo__row { display: flex; gap: 10px; align-items: center; }
.landing-demo__row--start { align-items: flex-start; }
.landing-demo__row--end { justify-content: flex-end; }
.landing-demo__bubble { padding: 10px 13px; border-radius: 11px 11px 3px 11px; font-family: var(--ff-display); font-size: 14.5px; line-height: 1.45; max-width: 84%; }
.landing-demo__bubble--you { background: var(--panel-bg); color: var(--panel-ink); }
.landing-demo__bubble--agent { background: linear-gradient(180deg, oklch(from var(--amber) l c h / 0.08), transparent), var(--glass-fill-2);
  border: 1px solid var(--glass-border); border-radius: 3px 11px 11px 11px; font-size: 14px; color: var(--ink-2); max-width: 88%; }
.landing-demo__avatar { flex-shrink: 0; width: 28px; height: 28px; border-radius: 6px; display: flex; align-items: center; justify-content: center;
  font-family: var(--ff-mono); font-size: 8.5px; font-weight: 600; color: var(--chip-ink); }
.landing-demo__avatar--you { background: var(--panel-bg); }
.landing-demo__avatar--co { background: var(--ink-3); }
/* Task 10 (a11y sweep): was a bare oklch(48% 0.08 25) literal — prototype-faithful,
   but a real gap: it passed AA against --paper on manuscript (5.94) and failed on
   pitch (2.29) / obsidian (2.02), because nothing lifted it on dark themes the way
   liftSpecialistAccents already lifts every specialist chip. data-accent (added on
   the element in home.html) puts it through that same mechanism instead of hard-coding
   a second dark palette; oklch(48% 0.08 25) below is only the pre-JS/no-JS fallback. */
.landing-demo__avatar--writer { background: var(--accent, oklch(48% 0.08 25)); }
.landing-demo__step-label { font-size: 12.5px; color: var(--ink-muted); }
.landing-demo__step-label--mono { font-family: var(--ff-mono); font-size: 11px; color: var(--ink-muted); }
.landing-demo__route { display: flex; align-items: center; gap: 5px; }
.landing-demo__chip { font-family: var(--ff-mono); font-size: 10.5px; padding: 2px 7px; border-radius: 4px; }
.landing-demo__chip--world { background: oklch(from var(--paper) l 0.03 180 / 0.8); color: oklch(from var(--ink) l 0.08 180); }
.landing-demo__chip--writer { background: oklch(from var(--paper) l 0.035 25 / 0.8); color: oklch(from var(--ink) l 0.08 25); }
.landing-demo__chip--reader { background: oklch(from var(--paper) l 0.03 50 / 0.8); color: oklch(from var(--ink) l 0.07 50); }
.landing-demo__arrow { color: var(--ink-faint); font-size: 11px; }
.landing-demo__typing { display: inline-flex; gap: 4px; padding-left: 2px; }
.landing-demo__typing-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ink-faint); animation: djBounce 1.1s infinite ease-in-out; }
.landing-demo__caption { text-align: center; font-family: var(--ff-mono); font-size: 10.5px; color: var(--ink-faint); margin-top: 14px; letter-spacing: 0.04em; }

/* ============================================================
   Try it now (#try) — Task 9. Task 3 carried this section's markup and
   web/marketing/hub.js's #agent-drawer shell forward verbatim and UNstyled
   (no landing-* classes), specifically so marketing-smoke.mjs's #try-input/
   #try-chips/#try-result .try-msg/#agent-drawer.is-open assertions kept
   passing across every intervening task. This is the re-skin pass; the
   markup and hub.js's behaviour (classify/doRoute/resultHtml/REPLIES/
   TRY_PROMPTS/DEFAULT_CHIPS) are unchanged.

   The classes below (.section--alt/.section__inner/.mono-label/.serif-h2/
   .section__desc, .try-*, .chip-btn*) are home.html's/hub.js's own
   pre-existing vocabulary, not landing-* BEM names, and none of them are
   used anywhere else in this file or home.html — restyled here in place
   rather than renamed, per the brief ("you may add classes, you may not
   rename or remove" the smoke-asserted ones; there was no reason to rename
   the rest just to relabel them). Shared chat/avatar primitives used by
   BOTH #try-result and #agent-drawer (.chat-agent, .chat-agent__av,
   .typing-dot) live in the "Agent drawer" section further down, next to
   the drawer-only .chat-you* siblings they're designed to sit beside.
   ============================================================ */
.section--alt { border-top: 1px solid var(--glass-hair); }
.section__inner { max-width: 1180px; margin: 0 auto; padding: 84px 32px; }
.section__desc { font-size: 15.5px; line-height: 1.6; color: var(--ink-muted); margin: 0; text-wrap: pretty; }
.mono-label { font-family: var(--ff-mono); font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-faint); }
.mono-label--accent { color: var(--amber); }
.serif-h2 { font-family: var(--ff-display); font-weight: 500; font-size: clamp(30px,3.6vw,46px); line-height: 1.05; letter-spacing: -0.018em; color: var(--ink); margin: 0; text-wrap: pretty; }

.try-box { margin-top: 32px; background: linear-gradient(180deg, var(--glass-sheen), transparent 60%), var(--glass-fill);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border); border-radius: 14px;
  box-shadow: 0 1px 0 var(--glass-hair), 0 24px 48px oklch(from var(--shade) l c h / .08);
  overflow: hidden; }
.try-input-row { display: flex; gap: 10px; align-items: flex-end; background: var(--glass-sheen);
  border: 1px solid var(--glass-border); border-radius: 11px; padding: 6px 6px 6px 14px; transition: border-color .15s; }
.try-input-row:focus-within { border-color: var(--amber-line); }
.try-input { flex: 1; min-width: 0; border: none; outline: none; background: transparent;
  font-family: var(--ff-display); font-size: 16px; color: var(--ink); padding: 8px 0; }
.try-input::placeholder { color: var(--ink-faint); }
.try-route-btn { flex-shrink: 0; display: inline-flex; align-items: center; gap: 7px; padding: 10px 16px;
  background: var(--cta-bg); color: var(--cta-ink); border-radius: 8px; font-size: 14px; font-weight: 500; transition: filter .15s; }
.try-route-btn:hover { filter: brightness(1.08); }
/* Task 10 (a11y sweep): these render at runtime (hub.js's #try-chips), so the
   verification script only catches them once populated — min-height: 44px
   (not media-query-scoped, unlike the chrome fixes above: these are real
   example-prompt buttons at every viewport, not mobile-only chrome). */
.chip-btn { display: flex; align-items: flex-start; gap: 9px; text-align: left; width: 100%; padding: 9px 13px;
  min-height: 44px; box-sizing: border-box;
  background: var(--glass-sheen); border: 1px solid var(--glass-border); border-radius: 9px;
  font-family: var(--ff-display); font-size: 14px; line-height: 1.4; color: var(--ink-2);
  transition: border-color .13s, color .13s, background .13s; }
.chip-btn:hover { border-color: var(--amber-line); color: var(--ink); background: var(--amber-soft); }
.chip-btn__arrow { flex-shrink: 0; margin-top: 1px; font-family: var(--ff-mono); font-size: 13px; color: var(--amber); }

.try-result { border-top: 1px solid var(--glass-border); background: var(--glass-sheen); padding: 18px 18px 15px;
  opacity: 0; animation: djReveal .32s ease forwards; }
.try-msg { margin-top: 12px; background: var(--glass-fill-3); border: 1px solid var(--glass-border); border-radius: 10px; padding: 13px 15px; }
.try-msg__lead { font-family: var(--ff-display); font-size: 15.5px; line-height: 1.55; color: var(--ink-2); margin: 0; }
.try-msg__ask { font-family: var(--ff-display); font-size: 14.5px; line-height: 1.55; color: var(--ink-3); margin: 11px 0 0; }
.try-msg__list { margin: 10px 0 0; padding-left: 20px; display: flex; flex-direction: column; gap: 6px; }
.try-msg__list li { font-family: var(--ff-display); font-size: 14.5px; line-height: 1.5; color: var(--ink-2); }
.try-msg__quote { margin: 10px 0 0; padding: 3px 0 3px 14px; border-left: 2px solid var(--glass-border);
  font-family: var(--ff-display); font-size: 14.5px; line-height: 1.6; color: var(--ink-2); }
.try-msg code { font-family: var(--ff-mono); font-size: .85em; background: var(--glass-fill); border: 1px solid var(--glass-border); border-radius: 4px; padding: 1px 5px; }

/* .work-panel/.artifact never render today — hub.js's REPLIES data no longer
   has a code path that emits either class (marketing-smoke.mjs's #try-result
   and #agent-drawer-inner checks guard that they STAY gone, they don't guard
   that they exist). Styled defensively with the same glass recipe anyway, per
   the brief, so neither ships bare if a future reply schema reintroduces one. */
.work-panel, .artifact { background: linear-gradient(180deg, var(--glass-sheen), transparent 60%), var(--glass-fill);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border); border-radius: 12px; padding: 16px 18px; margin-top: 12px;
  font-size: 14px; line-height: 1.55; color: var(--ink-2); }

/* ============================================================
   Who it's for (prototype lines 341-375)
   ============================================================ */
.landing-types { border-top: 1px solid var(--glass-hair); }
.landing-types__grid { position: relative; display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); gap: 16px; }
.landing-types__ring { position: absolute; top: -30px; bottom: -30px; border: 1.6px solid var(--note);
  border-radius: 54% 46% 50% 50% / 46% 56% 44% 54%; opacity: .7; pointer-events: none; z-index: 2;
  transition: left .42s cubic-bezier(.4,.9,.3,1), right .42s cubic-bezier(.4,.9,.3,1); }
/* Task 12: the select action (card body) and the explore action (CTA, opens
   the writer-type overlay) are two real buttons, so they cannot nest — the
   card-wrap is the grid item / carousel slide now, holding both as
   siblings. Flex column so the card fills the available height and the CTA
   sits directly under it regardless of tag copy length between the three
   cards. */
/* cursor:default (review follow-up): the CTA is align-self:flex-start, so
   the gap below the card and the space right of the CTA's own text belong
   to this non-interactive wrap, not either button. Neither zone is styled
   to look clickable, but making the wrap's own cursor explicit removes any
   ambiguity rather than leaving it to inherit whatever an ancestor sets. */
.landing-types__card-wrap { display: flex; flex-direction: column; gap: 10px; min-width: 0; cursor: default; }
.landing-types__card { position: relative; text-align: left; display: flex; flex-direction: column; gap: 13px; min-height: 188px; flex: 1;
  padding: 26px 22px 22px; background: var(--glass-fill); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border); border-radius: 13px; box-shadow: 0 1px 0 var(--glass-hair), 0 14px 32px oklch(from var(--shade) l c h / .07);
  cursor: pointer; overflow: hidden; width: 100%; font-family: inherit; }
.landing-types__card-bar { position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--accent); }
.landing-types__card-kicker { font-family: var(--ff-mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent); }
.landing-types__card-name { font-family: var(--ff-display); font-size: 27px; font-weight: 500; letter-spacing: -0.015em; color: var(--ink); line-height: 1.04; }
.landing-types__card-tag { font-size: 14px; line-height: 1.5; color: var(--ink-3); }
.landing-types__cta { align-self: flex-start; display: inline-flex; align-items: center; gap: 6px; padding: 4px 2px;
  font-family: var(--ff-mono); font-size: 11.5px; letter-spacing: 0.02em; color: var(--accent); transition: gap .15s ease; }
.landing-types__cta:hover { gap: 10px; }
.landing-types__arrow-wrap { margin-top: -22px; position: relative; z-index: 2; pointer-events: none; }
.landing-types__arrow { display: block; width: 100%; height: 96px; }
.landing-types__arrow--mobile { display: none; width: 148px; height: 62px; margin: 14px auto 0; }
.landing-types__caption-row { text-align: center; margin-top: 6px; }

/* ============================================================
   The Studio + Scholar (prototype lines 376-449)
   ============================================================ */
.landing-studio { border-top: 1px solid var(--glass-hair); }
.landing-studio__coordinator { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 20px; padding: 22px 24px; margin-bottom: 16px;
  background: linear-gradient(140deg, oklch(from var(--amber) l c h / 0.18), transparent 76%), var(--glass-fill);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--amber-line); border-left: 3px solid var(--amber); border-radius: 12px;
  box-shadow: 0 3px 14px oklch(from var(--amber) l c h / 0.16); }
.landing-studio__avatar { flex-shrink: 0; width: 48px; height: 48px; border-radius: 11px; display: flex; align-items: center; justify-content: center;
  font-family: var(--ff-mono); font-size: 14px; font-weight: 600; color: var(--chip-ink); background: var(--ink-2); }
.landing-studio__meta { flex: 1; min-width: 0; }
.landing-studio__meta-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.landing-studio__name { font-family: var(--ff-display); font-size: 22px; font-weight: 500; letter-spacing: -0.012em; line-height: 1.1; }
.landing-studio__badge { font-family: var(--ff-mono); font-size: 9.5px; letter-spacing: 0.08em; text-transform: uppercase; padding: 3px 9px;
  border-radius: 999px; background: var(--amber-soft); border: 1px solid var(--amber-line); color: var(--amber); }
.landing-studio__desc { font-size: 14px; line-height: 1.55; color: var(--ink-2); margin-top: 6px; max-width: 66ch; }
.landing-studio__handle { flex-shrink: 0; font-family: var(--ff-mono); font-size: 10px; color: var(--ink-faint); }

.landing-spec-grid { display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: 16px; }
.landing-spec-grid--scholar { grid-template-columns: repeat(3,minmax(0,1fr)); }
/* Cards inside .landing-spec-grid (both #specialists-grid and #scholar-grid)
   render at RUNTIME from landing.js's initSpecialistGrids()/specCardHtml(),
   reading window.DJHub's SPECIALISTS/SCHOLAR_AGENTS (hub.js's own data
   export). This superseded hub.js's own renderSpecialistsGrid()/
   renderScholarGrid() as of Task 9, which deleted both (they were dead
   weight: init() still called them first, but landing.js's
   initSpecialistGrids(), registered after hub.js's DOMContentLoaded
   handler, immediately overwrote the same innerHTML with the accent-aware
   version — see landing.js's own comment above specCardHtml()).

   Task 10 (a11y sweep): the cards themselves (.spec-card/.spec-avatar/
   .spec-handle/.spec-name/.spec-tag/.spec-role) were STILL UNSTYLED through
   Task 9 — a Task 9 reviewer escalated it out of the "minor" bucket since
   this is the specialists + Scholar roster, a primary content section.
   Styled below with the same glass-card recipe every sibling family on this
   page uses (.landing-types__card, .landing-plan) plus a real type
   hierarchy: handle (small mono, next to the monogram) -> name (display,
   largest) -> tagline (body, muted) -> role (small mono, bottom, accent).
   The accent border/role colour reads var(--accent) the same way
   .landing-types__card-bar / .landing-stage do — see landing.js's
   specCardHtml(), which now carries data-accent on the OUTER .spec-card
   button (moved off the inner .spec-avatar span) so --accent cascades to
   every descendant here, not just the monogram. */
.spec-card { position: relative; display: flex; flex-direction: column; gap: 10px; text-align: left; width: 100%;
  padding: 16px 16px 14px; background: var(--glass-fill); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border); border-top: 2px solid var(--accent); border-radius: 11px;
  box-shadow: 0 1px 0 var(--glass-hair), 0 10px 22px oklch(from var(--shade) l c h / .06);
  cursor: pointer; font-family: inherit; transition: box-shadow .15s; }
/* No hover transform, matching .landing-types__card/.landing-plan (neither
   sibling card family lifts on hover either) — box-shadow only, so this
   doesn't need a reduced-motion entry alongside them. */
.spec-card:hover { box-shadow: 0 1px 0 var(--glass-hair), 0 16px 30px oklch(from var(--shade) l c h / .1); }
.spec-card__top { display: flex; align-items: center; gap: 9px; }
.spec-card .spec-avatar { width: 34px; height: 34px; border-radius: 8px; font-size: 11px; flex-shrink: 0; }
.spec-handle { font-family: var(--ff-mono); font-size: 10.5px; color: var(--ink-faint); }
.spec-name { font-family: var(--ff-display); font-size: 16.5px; font-weight: 500; letter-spacing: -0.01em; color: var(--ink); line-height: 1.22; }
.spec-tag { font-size: 12.5px; line-height: 1.42; color: var(--ink-3); margin-top: 4px; }
.spec-role { font-family: var(--ff-mono); font-size: 9.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent);
  margin-top: auto; padding-top: 8px; border-top: 1px solid var(--glass-hair); }

.landing-scholar { margin-top: 48px; padding-top: 40px; border-top: 1px solid var(--glass-hair); position: relative; }
.landing-scholar__head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 28px; }
.landing-scholar__label-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.landing-scholar__label { font-family: var(--ff-mono); font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--scholar); }
.landing-scholar__badge { font-family: var(--ff-mono); font-size: 9.5px; letter-spacing: 0.05em; text-transform: uppercase; padding: 2px 9px;
  border-radius: 999px; background: var(--scholar-soft); border: 1px solid var(--scholar-line); color: var(--scholar); }
.landing-scholar__title { font-family: var(--ff-display); font-weight: 500; font-size: clamp(24px,2.8vw,34px); line-height: 1.1; letter-spacing: -0.015em; margin: 0; }
.landing-scholar__desc { font-size: 15.5px; line-height: 1.6; color: var(--ink-muted); max-width: 31em; margin: 0; text-wrap: pretty; }
/* Task 10 (a11y sweep): landing.css's global `a { color:inherit; text-decoration:none }`
   (Base/reset, above) leaves inline links reading as plain body text until hover —
   this one and .landing-plan-grid__error a below both need a static affordance. */
.landing-scholar__more { color: var(--scholar); font-weight: 500; text-decoration: underline;
  text-decoration-color: var(--scholar-line); text-underline-offset: 3px; }
.landing-scholar__caption-row { display: flex; justify-content: flex-end; margin-top: 14px; }
.landing-scholar__caption { text-align: right; transform: rotate(0.6deg); }

/* ============================================================
   How it works (prototype lines 450-527)
   ============================================================ */
.landing-how { border-top: 1px solid var(--glass-hair); }
.landing-how__title { font-family: var(--ff-display); font-weight: 500; font-size: clamp(30px,3.6vw,46px); line-height: 1.05; letter-spacing: -0.018em; margin: 0 0 46px; max-width: 16em; text-wrap: pretty; }
.landing-stages { display: grid; grid-template-columns: repeat(5,minmax(0,1fr)); gap: 28px; }
.landing-stage { border-color: var(--accent); border-style: solid; border-width: 2px 0 0; padding-top: 16px; }
.landing-stage__num-row { display: flex; align-items: center; gap: 9px; margin-bottom: 12px; }
.landing-stage__num { font-family: var(--ff-mono); font-size: 11px; color: var(--accent); }
.landing-stage__ndot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
.landing-stage__title { font-family: var(--ff-display); font-size: 21px; font-weight: 500; color: var(--ink); letter-spacing: -0.01em; }
.landing-stage__body { font-size: 13.5px; line-height: 1.55; color: var(--ink-muted); margin-top: 8px; text-wrap: pretty; }
.landing-stage__tally { display: none; align-items: center; gap: 12px; margin-top: 14px; }
.landing-stage__tally-marks { display: flex; align-items: flex-end; gap: 5px; }
.landing-stage__tally-mark { display: block; width: 1.7px; height: 19px; background: var(--note); transform: rotate(-8deg); opacity: .75; }
.landing-stage__tally-label { font-family: 'Caveat', cursive; font-size: 17px; color: var(--note-3); }

.landing-how__tally { position: relative; margin-top: 8px; padding-top: 44px; }
.landing-how__tally-svg { display: block; width: 100%; height: auto; }
.landing-how__tally-cols { display: grid; grid-template-columns: repeat(5,minmax(0,1fr)); gap: 28px; margin-top: 4px; }
.landing-how__tally-col { text-align: center; font-family: 'Caveat', cursive; font-size: 17px; color: var(--note-3); opacity: .85; }
.landing-how__tally-note { position: absolute; font-family: 'Caveat', cursive; font-size: 21px; line-height: 1.25; color: var(--note-2); }
.landing-how__tally-note--start { left: 0; top: 24%; transform: rotate(-0.7deg); }
.landing-how__tally-note--mid { left: 30%; top: 22%; transform: rotate(0.4deg); }
.landing-how__tally-note--end { right: 0; top: 0; text-align: right; transform: rotate(0.5deg); }
.landing-how__mobile-note { margin-top: 28px; font-family: 'Caveat', cursive; font-size: 19px; line-height: 1.3; color: var(--note-2); transform: rotate(-0.5deg); }

/* ============================================================
   The workspace (prototype lines 528-591)
   ============================================================ */
.landing-product { border-top: 1px solid var(--glass-hair); }
.landing-product__wrap { display: flex; flex-wrap: wrap; gap: 52px; align-items: center; }
.landing-product__text { flex: 1 1 320px; min-width: 280px; }
.landing-product__title { font-family: var(--ff-display); font-weight: 500; font-size: clamp(28px,3.4vw,42px); line-height: 1.05; letter-spacing: -0.018em; margin: 0; }
.landing-product__desc { font-size: 15.5px; line-height: 1.62; color: var(--ink-3); margin: 22px 0 0; max-width: 30em; text-wrap: pretty; }
.landing-product__bullets { display: flex; flex-direction: column; gap: 12px; margin-top: 26px; }
.landing-product__bullet { display: flex; gap: 11px; align-items: baseline; }
.landing-product__dash { color: var(--amber); font-size: 14px; }
.landing-product__bullet-text { font-size: 14.5px; color: var(--ink-2); }
.landing-product__at { font-family: var(--ff-mono); font-size: 12.5px; color: var(--amber); }
.landing-product__mock { flex: 1 1 440px; min-width: 320px; }

.landing-ws { border: 1px solid var(--glass-border); border-radius: 12px; overflow: hidden;
  box-shadow: 0 2px 4px oklch(from var(--shade) l c h / .05), 0 30px 60px oklch(from var(--shade) l c h / .1);
  background: var(--glass-fill); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); }
.landing-ws__bar { display: flex; align-items: center; gap: 7px; padding: 11px 14px; background: var(--glass-sheen); border-bottom: 1px solid var(--glass-border); }
.landing-ws__dot { width: 9px; height: 9px; border-radius: 50%; background: var(--rule); }
.landing-ws__title { margin-left: 8px; font-family: var(--ff-mono); font-size: 10.5px; color: var(--ink-faint); }
.landing-ws__grid { display: grid; grid-template-columns: 140px 1fr; }
.landing-ws__side { background: var(--glass-sheen); border-right: 1px solid var(--glass-border); padding: 14px 10px; display: flex; flex-direction: column; gap: 4px; }
.landing-ws__side-label { font-family: var(--ff-mono); font-size: 9px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); padding: 0 6px 6px; }
.landing-ws__proj { padding: 7px 8px; border-radius: 6px; }
.landing-ws__proj--active { background: var(--glass-fill-3); border: 1px solid var(--glass-border); box-shadow: inset 2px 0 0 var(--amber); }
.landing-ws__proj-name { font-family: var(--ff-display); font-size: 13px; font-weight: 500; color: var(--ink); line-height: 1.2; }
.landing-ws__proj--inactive .landing-ws__proj-name { color: var(--ink-muted); }
.landing-ws__proj-status { font-family: var(--ff-mono); font-size: 9px; color: var(--amber); margin-top: 3px; }
.landing-ws__proj--inactive .landing-ws__proj-status { color: var(--ink-faint); }
.landing-ws__chat { padding: 16px 16px 18px; display: flex; flex-direction: column; gap: 14px; }
.landing-ws__you { display: flex; gap: 9px; justify-content: flex-end; align-items: flex-start; }
.landing-ws__you-bubble { background: var(--panel-bg); color: var(--panel-ink); padding: 8px 11px; border-radius: 9px 9px 3px 9px;
  font-family: var(--ff-display); font-size: 13px; line-height: 1.4; max-width: 80%; }
.landing-ws__you-av { flex-shrink: 0; width: 24px; height: 24px; border-radius: 5px; display: flex; align-items: center; justify-content: center;
  font-family: var(--ff-mono); font-size: 7.5px; font-weight: 600; color: var(--chip-ink); background: var(--panel-bg); }
.landing-ws__agent { display: flex; gap: 9px; align-items: flex-start; }
/* Task 10 (a11y sweep): same fix, same reasoning as .landing-demo__avatar--writer
   above — was 5.05/3.75/3.67 on manuscript/pitch/obsidian, now lifted via
   data-accent (home.html) + liftSpecialistAccents. */
.landing-ws__agent-av { flex-shrink: 0; width: 24px; height: 24px; border-radius: 5px; display: flex; align-items: center; justify-content: center;
  font-family: var(--ff-mono); font-size: 7.5px; font-weight: 600; color: var(--chip-ink); background: var(--accent, oklch(52% 0.08 240)); }
.landing-ws__agent-text { font-family: var(--ff-display); font-size: 13.5px; line-height: 1.5; color: var(--ink); }
.landing-ws__handoff { display: inline-flex; align-items: center; gap: 6px; margin-top: 8px; padding: 3px 9px;
  background: var(--amber-soft); border: 1px solid var(--amber-line); border-radius: 999px; font-family: var(--ff-mono); font-size: 9.5px; color: var(--amber); }
/* Task 10 (a11y sweep): same fix again — was 5.94/2.29/2.02 on
   manuscript/pitch/obsidian, now lifted via data-accent + liftSpecialistAccents. */
.landing-ws__handoff-to { color: var(--accent, oklch(48% 0.08 25)); }

/* ============================================================
   A fair question (Task 12 — restored; Task 3 dropped this section with no
   successor, see task-12-report.md). Re-homed between product and pricing;
   own narrower reading column (860px vs. the shared 1180px .landing-wrap)
   like the pre-revamp page used, plus a fresh landing-why* BEM family (the
   old page reused .stages-grid/.stage for this, but that pairing is now
   owned by "How it works", which is a different fixed-count component —
   5 numbered stages, not 3 unnumbered cards). Cards use the same
   frosted-glass recipe as every sibling card family on this page
   (.landing-types__card, .spec-card, .landing-plan).
   ============================================================ */
.landing-why { border-top: 1px solid var(--glass-hair); }
.landing-why__inner { max-width: 860px; margin: 0 auto; padding: 84px 32px; }
.landing-why__title { font-family: var(--ff-display); font-weight: 500; font-size: clamp(30px,3.6vw,46px); line-height: 1.05; letter-spacing: -0.018em; color: var(--ink); margin: 14px 0 40px; text-wrap: pretty; }
.landing-why__grid { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); gap: 18px; }
.landing-why__card { padding: 22px 20px; background: linear-gradient(180deg, var(--glass-sheen), transparent 60%), var(--glass-fill);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border); border-top: 2px solid var(--amber); border-radius: 12px;
  box-shadow: 0 1px 0 var(--glass-hair), 0 10px 22px oklch(from var(--shade) l c h / .06); }
.landing-why__card-title { font-family: var(--ff-display); font-size: 19px; font-weight: 500; letter-spacing: -0.01em; color: var(--ink); }
.landing-why__card-body { font-size: 13.5px; line-height: 1.55; color: var(--ink-muted); margin-top: 8px; text-wrap: pretty; }

/* ============================================================
   Pricing (prototype lines 592-638). Static prototype copy for now
   (Draft/Studio/Scholar) — Task 7 replaces this whole grid with three
   cards fetched from GET /api/pricing (Free/Student/Member), including
   the .landing-plan--featured modifier this already uses.
   ============================================================ */
.landing-pricing { border-top: 1px solid var(--glass-hair); }
.landing-plan-grid { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); gap: 16px; align-items: stretch; }
.landing-plan { position: relative; display: flex; flex-direction: column; gap: 18px; padding: 28px 24px 26px;
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border-radius: 13px; box-shadow: 0 1px 0 var(--glass-hair), 0 14px 32px oklch(from var(--shade) l c h / .07);
  background: var(--glass-fill); border: 1px solid var(--glass-border); }
.landing-plan--featured { background: linear-gradient(150deg, oklch(from var(--amber) l c h / 0.16), transparent 72%), var(--glass-fill-2); border-color: var(--amber-line); }
.landing-plan--scholar { background: linear-gradient(160deg, oklch(from var(--scholar) l c h / 0.12), transparent 66%), var(--glass-fill); border-color: var(--scholar-line); }
.landing-plan__top-row { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.landing-plan__name { font-family: var(--ff-display); font-size: 24px; font-weight: 500; letter-spacing: -0.014em; line-height: 1.1; }
.landing-plan__tag { font-family: var(--ff-mono); font-size: 9.5px; letter-spacing: 0.06em; text-transform: uppercase; padding: 2px 9px;
  border-radius: 999px; border: 1px solid var(--glass-border); color: var(--ink-faint); }
.landing-plan--featured .landing-plan__tag { border-color: var(--amber-line); color: var(--amber); }
.landing-plan--scholar .landing-plan__tag { border-color: var(--scholar-line); color: var(--scholar); }
.landing-plan__price-row { display: flex; align-items: baseline; gap: 6px; margin-top: 14px; }
.landing-plan__price { font-family: var(--ff-display); font-size: 42px; font-weight: 500; letter-spacing: -0.02em; line-height: 1; }
.landing-plan__cadence { font-family: var(--ff-mono); font-size: 11px; color: var(--ink-faint); }
.landing-plan__blurb { font-size: 14px; line-height: 1.55; color: var(--ink-3); margin-top: 12px; text-wrap: pretty; }
.landing-plan__features { display: flex; flex-direction: column; gap: 9px; margin: 0; padding: 0; list-style: none; }
.landing-plan__feature { display: flex; gap: 10px; align-items: baseline; font-size: 14px; color: var(--ink-2); line-height: 1.45; }
.landing-plan__dash { color: var(--amber); flex: none; }
.landing-plan__cta { margin-top: auto; display: inline-flex; align-items: center; justify-content: center; gap: 7px; padding: 12px 18px;
  border-radius: 7px; font-size: 14.5px; font-weight: 500; background: var(--glass-hair); color: var(--ink); border: 1px solid var(--glass-border); }
.landing-plan--featured .landing-plan__cta { background: var(--cta-bg); color: var(--cta-ink); border-color: var(--amber-line); }
.landing-plan--scholar .landing-plan__cta { background: var(--glass-hair); color: var(--ink); border-color: var(--scholar-line); }
/* Task 10 (a11y sweep): see .landing-scholar__more above for why this needs a
   static affordance — same global `a { text-decoration:none }` reset. */
.landing-plan-grid__error a { color: var(--amber); font-weight: 500; text-decoration: underline;
  text-decoration-color: var(--amber-line); text-underline-offset: 3px; }
.landing-pricing__caption-row { display: flex; align-items: flex-start; gap: 10px; margin-top: 16px; padding-left: 6px; }
.landing-pricing__caption { transform: rotate(-0.6deg); }

/* ============================================================
   Final CTA (prototype lines 639-653)
   ============================================================ */
.landing-cta { max-width: 1180px; margin: 0 auto; padding: 60px 32px 80px; }
.landing-cta__inner { background: var(--panel-bg); border-radius: 18px; padding: clamp(40px,6vw,72px); position: relative; overflow: hidden; }
.landing-cta__glow { position: absolute; top: -40px; right: -20px; width: 260px; height: 260px; background: var(--amber); opacity: .18;
  filter: blur(64px); border-radius: 50%; pointer-events: none; }
.landing-cta__content { position: relative; max-width: 30em; }
/* Uses --panel-accent rather than the raw --amber-2 token. This kicker sits on
   --panel-bg, where --amber-2 failed on birch (3.55), slate (3.89) and dusk
   (3.24). It passes on paper at 6.29, which is why a paper-only check
   previously cleared it as a phantom.
   NB: write token names in comments without a trailing colon — the guard in
   web/tests/landing-tokens.test.mjs regexes raw source, comments included, so
   "--amber-2" immediately followed by ":" reads as a re-declaration. */
.landing-cta__label { font-family: var(--ff-mono); font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--panel-accent); margin-bottom: 18px; }
.landing-cta__title { font-family: var(--ff-display); font-weight: 500; font-size: clamp(32px,4.4vw,56px); line-height: 1.04; letter-spacing: -0.02em; color: var(--panel-ink); margin: 0; }
.landing-cta__text { font-size: 16px; line-height: 1.6; color: var(--panel-ink-2); margin: 22px 0 0; }
.landing-cta__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; margin-top: 32px; }
.landing-cta__link { font-size: 15px; color: var(--panel-ink-2); border-bottom: 1px solid var(--panel-rule); padding-bottom: 2px; }

/* ============================================================
   Footer (prototype lines 654-669)
   ============================================================ */
.landing-footer { border-top: 1px solid var(--glass-hair); }
.landing-footer__inner { max-width: 1180px; margin: 0 auto; padding: 44px 32px; display: flex; flex-wrap: wrap; gap: 28px; align-items: center; justify-content: space-between; }
.landing-footer__brand { display: flex; align-items: center; gap: 9px; }
.landing-footer__logo { height: 14px; width: auto; display: block; flex-shrink: 0; }
.landing-footer__name { font-family: var(--ff-display); font-size: 16px; font-weight: 500; }
.landing-footer__links { display: flex; flex-wrap: wrap; gap: 22px; font-size: 13px; color: var(--ink-muted); }
.landing-footer__copy { font-family: var(--ff-mono); font-size: 10.5px; color: var(--ink-faint); letter-spacing: 0.04em; }

/* ============================================================
   Mobile nav drawer (prototype lines 670-692). Rendered OUTSIDE
   .landing-nav / .landing-stack in home.html — the nav's backdrop-filter
   makes it a containing block for fixed descendants, so a drawer nested
   inside it would position against the nav bar instead of the viewport.
   ============================================================ */
.landing-drawer { display: none; position: fixed; inset: 0; z-index: 80; flex-direction: column; padding: 18px 22px 26px; background: var(--paper); overflow-y: auto; }
.landing-drawer__top { display: flex; align-items: center; justify-content: space-between; padding-bottom: 18px; }
.landing-drawer__brand { display: flex; align-items: center; gap: 9px; }
.landing-drawer__logo { height: 16px; width: auto; display: block; }
.landing-drawer__name { font-family: var(--ff-display); font-size: 18px; font-weight: 500; letter-spacing: -0.01em; }
.landing-drawer__close { width: 38px; height: 38px; display: grid; place-items: center; padding: 0; background: none; border: 1px solid var(--rule);
  border-radius: 8px; color: var(--ink); font-size: 15px; font-family: inherit; cursor: pointer; }
.landing-drawer__links { display: flex; flex-direction: column; }
.landing-drawer__link { padding: 15px 2px; font-family: var(--ff-display); font-size: 26px; font-weight: 500; letter-spacing: -0.012em;
  border-bottom: 1px solid var(--glass-hair); }
.landing-drawer__actions { display: flex; flex-direction: column; gap: 14px; margin-top: 26px; }
.landing-drawer__login { text-align: center; font-size: 14.5px; color: var(--ink-2); }
.landing-drawer__copy { margin-top: auto; padding-top: 28px; font-family: var(--ff-mono); font-size: 10.5px; color: var(--ink-faint); letter-spacing: 0.04em; }

/* ============================================================
   Theme dock (prototype lines 693-704). Rendered outside the nav/stack
   for the same containing-block reason as the drawer above.
   ============================================================ */
.landing-dock { position: fixed; right: 22px; bottom: 22px; z-index: 90; display: flex; align-items: center; gap: 12px; padding: 9px 13px;
  border-radius: 999px; background: var(--glass-fill-3); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border); box-shadow: 0 10px 34px oklch(from var(--shade) l c h / .16); }
.landing-dock__toggle { display: none; place-items: center; width: 26px; height: 26px; padding: 0; background: none; border: none; cursor: pointer; }
.landing-dock__toggle-dot { width: 16px; height: 16px; border-radius: 999px; border: 1px solid var(--ink-faint);
  background: linear-gradient(90deg, var(--ink) 50%, var(--amber) 50%); }
.landing-dock__label { font-family: var(--ff-mono); font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-faint); padding-left: 4px; }
/* isolation:isolate scopes the swatches' negative-z hit-slop (below) to
   THIS row's own stacking context. Without it, a swatch's z-index:-1
   ::before sinks below the row's own (transparent, but still hit-testable)
   box too — not just below sibling swatches — since the row itself doesn't
   otherwise establish a stacking context, so the row becomes the topmost
   thing painted in the gaps between dots and silently swallows every click
   there (the row has no click handler of its own; .landing-dock's
   delegated handler only matches `[role="radio"]` targets). Confirmed via
   elementFromPoint at a gap point: without isolation it returns
   .landing-dock__row; with it, a swatch. */
.landing-dock__row { isolation: isolate; display: flex; align-items: center; gap: 6px; }
.landing-dock__swatch { position: relative; width: 22px; height: 22px; padding: 0; border-radius: 999px; cursor: pointer; display: grid; place-items: center;
  border: 1px solid var(--glass-border); transition: transform 160ms cubic-bezier(.4,0,.2,1), box-shadow 200ms ease; }
.landing-dock__swatch:hover { transform: translateY(-2px); }
.landing-dock__swatch-dot { width: 7px; height: 7px; border-radius: 999px; }
.landing-dock__swatch--paper      { background: oklch(97.5% 0.008 72); }
.landing-dock__swatch--paper      .landing-dock__swatch-dot { background: oklch(52% 0.16 55); }
.landing-dock__swatch--manuscript { background: oklch(97.5% 0.01 75); }
.landing-dock__swatch--manuscript .landing-dock__swatch-dot { background: oklch(53% 0.18 50); }
.landing-dock__swatch--birch      { background: oklch(97.5% 0.006 140); }
.landing-dock__swatch--birch      .landing-dock__swatch-dot { background: oklch(46% 0.1 155); }
.landing-dock__swatch--slate      { background: oklch(97.5% 0.005 245); }
.landing-dock__swatch--slate      .landing-dock__swatch-dot { background: oklch(44% 0.2 248); }
.landing-dock__swatch--dusk       { background: oklch(96% 0.008 70); }
.landing-dock__swatch--dusk       .landing-dock__swatch-dot { background: oklch(48% 0.22 44); }
.landing-dock__swatch--obsidian   { background: oklch(22% 0.022 258); }
.landing-dock__swatch--obsidian   .landing-dock__swatch-dot { background: oklch(70% 0.22 254); }
.landing-dock__swatch--embers     { background: oklch(21% 0.024 48); }
.landing-dock__swatch--embers     .landing-dock__swatch-dot { background: oklch(70% 0.2 78); }
.landing-dock__swatch--pitch      { background: oklch(21% 0.005 60); }
.landing-dock__swatch--pitch      .landing-dock__swatch-dot { background: oklch(80% 0.018 74); }

/* ============================================================
   Writer-type overlay (#hub-overlay) — Task 12, restored; Task 3 dropped
   this with no successor (task-12-report.md). The shell below (.hub-overlay/
   .hub-overlay__nav*, .overlay-back/.overlay-dj*) is new page-authored CSS
   for the shell home.html now defines. #overlay-content's INNER markup is
   generated at runtime by hub.js's buildOverlayHtml(type), which is
   unmodified and still emits the pre-revamp class vocabulary below
   (.overlay-hero/.overlay-body/.overlay-section/.value-prop*, .pick-card*, 
   .flow-step*, .case-study-box*, .case-agent*, .case-you*, .try-prompt-btn/
   .faq-*, .hub-btn*) — restyled in place, not renamed, same precedent as
   the "Try it now" section above (Task 9's own note on that reasoning).
   A good deal of buildOverlayHtml's own output is inline-styled directly
   (its headings/body copy set color/font-family via style="", reading real
   current theme tokens like var(--ink)/var(--accent)) — those already
   render correctly with zero CSS here; only the class-based structural
   rules below are new. Rendered OUTSIDE .landing-nav/.landing-stack, same
   containing-block reason as the mobile drawer/theme dock above it in
   home.html. No entrance animation (the pre-revamp prototype had a djFade
   fade-in) — hub.js's openOverlay() does not move focus anywhere, so
   skipping motion here avoids a reduced-motion entry for a purely
   decorative fade that would otherwise need one.
   ============================================================ */
.hub-overlay { display: none; position: fixed; inset: 0; z-index: 150; background: var(--paper); overflow-y: auto; }
.hub-overlay.is-open { display: block; }
.hub-overlay__nav { position: sticky; top: 0; z-index: 5; background: var(--glass-fill);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border-bottom: 1px solid var(--glass-border); }
.hub-overlay__nav-inner { max-width: 920px; margin: 0 auto; padding: 14px 32px; display: flex; align-items: center; gap: 16px; }
.overlay-back { display: inline-flex; align-items: center; gap: 7px; padding: 8px 14px;
  border: 1px solid var(--glass-border); border-radius: 7px; font-size: 13px; color: var(--ink-3);
  background: var(--glass-fill-3); transition: color .15s; }
.overlay-back:hover { color: var(--ink); }
.overlay-dj { margin-left: auto; display: flex; align-items: center; gap: 9px; }
.overlay-dj__icon { height: 13px; width: auto; display: block; flex-shrink: 0; }
.overlay-dj__name { font-family: var(--ff-display); font-size: 15px; font-weight: 500; color: var(--ink); }
.overlay-hero { border-bottom-width: 1px; border-bottom-style: solid; }
.overlay-hero__inner { max-width: 920px; margin: 0 auto; padding: 60px 32px 52px; }
.overlay-pick-av { width: 30px; height: 30px; border-radius: 7px; display: flex; align-items: center; justify-content: center;
  font-family: var(--ff-mono); font-size: 10px; font-weight: 600; color: var(--chip-ink); }
.overlay-body { max-width: 920px; margin: 0 auto; padding: 56px 32px 88px; }
.overlay-section { margin-top: 56px; padding-top: 44px; border-top: 1px solid var(--glass-hair); }

.value-props { display: grid; grid-template-columns: repeat(auto-fit,minmax(220px,1fr)); gap: 18px; }
.value-prop { padding: 22px 20px; background: linear-gradient(180deg, var(--glass-sheen), transparent 60%), var(--glass-fill);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border); border-radius: 12px; box-shadow: 0 1px 0 var(--glass-hair), 0 10px 22px oklch(from var(--shade) l c h / .06); }
.value-prop__bar { width: 28px; height: 3px; border-radius: 2px; margin-bottom: 16px; }
.value-prop__title { font-family: var(--ff-display); font-size: 20px; font-weight: 500; letter-spacing: -0.01em; color: var(--ink); line-height: 1.15; }
.value-prop__body { font-size: 14px; line-height: 1.55; color: var(--ink-muted); margin-top: 10px; }

.picks-list { display: grid; grid-template-columns: repeat(auto-fit,minmax(340px,1fr)); gap: 14px; }
.pick-card { display: flex; gap: 14px; align-items: flex-start; padding: 18px; background: var(--glass-fill);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border); border-radius: 11px; }
.pick-card__av { flex-shrink: 0; width: 40px; height: 40px; border-radius: 9px; display: flex; align-items: center; justify-content: center;
  font-family: var(--ff-mono); font-size: 12px; font-weight: 600; color: var(--chip-ink); }
.pick-card__name { font-family: var(--ff-display); font-size: 18px; font-weight: 500; color: var(--ink); letter-spacing: -0.01em; }
.pick-card__handle { font-family: var(--ff-mono); font-size: 10px; color: var(--ink-faint); margin-left: 8px; }
.pick-card__why { font-size: 13.5px; line-height: 1.5; color: var(--ink-muted); margin-top: 4px; }

.flow-steps { display: flex; flex-wrap: wrap; gap: 24px; }
.flow-step { flex: 1 1 158px; min-width: 150px; padding-top: 14px; border-top-width: 2px; border-top-style: solid; }
.flow-step__num { font-family: var(--ff-mono); font-size: 11px; margin-bottom: 8px; }
.flow-step__title { font-family: var(--ff-display); font-size: 19px; font-weight: 500; color: var(--ink); letter-spacing: -0.01em; }
.flow-step__body { font-size: 13px; line-height: 1.5; color: var(--ink-muted); margin-top: 7px; }

.case-study-box { border: 1px solid var(--glass-border); border-radius: 13px; overflow: hidden; background: var(--glass-fill);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); }
.case-study-box__body { padding: 22px 20px; display: flex; flex-direction: column; gap: 18px; }
.case-you { display: flex; gap: 11px; justify-content: flex-end; align-items: flex-start; }
.case-you__bubble { background: var(--panel-bg); color: var(--panel-ink); padding: 11px 14px; border-radius: 11px 11px 3px 11px;
  font-family: var(--ff-display); font-size: 15px; line-height: 1.5; max-width: 80%; }
.case-you__av { flex-shrink: 0; width: 30px; height: 30px; border-radius: 6px; display: flex; align-items: center; justify-content: center;
  font-family: var(--ff-mono); font-size: 8.5px; font-weight: 600; color: var(--panel-ink); background: var(--panel-bg); }
.case-agent { display: flex; gap: 11px; align-items: flex-start; }
.case-agent__av { flex-shrink: 0; width: 30px; height: 30px; border-radius: 6px; display: flex; align-items: center; justify-content: center;
  font-family: var(--ff-mono); font-size: 9px; font-weight: 600; color: var(--chip-ink); }
.case-agent__name { font-family: var(--ff-ui); font-size: 13px; font-weight: 600; color: var(--ink); margin-bottom: 5px; }
.case-agent__lead { font-family: var(--ff-display); font-size: 15px; line-height: 1.55; color: var(--ink-2); }

.try-prompts-list { display: flex; flex-direction: column; gap: 7px; }
/* min-height:44px is not media-query-scoped, matching .chip-btn's own note
   above: this renders at runtime (hub.js's buildOverlayHtml) as a real
   example-prompt button at every viewport, not mobile-only chrome. */
.try-prompt-btn { display: flex; align-items: flex-start; gap: 9px; text-align: left; padding: 11px 14px; border-radius: 9px;
  min-height: 44px; box-sizing: border-box;
  border: 1px solid var(--glass-border); background: var(--glass-sheen); color: var(--ink-2); font-family: var(--ff-display);
  font-size: 15px; line-height: 1.4; transition: border-color .13s, background .13s, color .13s; width: 100%; }
.try-prompt-btn:hover { color: var(--ink); border-color: var(--amber-line); background: var(--amber-soft); }

.faq-item { padding: 18px 0; border-top: 1px solid var(--glass-hair); }
.faq-q { font-family: var(--ff-display); font-size: 18px; font-weight: 500; color: var(--ink); letter-spacing: -0.01em; }
.faq-a { font-size: 14.5px; line-height: 1.6; color: var(--ink-muted); margin-top: 8px; max-width: 46em; }

.hub-btn { display: inline-flex; align-items: center; gap: 7px; padding: 9px 16px; border-radius: 6px;
  font-size: 13.5px; font-weight: 500; color: var(--chip-ink); transition: filter .15s; }
.hub-btn:hover { filter: brightness(1.08); }
.hub-btn--lg { padding: 14px 24px; font-size: 15px; border-radius: 7px; }

/* ============================================================
   Agent drawer (#agent-drawer / #agent-drawer-bd) — Task 9. Carried forward
   verbatim and UNstyled by Task 3 for the same reason as #try above
   (marketing-smoke.mjs's #agent-drawer.is-open / #agent-drawer-inner
   .chat-you / .js-drawer-close assertions). Rendered outside .landing-nav/
   .landing-stack in home.html, alongside the mobile drawer and theme dock
   above, for the same containing-block reason those two call out — grouped
   here with them rather than near "The Studio" section, since it is a
   page-level overlay like they are, not in-flow content.

   Includes the shared chat/avatar primitives .chat-agent/.chat-agent__av/
   .typing-dot, used by BOTH #try-result (resultHtml) and this drawer
   (agentDrawerHtml) — .chat-you/.chat-you__bubble/.chat-you__av are
   drawer-only (resultHtml never renders a "YOU" bubble, only the routed
   agent's reply). .spec-avatar gets only the minimal base circle+font
   styling agentDrawerHtml's own id-row needs (it sets accent/size inline;
   the class supplies flex-centering, font-family and text color) — the
   fuller #specialists-grid/#scholar-grid card styling that class also
   feeds (.spec-card/.spec-handle/.spec-name/.spec-tag/.spec-role) is out
   of this task's scope; see the landing-spec-grid comment above.
   ============================================================ */
.chat-agent { display: flex; gap: 10px; align-items: flex-start; }
.chat-agent__av { flex-shrink: 0; width: 28px; height: 28px; border-radius: 6px; display: flex; align-items: center; justify-content: center;
  font-family: var(--ff-mono); font-size: 8.5px; font-weight: 600; color: var(--chip-ink); }
.typing-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ink-faint); display: inline-block; animation: djBounce 1.1s infinite ease-in-out; }
.spec-avatar { display: flex; align-items: center; justify-content: center; font-family: var(--ff-mono); font-weight: 600; color: var(--chip-ink); }

.agent-drawer__backdrop { display: none; position: fixed; inset: 0; z-index: 190; background: oklch(from var(--shade) l c h / .4); }
.agent-drawer__backdrop.is-open { display: block; }
/* visibility is belt-and-braces alongside hub.js's openAgentDrawer/
   closeAgentDrawer `inert` toggle, for the same reason .landing-drawer
   below carries it (see that rule's own comment): `inert` alone still
   leaves this subtree tabbable/AT-reachable on a browser old enough to
   lack the `inert` IDL property but young enough to still render the page,
   since `oklch(from ...)` only fails at computed-value time, not parse
   time. The `0s` delayed transition on the closed state keeps the slide-
   out visible before visibility actually flips; the open state zeroes
   that delay so the drawer is interactive (and closeBtn.focus() takes)
   the instant it opens. */
.agent-drawer { position: fixed; right: 0; top: 0; height: 100vh; width: 420px; z-index: 200; overflow-y: auto;
  background: linear-gradient(180deg, var(--glass-sheen), transparent 60%), var(--glass-fill);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border-left: 1px solid var(--glass-border);
  box-shadow: -6px 0 28px oklch(from var(--shade) l c h / .12);
  transform: translateX(100%); visibility: hidden;
  transition: transform .28s ease, visibility 0s linear .28s; }
.agent-drawer.is-open { transform: translateX(0); visibility: visible; transition: transform .28s ease, visibility 0s; }
.agent-drawer__head { background: var(--glass-sheen); border-bottom: 1px solid var(--glass-border);
  padding: 16px 20px 18px; display: flex; flex-direction: column; gap: 14px; }
.agent-drawer__top-row { display: flex; align-items: center; justify-content: space-between; }
.agent-drawer__close { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px;
  border: 1px solid var(--glass-border); border-radius: 6px; font-size: 12px; color: var(--ink-3);
  background: var(--glass-fill-3); transition: color .13s; }
.agent-drawer__close:hover { color: var(--ink); }
.agent-drawer__meta { font-family: var(--ff-mono); font-size: 10px; color: var(--ink-faint); letter-spacing: 0.04em; }
.agent-drawer__id-row { display: flex; align-items: center; gap: 12px; }
.agent-drawer__body { padding: 26px 22px 40px; display: flex; flex-direction: column; gap: 20px; }
.agent-drawer__desc { font-family: var(--ff-display); font-size: 15.5px; line-height: 1.62; color: var(--ink-3); margin: 0; }
.agent-drawer__sample-label { font-family: var(--ff-mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-muted); margin-bottom: 10px; }
.agent-drawer__exchange { display: flex; flex-direction: column; gap: 14px; margin-top: 12px; }
.drawer-step { opacity: 0; animation: djReveal .45s ease forwards; }
.drawer-step--typing { opacity: 0; animation: djTypingPulse 1.5s ease forwards; }
.chat-you { display: flex; gap: 10px; align-items: flex-start; justify-content: flex-end; }
.chat-you__bubble { background: var(--panel-bg); color: var(--panel-ink); padding: 10px 13px; border-radius: 11px 11px 3px 11px;
  font-family: var(--ff-display); font-size: 14.5px; line-height: 1.45; max-width: 84%; }
.chat-you__av { flex-shrink: 0; width: 28px; height: 28px; border-radius: 6px; display: flex; align-items: center; justify-content: center;
  font-family: var(--ff-mono); font-size: 8.5px; font-weight: 600; color: var(--panel-ink); background: var(--panel-bg); }
.agent-drawer__cta { display: inline-flex; align-items: center; gap: 7px; padding: 14px 24px; border-radius: 7px;
  font-size: 15px; font-weight: 500; color: var(--chip-ink); align-self: flex-start; transition: filter .15s; }
.agent-drawer__cta:hover { filter: brightness(1.1); }

/* ============================================================
   Responsive layer — prototype lines 154-233, verbatim breakpoints
   (1080 / 900 / 860 / 768 / 430), every !important dropped (they only
   ever existed to beat the prototype's own inline styles, which this
   port has no inline styles for), data-r/data-only hooks converted to
   the real classes above. The mobile stacking order gains a "try"
   step between hero(1) and types — the prototype has no #try section,
   this port carries it forward per the Task 3 brief — the rest of the
   list is renumbered accordingly.
   ============================================================ */
/* Closed state: still display:flex once past the 900px breakpoint below (so
   it can transition open), but invisible and non-interactive until
   data-open="true". Without pointer-events:none here the closed drawer —
   position:fixed;inset:0, i.e. covering the ENTIRE viewport — silently
   eats every click on the page below 900px wide (that is how this was
   actually caught: marketing-smoke.mjs's #try-result click landed on
   .landing-drawer__login instead of the chip underneath, confirmed via
   elementFromPoint against Puppeteer's real 800x600 default viewport).
   `visibility` here is belt-and-braces alongside initDrawer's `inert`
   toggle (landing.js): a review finding about `inert` browser support was
   earlier parked on the reasoning that any browser too old for `inert`
   would also choke on this file's `oklch(from ...)` relative-colour syntax
   and never render the page at all — that reasoning was wrong. Relative
   colour only goes invalid at computed-value time, so a browser lacking
   `inert` (Firefox 102 to 111, Safari 15.4 and earlier, Chrome 101 and
   earlier) still serves and renders this page, with `drawer.inert = true`
   silently reduced to an inert-but-inactive plain expando property — so
   without this rule, those browsers keep the closed drawer's nine controls
   tabbable and AT-reachable indefinitely. The `0s` delay on the closed
   transition keeps the fade-out visible before visibility actually flips;
   the open rule zeroes that delay so the drawer is immediately
   interactive the moment it opens. */
.landing-drawer { transform: translateY(-10px); opacity: 0; pointer-events: none; visibility: hidden;
  transition: opacity .22s ease, transform .26s cubic-bezier(.3,.8,.3,1), visibility 0s linear .22s; }
.landing-drawer[data-open="true"] { transform: none; opacity: 1; pointer-events: auto; visibility: visible;
  transition: opacity .22s ease, transform .26s cubic-bezier(.3,.8,.3,1), visibility 0s; }
.landing-types__grid::-webkit-scrollbar { display: none; }

@media (max-width: 1080px) {
  .landing-spec-grid { grid-template-columns: repeat(3, minmax(0,1fr)); }
  .landing-stages { gap: 20px; }
}

@media (max-width: 900px) {
  .landing-nav__links, .landing-nav__login { display: none; }
  .landing-burger { display: inline-flex; }
  .landing-drawer { display: flex; }
  .landing-stages { grid-template-columns: 1fr; gap: 0; }
  .landing-stage { border-width: 0 0 0 2px; padding: 0 0 30px 18px; }
  .landing-stage:last-child { padding-bottom: 0; }
  .landing-how__tally { display: none; }
  .landing-stage__tally { display: flex; }
  /* Task 10 (a11y sweep): touch targets, measured at 390px. Ink stays the
     design's own small mark (the 38px burger/close squares, the ~17px
     "Log in" text) — only the hit area grows to 44px, via min-height/
     min-width + flex centring rather than resizing the visible glyph. */
  .landing-burger { width: 44px; height: 44px; }
  .landing-nav__actions .landing-btn { min-height: 44px; display: inline-flex; align-items: center; }
  .landing-drawer__close { width: 44px; height: 44px; }
  .landing-drawer__login { min-height: 44px; display: flex; align-items: center; justify-content: center; }
  /* Beyond the brief's own named six: the verification script (Step 5) also
     flags these at 390px. The nav brand sits in a row the CTA fix above
     already makes taller than its own 27px box, so an invisible ::before
     hit-slop (matching the theme-swatch technique) reaches 44px without
     growing the visible logo+wordmark or the nav bar itself; the two
     "Find your studio" secondary links and the try-it submit button get a
     direct min-height instead, same recipe as .landing-drawer__login. */
  .landing-nav__brand::before { content: ""; position: absolute; inset: -9px 0; }
  .landing-link, .landing-cta__link { min-height: 44px; display: inline-flex; align-items: center; }
  .landing-types__cta { min-height: 44px; }
  .try-route-btn { min-height: 44px; }
  .overlay-back { min-height: 44px; }
  .landing-footer__links a { min-height: 44px; min-width: 44px; display: inline-flex; align-items: center; justify-content: center; }
  /* "Read more ->" is the tail of a running paragraph, not a standalone
     control, but the verification script still measures its own line box
     (43px — one under target) — same min-height fix, safe as the last
     inline run in the sentence. */
  .landing-scholar__more { display: inline-flex; align-items: center; min-height: 44px; }
}

@media (max-width: 860px) {
  .landing-plan-grid { grid-template-columns: 1fr; }
}

@media (max-width: 768px) {
  .landing-wrap { padding: 56px 22px; }
  .section__inner { padding: 56px 22px; }
  .landing-hero { padding: 44px 22px 48px; gap: 40px; }
  .landing-nav__inner { padding: 11px 18px; gap: 12px; }
  .landing-cta { padding: 40px 22px 56px; }
  .landing-footer__inner { padding: 34px 22px; }
  .agent-drawer { width: 100vw; }
  .hub-overlay__nav-inner { padding: 11px 18px; }
  .overlay-hero__inner { padding: 40px 18px 34px; }
  .overlay-body { padding: 40px 18px 64px; }
  .landing-why__inner { padding: 56px 22px; }
  .landing-why__grid { grid-template-columns: 1fr; }
  .landing-hero__lead { display: none; }
  .landing-only-mobile { display: block; }
  .landing-spec-grid { grid-template-columns: repeat(2, minmax(0,1fr)); gap: 12px; }
  .landing-spec-grid--scholar { grid-template-columns: 1fr; }
  /* picker becomes a snap carousel; the hand-drawn ellipse is welded to
     three-column geometry, so it steps aside for the vertical arrow */
  .landing-types__grid { display: flex; overflow-x: auto; scroll-snap-type: x mandatory;
    scroll-padding-left: 22px; scrollbar-width: none; margin: 0 -22px; padding: 4px 22px 10px; }
  .landing-types__grid > .landing-types__card-wrap { flex: 0 0 76%; scroll-snap-align: center; }
  .landing-types__ring, .landing-types__arrow { display: none; }
  .landing-types__arrow--mobile { display: block; }
  .landing-ws__grid { grid-template-columns: 1fr; }
  .landing-ws__side { display: none; }
  .landing-dock { padding: 7px; gap: 8px; }
  .landing-dock__label, .landing-dock__row { display: none; }
  /* Task 10 (a11y sweep): 26px -> 44px hit area; the dot mark (16px, via
     .landing-dock__toggle-dot) stays put, still centred by place-items. */
  .landing-dock__toggle { display: grid; width: 44px; height: 44px; }
  .landing-dock[data-open="true"] .landing-dock__row { display: flex; }
  /* Task 10 (a11y sweep): the 22px swatch dot IS the design's colour ink —
     see the brief's own "keep the visual mark small" guidance — so each
     button gets an invisible expanded hit region via ::before instead of
     growing the visible circle. getBoundingClientRect() on the button
     itself still reports 22x22 (the brief's verification script expects
     exactly this: "[], or only the eight 22px theme swatches ... verify
     that by hand"); the real tap target is the 44x44 box the ::before
     inset defines. Packed 6px apart (centres 28px apart), adjacent expanded
     regions overlap by ~16px — genuine non-overlapping 44px for all 8 needs
     ~352px of span but only ~240px is available at this pitch, so full 44px
     coverage for every swatch isn't reachable without growing the dots
     (against the brief) or wrapping the row (a bigger layout change than an
     a11y sweep should make unasked). What IS fixable, and was a real
     regression until this fix: every sibling here is position:relative with
     the implicit z-index:auto, so positioned siblings paint in DOM order —
     swatch N+1's ::before was painting OVER the trailing ~5px of swatch N's
     OWN visible dot (dot spans [c-11,c+11], next swatch's slop starts at
     c+6), so a tap on the right edge of a dot selected the NEXT theme, not
     the one you tapped. z-index:-1 sinks the slop behind every sibling's
     real content (siblings don't form their own stacking contexts), so each
     dot's own ink always wins hit-testing while the slop still fills the
     gaps between dots — verified via elementFromPoint at each swatch's own
     trailing edge, all 8 now resolve to themselves. */
  .landing-dock__swatch::before { content: ""; position: absolute; inset: -11px; z-index: -1; }
  .landing-caption { font-size: 18px; }
  /* reading order for a phone: what it is -> who it's for -> how it flows ->
     who does the work -> the room -> why not DIY -> price (the #try demo
     slots in right after the hero, ahead of the reorder proper; "why" is
     Task 12's restored section, slotted between product and pricing to
     match its desktop position — see home.html's own placement comment) */
  .landing-stack { display: flex; flex-direction: column; }
  .landing-stack > [data-sec="nav"]     { order: 0; }
  .landing-stack > [data-sec="hero"]    { order: 1; }
  .landing-stack > [data-sec="try"]     { order: 2; }
  .landing-stack > [data-sec="types"]   { order: 3; }
  .landing-stack > [data-sec="how"]     { order: 4; }
  .landing-stack > [data-sec="studio"]  { order: 5; }
  .landing-stack > [data-sec="product"] { order: 6; }
  .landing-stack > [data-sec="why"]     { order: 7; }
  .landing-stack > [data-sec="pricing"] { order: 8; }
  .landing-stack > [data-sec="cta"]     { order: 9; }
  .landing-stack > [data-sec="footer"]  { order: 10; }
}

@media (max-width: 430px) {
  .landing-wrap { padding: 48px 18px; }
  .section__inner { padding: 48px 18px; }
  .landing-hero { padding: 36px 18px 42px; }
  .landing-nav__inner { padding: 10px 14px; }
  .landing-cta { padding: 34px 18px 48px; }
  .landing-footer__inner { padding: 30px 18px; }
  .landing-why__inner { padding: 48px 18px; }
  .landing-spec-grid { gap: 10px; }
  .landing-types__grid { scroll-padding-left: 18px; margin: 0 -18px; padding: 4px 18px 10px; }
  .landing-types__grid > .landing-types__card-wrap { flex: 0 0 82%; }
}

/* ============================================================
   Reduced motion. The old home.html carried a page-wide
   "* { animation: none; transition: none; }" rule under this same
   media query; this port has no equivalent anywhere, while running four
   520-640px blurred blobs on infinite 15-21s loops (djBloomA/djBloomB
   above) plus the demo's djCaret/djBounce loops and the drawer/dock open
   transitions. Same specificity (0,1,0) as each animated selector above,
   so source order (this block is last) — not specificity — is what makes
   `none` win here; media queries add no specificity of their own.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .landing-blob { animation: none; }
  .landing-demo__dot { animation: none; }
  .landing-demo__typing-dot { animation: none; }
  .landing-drawer { transition: none; }
  .landing-dock__swatch { transition: none; }
  .landing-types__ring { transition: none; }
  /* Task 9: #try-result's entrance pop and the agent drawer's staged
     djReveal/djTypingPulse reveal + slide-in transition, same treatment as
     the mobile drawer above — .drawer-step needs an explicit opacity:1
     restore (not just animation:none) because its own non-reduced-motion
     rule declares a static opacity:0 as the pre-animation resting state;
     without this override every drawer step — including the final agent
     reply — would stay permanently invisible for reduced-motion users.
     .drawer-step--typing does NOT get the same opacity:1 restore: hub.js
     renders it with an inline style="display:flex;..." (agentDrawerHtml),
     and a non-!important class rule can never override an inline style
     regardless of specificity or source order — a display:none here would
     be silently ineffective (this file bans !important, which is what the
     pre-revamp CSS relied on for this exact override). Leaving its static
     opacity:0 in place is what actually hides it; only animation:none is
     added, to stop it being reduced then restored to 0 by djTypingPulse's
     own keyframe (a purely cosmetic no-op either way, but explicit here so
     a future reader doesn't "fix" it into the same dead rule). */
  .typing-dot { animation: none; }
  .try-result { animation: none; opacity: 1; }
  .drawer-step { animation: none; opacity: 1; }
  .drawer-step--typing { animation: none; }
  .agent-drawer { transition: none; }
  /* Belt-and-braces: landing.js already never sets data-theme-shift under
     reduced motion, so this selector should never match in practice — but a
     purely-CSS backstop means the cross-fade still can't fire even if the
     attribute is ever set some other way (devtools, a future caller). */
  html[data-theme-shift] *,
  html[data-theme-shift] *::before,
  html[data-theme-shift] *::after { transition: none; }
}
