/* ═══════════════════════════════════════════════════════════════════════════
   THE ASSESSMENT — shared primitives

   brand.css supplies the kit: --lead, --paper, --ink, the type, the corner and
   the quilt ground. This file supplies the parts every one of the three
   presentations needs identically, and nothing about layout. Layout is where
   they are supposed to differ.

   Every global rule in assessment.md §2 is enforced here rather than left to
   each build to remember:
     · one screen, one question, and no scrolling on a question screen
     · an explicit Continue on every scored question — no auto-advance
     · the CTA carries the skip text until an answer exists, then becomes
       Continue (Warby Parker's morphing CTA), so skipping costs no extra UI
       and never reads as failure
     · no back button, said once on the opener and never enforced with a dialog
     · reactions are skippable on tap
     · a–d select, Enter continues, and the affordance is visible
     · reduced motion keeps opacity and colour, and disables movement only
   ═══════════════════════════════════════════════════════════════════════════ */


/* ── THE BASE TOKENS ────────────────────────────────────────────────────────
   These live here rather than in brand.css, and that distinction cost an hour.

   brand.css is an OVERRIDE for the six older games: it retargets --yellow,
   --lead, --body and --r, and it assumes --paper / --ink / --card / --line /
   --display / --ease already exist, because each of those six declares them in
   its own inline <style>. The three new files have no inline style, so every one
   of those was undefined — which CSS treats as an invalid value, so it falls
   back to initial. The symptom was a Continue button with no fill and body text
   in pure black instead of Midnight, on a page whose accent colour worked fine
   because --lead IS in brand.css.

   Declaring them here and not in brand.css keeps the six untouched: brand.css
   stays a delta over what they already have, and this file is self-sufficient.
   Values are brand-kit.ts, so both routes agree.
*/
:root{
  --paper:#FBFBF8; --rail:#F5F4EF; --card:#FFFFFF; --line:#E4E3DE;
  --ink:#151524; --text2:#4A4943; --mute:#6E6D66; --faint:#9C9B93;
  --display:"Funnel Display","Instrument Sans",-apple-system,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,Menlo,monospace;
  --ease:cubic-bezier(.16,.84,.28,1);
}

/* The ground is quieter here than on the six. They are dense — a board, a desk,
   a canvas — and carry .16 without noticing. An assessment screen is one
   question on open paper, and at .16 the quilt was competing with the sentence
   the whole thing turns on. */
.tilefield{filter:opacity(.07)}

*,*::before,*::after{box-sizing:border-box}
html,body{height:100%;margin:0;padding:0;overflow:hidden}
body{background:var(--paper);color:var(--ink);font-family:var(--body);
  font-size:16px;line-height:1.55;-webkit-font-smoothing:antialiased}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
input,textarea{font:inherit;color:inherit}
:focus-visible{outline:2px solid var(--lead);outline-offset:3px}

/* ── the site header ──────────────────────────────────────────────────────
   Ported from web/public/new-home/index.html: fixed, out of the flow, opaque,
   hairline under it, logo at 22px — site-header.tsx's value, which the homepage
   condenses to. It is deliberately the CONDENSED bar and not the 88px open one:
   this is a two-minute flow on one screen with no scrolling, and 88px of chrome
   is 10% of a laptop's height spent on navigation nobody is going to use
   mid-assessment.

   Everything else on the page is offset by --nav-h rather than sitting under
   it — the rail, the question, the field. */
:root{ --nav-h:58px; }
.site{position:fixed;top:0;left:0;right:0;height:var(--nav-h);z-index:60;
  display:flex;align-items:center;gap:clamp(16px,2.2vw,34px);
  padding-inline:clamp(20px,3.4vw,52px);
  background:var(--paper);border-bottom:1px solid var(--line)}
.site img{height:22px;width:auto;display:block}
.site .links{display:flex;gap:clamp(16px,2.4vw,32px);margin-left:auto}
.site .links a{font-size:14px;color:var(--text2);text-decoration:none;transition:color .15s}
.site .links a:hover{color:var(--lead)}
.site .cta-nav{display:inline-flex;align-items:center;height:36px;padding:0 16px;
  background:var(--ink);color:var(--paper);font-size:13.5px;font-weight:600;
  border-radius:var(--r);text-decoration:none;transition:background .15s}
.site .cta-nav:hover{background:var(--lead);color:var(--onlead)}
/* BEGIN GENERATED NAV CSS · scripts/sync-nav.mjs · edit web/src/lib/nav.json */
/*
  THE MOBILE DRAWER. Generated — do not hand-edit; edit web/src/lib/nav.json and
  run scripts/sync-nav.mjs.

  ONE BREAKPOINT, 820px, and it is the same number in globals.css and in the
  React header. It was 820 here and 760 there, which is a band 60px wide where
  the two implementations disagreed about what a phone is. Measured, this bar's
  children fit down to 480px, so neither number was ever forced by the content —
  820 is chosen because blueprint.html already stacks its hero there, giving
  the page one mobile threshold instead of two.

  EVERY COLLAPSE RULE IS SCOPED TO html.nav-js, WHICH THE SCRIPT ADDS. Without
  it the links stay in the bar, stacked and reachable. That is the difference
  between a reader with blocked JS getting a usable header and getting a toggle
  that does nothing — and it keeps primary navigation visible to crawlers that
  do not execute JS, which is most of the AI ones. The bar's own position,
  height and ground stay with the page: blueprint and work-with-us are fixed
  with a spacer because the hero's measure-once contract depends on it, and
  skill-packs is sticky. That divergence is out of this generator's scope.
*/

/* ── GROUPS ───────────────────────────────────────────────────────────────
   Back on 2026-08-22 after being removed on 2026-08-13. See the type note in
   web/src/lib/brand.ts for what changed and for the one-child rule.

   OPEN AND CLOSE ARE CSS. :hover behind a fine-pointer query for a mouse,
   :focus-within for the keyboard. The script adds only what CSS cannot do —
   the touch branch, Escape with focus return, and the mobile accordion — so a
   dead script leaves a bar whose menus still open. Same discipline as the
   drawer below it. */
.navgrp{position:relative;display:flex;align-items:center}
.navgrp-top{display:inline-flex;align-items:center;gap:7px}
.navcaret{width:8px;height:8px;flex:none;fill:none;stroke:currentColor;
  stroke-width:1.6;transition:transform .2s var(--ease)}

/* Square, 1px ink, hard 4px offset — the kit's own button language rather than
   a soft floating card, because a dropdown is structure like everything else
   and law 8 rules out blur and radius. */
.navpanel{position:absolute;top:100%;left:0;min-width:236px;z-index:2;
  display:flex;flex-direction:column;padding:6px;
  background:var(--paper);border:1px solid var(--ink);box-shadow:4px 4px 0 var(--ink);
  opacity:0;visibility:hidden;transform:translateY(-4px);
  transition:opacity .18s var(--ease),transform .18s var(--ease),visibility .18s}
/* The bridge. Invisible, 9px, and load-bearing: without it the pointer crosses
   a gap between the trigger and the panel on the way down, :hover drops, and
   the menu closes under the cursor. */
.navpanel::before{content:"";position:absolute;left:0;right:0;top:-9px;height:9px}
.navpanel a{display:block;padding:9px 12px;font-size:14.5px;white-space:nowrap;
  transition:background .15s var(--ease)}
.navpanel a:hover,.navpanel a:focus-visible{background:var(--rail)}
/* The view-all row. A rule above it and a quieter voice: it is the way out of
   the list rather than another item in it. */
.navpanel-all{margin-top:5px;padding-top:11px;border-top:1px solid var(--line);
  font-size:13px;color:var(--mute)}

@media (hover:hover) and (pointer:fine){
  .navgrp:hover>.navpanel{opacity:1;visibility:visible;transform:none}
  .navgrp:hover>.navgrp-top .navcaret{transform:rotate(180deg)}
}
.navgrp:focus-within>.navpanel,
.navgrp[data-open]>.navpanel{opacity:1;visibility:visible;transform:none}
.navgrp:focus-within>.navgrp-top .navcaret,
.navgrp[data-open]>.navgrp-top .navcaret{transform:rotate(180deg)}

.navtoggle{display:none}
@media (max-width:820px){
  /* THE ACCORDION. Hover is not a gesture a phone has, so inside the drawer the
     panel stops floating and becomes an indented block that pushes the rows
     below it down. Nothing about the tree changes — only how it is revealed. */
  .navgrp{display:block}
  .navgrp-top{width:100%;justify-content:space-between}
  .navpanel{position:static;opacity:1;visibility:visible;transform:none;
    min-width:0;display:none;margin:0 0 8px;padding:0 0 0 14px;
    border:0;border-left:1px solid var(--line);box-shadow:none}
  .navpanel::before{display:none}
  .navgrp[data-open]>.navpanel,
  .navgrp:focus-within>.navpanel{display:block}
  .navpanel a{padding:11px 0;min-height:44px;display:flex;align-items:center;
    white-space:normal}
  .navpanel a:hover{background:none}

  /* NO SCRIPT: the bar joins the flow so it can grow to hold the stacked links
     instead of covering the page under it, and the spacer that held its place
     is no longer holding anything. */
  html:not(.nav-js) nav{position:static;height:auto;flex-wrap:wrap;
    row-gap:10px;padding-block:12px}
  html:not(.nav-js) .navlinks{display:flex;width:100%;margin:0;gap:20px}
  html:not(.nav-js) .nav-spacer{display:none}

  /* SCRIPT: the links become a panel under the bar, opened by the toggle. */
  html.nav-js .navtoggle{display:inline-flex;align-items:center;
    justify-content:center;margin-left:auto;
    /* flex:none, and it is load-bearing. The bar is a flex row, so without it
       the toggle is a shrinkable item: measured at 360px it was squeezed to
       42.3px on one page and 33.6px on another, i.e. under the 44px floor, by
       a width:44px rule that reads as if it settled the question. */
    flex:none;
    /* 44px is the tap-target floor from 8ec45a3 — HIG and WCAG 2.5.8. It is the
       box a thumb hits, which is not the size of the glyph inside it. */
    width:44px;height:44px;padding:0;background:none;
    border:1px solid var(--line);color:var(--ink);cursor:pointer}
  html.nav-js .navtoggle-bars{display:block;position:relative;width:18px;height:12px}
  html.nav-js .navtoggle-bars span{position:absolute;left:0;width:100%;height:1.5px;
    background:currentColor;transition:transform .18s var(--ease),opacity .12s linear}
  html.nav-js .navtoggle-bars span:nth-child(1){top:0}
  html.nav-js .navtoggle-bars span:nth-child(2){top:5.25px}
  html.nav-js .navtoggle-bars span:nth-child(3){top:10.5px}
  /* the bars become the close mark, so the control never moves or resizes when
     it changes meaning */
  html.nav-js nav[data-nav-open] .navtoggle-bars span:nth-child(1){
    transform:translateY(5.25px) rotate(45deg)}
  html.nav-js nav[data-nav-open] .navtoggle-bars span:nth-child(2){opacity:0}
  html.nav-js nav[data-nav-open] .navtoggle-bars span:nth-child(3){
    transform:translateY(-5.25px) rotate(-45deg)}

  html.nav-js .navlinks{position:absolute;top:100%;left:0;right:0;
    display:flex;flex-direction:column;align-items:stretch;gap:0;margin:0;
    padding:4px var(--inset) 12px;background:var(--paper);
    border-bottom:1px solid var(--line)}
  /* gap, not a space. display:flex makes the label and the arrow span flex items,
     and a flex container drops whitespace-only anonymous boxes between them —
     so the space authored in the markup vanishes and it renders "Community↗". */
  /* SCOPED TO THE BAR SO THE 16px SURVIVES — 2026-08-25, punch list G1.
     The type block further down declares nav[aria-label="Primary"] .navlinks a
     at font-size:14px, which is (0,2,2) — the same specificity this rule had as
     html.nav-js .navlinks a, and it is emitted later, so the drawer was
     rendering the BAR's 14px instead of its own 16px (measured on all three
     generated pages at 390 and at 768). Naming the bar here makes it (0,3,3).
     Unlike .navlinks above, that type rule is NOT fenced above the breakpoint:
     the drawer wants everything else in it — the colour, the line-height reset
     and the letter-spacing reset that stop a host page reaching in. Only the
     size differs between the two states, so only the size is overridden. */
  html.nav-js nav[aria-label="Primary"] .navlinks a{display:flex;align-items:center;
    gap:.35em;min-height:44px;
    font-size:16px;border-top:1px solid var(--line)}
  /* display:none, not visibility — a closed drawer has to be out of the tab
     order as well as out of sight, or the first Tab off the toggle lands on a
     link nobody can see. */
  html.nav-js nav:not([data-nav-open]) .navlinks{display:none}
}
@media (prefers-reduced-motion:reduce){ .navtoggle-bars span{transition:none} }
/* the toggle's real label — three bars are not a word */
.nav-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* THE BAR'S ONE BUTTON — 2026-08-24, Scotty: "it needs to not be black, it
   needs to be white with a border", and a border on every other page too.

   White with an ink rule and the kit's hard 4px offset — no blur, no radius,
   law 8, and the same treatment .navpanel above already uses. It was solid ink,
   which made the single button the heaviest object in an otherwise quiet bar.

   SCOPED TO THE BAR, NOT TO .btn-solid. That class is the site's general solid
   button and it dresses hero CTAs on seven pages; restyling it here would have
   turned every one of them white. This rule reaches the nav's copy only.

   ONE RULE, EVERY PAGE. The bar is a single component now, so there is no
   homepage variant to keep in step — the same button renders on the static
   pages, the (site) routes and the two workshop routes. If a per-page variant
   is ever wanted, add it here behind a body class rather than forking the bar,
   which is the thing this file was rewritten to stop. */
/* THE LOCKUP IS THE BAR'S, NOT THE PAGE'S — 2026-08-24.
   Three static pages carried their own "nav img" rule — clamp(22px,2vw,30px) —
   outside this region and rendered a 29px mark where every other surface
   rendered 36. The attribute selector is (0,1,2) against a bare nav img
   (0,0,2), so this wins wherever it lands in the cascade and the page copies
   become dead weight rather than a fight.

   NO BACKTICKS IN THIS BLOCK. It is inside renderCss's template literal, and
   quoting a selector the way the rest of this repo does closes the string. That
   has now cost four builds in three days; the check below is cheaper than the
   habit. Delete them when convenient; nothing
   depends on them now. */
nav[aria-label="Primary"] img{height:clamp(24px,2.5vw,36px);width:auto;display:block;
  transition:height .2s var(--ease)}


/* ══ THE BAR OWNS ITS OWN TYPE ═════════════════════════════════════════════
   2026-08-24. Scotty, on being told the bar was unified: "the workshops and
   resources text jumps in size" going from one page to another. It did, and the
   check that said otherwise had only measured the box — bar height, lockup,
   button — never the link text inside it.

   Diffed every computed property of every element in the bar across seven
   pages. Four leaks, all inherited from the page rather than declared by the
   bar:

     .navlinks a font-size   14px on four pages, 14.976px on contact,
                             starter-pack and automatable — those three never had
                             the rule and fell through to a page clamp
     .navlinks a color       #4A4943 on the homepage, ink on the React routes —
                             two different link colours, not one bar
     line-height             18px vs 22px, same cause
     inherited base          the React routes run a 17px body against the static
                             pages' 16px, and carry a -0.0675px letter-spacing
                             that reached the button

   A bar that inherits is a bar that differs. Everything it renders is declared
   here now, in absolute units, with letter-spacing and line-height reset so a
   host page cannot reach in. The values are the homepage's, which is the one
   Scotty asked every other page to look like.

   NO BACKTICKS IN THIS BLOCK — it is inside renderCss's template literal. */
nav[aria-label="Primary"]{font-size:16px;line-height:1.4;letter-spacing:normal;
  font-family:var(--body,"Instrument Sans",system-ui,sans-serif);
  /* THE GROUND AND THE INSET, OWNED — 2026-08-24. contact, starter-pack and
     automatable painted the bar rgba(251,251,248,.92) with a 10px backdrop blur
     while every other page painted it solid, and sat 3px further in because
     their --inset resolves differently. Both are visible, both were per-page,
     both are the bar's business now. Solid, because that is the homepage's and
     because a blurred bar over a Blaze quilt tints orange.
     POSITION IS DELIBERATELY NOT SET HERE. Those three are sticky and occupy
     flow; the other four are fixed and carry a hand-placed .nav-spacer.
     Forcing one would either double the gap or slide content under the bar,
     and neither is visible at rest — this is integration, not appearance. */
  background:var(--paper,#FBFBF8);backdrop-filter:none;-webkit-backdrop-filter:none;
  padding-inline:clamp(20px,3.4vw,52px);
  /* AND THE LAYOUT. The flex gap was 31.68px on the pages that declare it in
     their own nav rule and "normal" — none at all — on the three that do not,
     which is the last 3px anyone could see. A bar that does not declare its own
     display, alignment and gap is not one bar. */
  display:flex;align-items:center;gap:clamp(16px,2.2vw,34px);
  border-bottom:1px solid var(--line,#E4E3DE)}
/* THIS IS THE HORIZONTAL BAR'S LAYOUT, AND IT IS FENCED ABOVE THE BREAKPOINT
   ON PURPOSE — 2026-08-25, punch list G1.

   It used to be unconditional, and that silently broke the mobile drawer on
   every generated page. The drawer rule above is

       html.nav-js .navlinks{...align-items:stretch;gap:0...}      (0,2,1)

   and this one was

       nav[aria-label="Primary"] .navlinks{...align-items:center;gap:...}  (0,2,1)

   IDENTICAL SPECIFICITY, and this block is emitted LATER in the same stylesheet,
   so inside the drawer the bar's horizontal layout won. Measured at 390x844 with
   the drawer open, on /, /workshops and /workshops/claude-cowork alike:
   align-items resolved to center and gap to 20px, so the two rows rendered
   86.3px and 79.8px wide at x=151.8 and x=155.1 — content-width, centred, with
   floating hairlines above each instead of full-bleed rows. Same at 768.

   A min-width fence is the fix rather than more specificity, because the two
   states then cannot overlap at all: a later edit that adds another horizontal
   property to this rule can no longer leak into the drawer. BP + 1 is the
   complement of the drawer's max-width:BP, so this introduces no new number --
   820 is still the site's one threshold.

   display:flex is inside the fence with the rest because the drawer declares its
   own display:flex; nothing below the breakpoint depends on this rule. */
@media (min-width:821px){
  nav[aria-label="Primary"] .navlinks{display:flex;align-items:center;
    gap:clamp(20px,2vw,30px);
    /* EVERY margin, not just the auto one. contact, starter-pack and automatable
       added margin-right:28.8px to this block from their own stylesheets, which
       pushed the links 29px left of where every other page put them — the last
       thing anyone could see, and invisible to a check that only measured the
       elements themselves rather than the space around them. */
    margin:0 0 0 auto}
}
nav[aria-label="Primary"] .navlinks a,
nav[aria-label="Primary"] .navgrp-top{font-size:14px;line-height:22px;font-weight:400;
  letter-spacing:normal;color:#4A4943;text-decoration:none;
  /* OPACITY, WHICH IS WHY THEY LOOKED LIKE DIFFERENT COLOURS. contact,
     starter-pack and automatable set opacity:.75 on these links. Every property a
     colour check reads was identical — same rgb(74,73,67), same weight, same
     family — and they still rendered visibly lighter, because opacity is not a
     colour and does not show up in one. A pixel diff of the bar found it; a
     property diff never would have. */
  opacity:1}
nav[aria-label="Primary"] .navlinks a:hover,
nav[aria-label="Primary"] .navgrp-top:hover{color:var(--signal,#FC7800)}
nav[aria-label="Primary"] .navpanel a{font-size:14.5px;line-height:1.4;letter-spacing:normal;
  font-weight:400;color:var(--ink,#151524)}

/* THE BUTTON'S BOX, ALSO THE BAR'S — 2026-08-24. Same class of bug as the
   lockup above and found the same way: contact, starter-pack and automatable
   rendered 140x48 at 15px where every other page rendered 121x40 at 13.5px,
   because the nav-specific sizing rule lives outside this region on the pages
   that have it and simply does not exist on the ones that do not. Those three
   fell through to the site-wide .btn. Owned here now, so the bar carries its
   own button on every surface. */
nav[aria-label="Primary"] .btn{display:inline-flex;align-items:center;justify-content:center;
  gap:9px;font-weight:600;border:1px solid transparent;white-space:nowrap;
  height:clamp(36px,2.8vw,40px);font-size:clamp(12.5px,0.94vw,13.5px);
  padding:0 clamp(14px,1.3vw,20px);letter-spacing:normal;line-height:1}

nav[aria-label="Primary"] .btn-solid{
  background:var(--paper);color:var(--ink);
  border:1px solid var(--ink);box-shadow:4px 4px 0 var(--ink)}
/* PRESS INTO THE SHADOW — the homepage hero button's motion, which the bar's
   button did not have. On the static pages it came from a page-level
   .btn:hover rule; on the React routes that rule does not exist, so the nav
   button sat inert while the hero button moved. It belongs to the bar.

   The button travels the exact offset of its own shadow and the shadow
   collapses to zero, so it lands ON the shadow rather than near it — that is
   what makes it read as pressing in rather than sliding. Active adds nothing
   further except a hair of scale, because it is already down. */
nav[aria-label="Primary"] .btn-solid{transition:transform .16s var(--ease,cubic-bezier(.7,0,0,1)),
  box-shadow .16s var(--ease,cubic-bezier(.7,0,0,1)),background .18s}
nav[aria-label="Primary"] .btn-solid:hover,
nav[aria-label="Primary"] .btn-solid:focus-visible{background:#fff;
  transform:translate(4px,4px);box-shadow:0 0 0 var(--ink,#151524)}
nav[aria-label="Primary"] .btn-solid:active{
  transform:translate(4px,4px) scale(.985);box-shadow:0 0 0 var(--ink,#151524)}
@media (prefers-reduced-motion:reduce){
  nav[aria-label="Primary"] .btn-solid{transition:box-shadow .14s,background .18s}
  nav[aria-label="Primary"] .btn-solid:hover,
  nav[aria-label="Primary"] .btn-solid:focus-visible,
  nav[aria-label="Primary"] .btn-solid:active{transform:none}
}

/* THE CONDENSE RULE, also the bar's. The class is toggled by the component's
   own effect, but the rule that acts on it lived only in the static pages'
   stylesheets — so the React routes toggled html.tight against nothing and the
   bar never shrank on /workshops, the Cowork page or any (site) route. */
html.tight nav[aria-label="Primary"]{height:var(--nav-tight,clamp(50px,3.9vw,58px))}
html.tight nav[aria-label="Primary"] img{height:clamp(20px,1.9vw,26px)}
/* END GENERATED NAV CSS */

/* ── type ────────────────────────────────────────────────────────────────── */
.q{font-family:var(--display);font-weight:500;letter-spacing:-.03em;line-height:1.06;
  /* Scaled off vw ALONE this overflowed a short window: at 1280x720 the Q9
     screen ran 41px past the fold and, with html{overflow:hidden} enforcing
     "no scrolling on a question", Continue was unreachable. It takes whichever
     axis binds — the same mistake the homepage hero made with its cell. */
  margin:0;font-size:clamp(25px,min(3.1vw,4.4vh),46px)}
/* an aside inside a headline — same size and colour, lighter weight */
.q .q-lt{font-weight:300}
.sub{margin:14px 0 0;font-size:clamp(14px,1.05vw,17px);color:var(--text2);line-height:1.55}
.why{margin:10px 0 0;font-size:13px;color:var(--mute)}
.eyebrow{font-family:var(--mono);font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--mute);margin:0}

/* ── the choice ladder ───────────────────────────────────────────────────── */
/* Stacked, not wrapped: these are full sentences, and a flex-wrap row would
   set them at ragged widths that read as a paragraph broken into pieces. The
   grid keeps one per line. The SHAPE is the pill's — same 999px radius — so a
   single-select choice looks like a single-select choice everywhere in the
   assessment, whether the options are two words or a full sentence. */
.opts{display:grid;gap:9px;margin:26px 0 0;max-width:640px}
.opt{display:block;text-align:left;padding:15px 22px;
  border:1px solid var(--line);background:var(--card);border-radius:999px;
  transition:border-color .14s,background .14s,color .14s}
.opt:hover{border-color:var(--ink)}
.opt[aria-checked="true"]{border-color:var(--ink);background:var(--paper)}
.opt .t{font-size:15.5px;line-height:1.45}

/* multi-select pills and single-select pills */
.pills{display:flex;flex-wrap:wrap;gap:9px;margin:26px 0 0;max-width:660px}
.pill{padding:11px 16px;border:1px solid var(--line);border-radius:999px;background:var(--card);
  font-size:14.5px;transition:border-color .14s,background .14s,color .14s}
.pill:hover{border-color:var(--ink)}
.pill[aria-checked="true"]{background:var(--lead);border-color:var(--lead);color:var(--onlead);font-weight:600}

textarea.job{width:100%;max-width:640px;margin:24px 0 0;min-height:104px;resize:none;
  padding:14px 16px;border:1px solid var(--line);border-radius:var(--r);background:var(--card);
  font-size:16px;line-height:1.5}
textarea.job::placeholder{color:var(--faint)}

/* ── the morphing CTA ────────────────────────────────────────────────────── */
/* align-self matters: .screen is display:contents in a1, so the button's real
   parent is a flex COLUMN whose default align-items is stretch — inline-flex
   does not save it, and it rendered 640px wide. */
.cta{display:inline-flex;align-self:flex-start;flex:none;align-items:center;gap:11px;margin-top:28px;height:50px;
  padding:0 24px;border-radius:var(--r);font-size:15.5px;font-weight:600;
  background:var(--ink);color:var(--paper);transition:background .16s,color .16s,box-shadow .16s,opacity .16s}
/* Hover lives with the other colour decisions, further down, because it has to
   carry :not([disabled]) — see the note above .cta:hover:not([disabled]). */
.cta[data-state="skip"]{background:transparent;color:var(--mute);
  box-shadow:inset 0 0 0 1px var(--line);font-weight:400}
.cta[data-state="skip"]:hover{color:var(--ink);box-shadow:inset 0 0 0 1px var(--ink)}
.cta .ent{font-family:var(--mono);font-size:10px;letter-spacing:.12em;opacity:.62}

/* ── the dial ─────────────────────────────────────────────────────────────
   Sized off the cell, not off the viewport, so it sits in the same lattice as
   everything else. The arc and the hand are the only things that move. */
.dialrow{display:grid;grid-template-columns:auto 1fr;grid-template-rows:auto auto;
  gap:0 22px;align-items:center;margin-top:26px;max-width:520px}
.dial-q{grid-column:2;align-self:end;margin:0 0 6px;font-size:15px;color:var(--text2)}
.dial{grid-row:1 / span 2;width:132px;height:132px;cursor:grab;touch-action:none;
  border-radius:50%}
.dial:active{cursor:grabbing}
.dial .d-track{fill:var(--card);stroke:var(--line);stroke-width:2}
.dial .d-arc{stroke:var(--lead);stroke-width:6;stroke-linecap:round}
.dial .d-tick{stroke:var(--line);stroke-width:2}
.dial .d-hand{stroke:var(--ink);stroke-width:3.5;stroke-linecap:round;
  transition:none}
.dial .d-hub{fill:var(--ink)}
.dial:focus-visible{outline:2px solid var(--lead);outline-offset:4px}
.read{grid-column:2;align-self:start;margin:0;font-size:15px;color:var(--mute);
  display:grid;gap:3px}
.read span{white-space:nowrap}
.read b{font-family:var(--display);font-weight:500;font-size:21px;color:var(--ink);
  letter-spacing:-.02em}
.read .sep{opacity:.4;margin:0 4px}
@media (prefers-reduced-motion:reduce){ .dial .d-hand{transition:none} }

/* ── the reaction, as a popup ─────────────────────────────────────────────
   Three shapes were tried. A full screen of its own was six extra screens and
   six extra taps inside a flow that promises "under two minutes". A static line
   in the layout reserved height on every question whether or not it had
   anything to say, and moved the button when it did.

   A popup owns neither problem: it is out of the flow entirely, so nothing on
   the page moves when it arrives, and it costs no tap — it appears when an
   answer exists and leaves with the question. It sits at the foot of the copy
   column rather than centre-screen, so it never covers the options it is about.
*/
/* Bottom-CENTRE put a dark card level with the dark Continue button and the two
   read as a pair of buttons — one of which does nothing when you press it. It
   lives in the bottom-right corner instead, out of the answer column entirely. */
.pop{position:fixed;left:auto;right:26px;bottom:26px;z-index:45;display:flex;
  justify-content:center;pointer-events:none;padding-inline:22px}
.pop-in{max-width:min(44vw,480px);background:var(--ink);color:var(--paper);
  border-radius:var(--r);padding:15px 20px;font-size:15px;line-height:1.45;
  box-shadow:0 10px 34px -14px rgba(21,21,36,.55);
  border-left:3px solid var(--lead);
  opacity:0;transform:translateY(10px);
  transition:opacity .26s var(--ease),transform .26s var(--ease)}
.pop.on .pop-in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  .pop-in{transform:none;transition:opacity .2s linear}
}

/* ── the level rail — assessment.md §2, "the rail is the progress bar" ─────
   Down the LEFT edge, all five visible and faint, and a level fills when its
   boundary question is answered and STAYS filled. It is what makes the scoring
   legible by question five, so the result reads as a confirmation rather than
   as a surprise. */
.rail{position:fixed;left:0;top:var(--nav-h);bottom:0;width:190px;padding:26px 0 26px 26px;
  display:flex;flex-direction:column;justify-content:center;gap:16px;z-index:20;
  border-right:1px solid var(--line);background:color-mix(in srgb,var(--paper) 88%,transparent)}
.prog{padding-right:22px;opacity:0;transition:opacity .3s var(--ease)}
.rail.live .prog{opacity:1}
.prog-lb{margin:0;font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--faint)}
.prog-n{margin:4px 0 0;font-family:var(--display);font-weight:500;font-size:26px;
  letter-spacing:-.02em;color:var(--ink);line-height:1}
.rail-hd{padding-top:15px;border-top:1px solid var(--line);margin-right:22px}
/* TWO VOICES, NOT ONE — 2026-08-26 (Scotty): "I would like different fonts for
   'your level so far' and 'fills in as you answer'."
   They were the same mono at two sizes, which read as one thing broken in half
   by the ladder. They are not one thing. The head is a LABEL for the column and
   keeps the mono: uppercase, letterspaced, the same voice every other label in
   this instrument uses. The foot is a SENTENCE about how the column behaves,
   and a sentence set in mono reads as code. It moves to the body face. */
.rail-hd{margin:0;font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--faint);padding-right:22px}
.rail-ft{font-family:var(--body);font-size:11.5px;letter-spacing:0;
  text-transform:none;line-height:1.4;color:var(--faint);padding-right:22px}
/* ── the spine — five names with nothing joining them read as a list of links ──
   DRAWN IN SEGMENTS BETWEEN THE BOXES, not as one line behind them.
   2026-08-26 (Scotty): "I can see the dividing line that connects all of them
   through the rounded rectangle squares, and I don't want that when they're
   blank — I'd rather not show that line through that box."

   Two full-height lines used to run from the top rung to the bottom one, and
   each dot was supposed to occlude them by painting itself over the top. On the
   lattice skin it does not: that page overrides the dot to `background:
   transparent` so the boxes read as empty outlines, and a transparent box hides
   nothing.

   Painting the dot opaque again was the obvious fix and it is the wrong one —
   the rail's own ground there is a horizontal gradient (`rgba(scrim,.9)` to
   `rgba(scrim,.5)`), so there is no single colour a 9px chip could be to
   disappear into it. Any value picked would be right at one x and visibly wrong
   at another.

   So the line simply stops at each box and starts again after it. One segment
   per rung, sitting in the gap BELOW that rung's dot, which is what makes the
   colour rule trivial: the ladder runs 5 at the top down to 1 at the bottom, so
   the segment below rung L joins L to L-1 and is lit exactly when L itself is
   reached. No sibling has to look upward at another.

   Geometry is in percentages of the row rather than pixels so it survives a
   font-size or line-height change: from 5px below this dot's centre to 5px
   above the next one's, both clearing the 9px box by half a pixel. */
.rungs{position:relative}
.rail .lv:not(:last-child)::after{content:"";position:absolute;left:28px;width:1px;
  top:calc(50% + 5px);bottom:calc(-50% + 5px);background:var(--line);
  transition:background .4s var(--ease)}
.rail .lv.on:not(:last-child)::after,
.rail .lv.now:not(:last-child)::after{background:var(--lead)}
/* THE DIM STATE MOVED OFF .lv AND ONTO ITS CHILDREN. It was `opacity:.34` on
   the row, which an ::after inherits — the unreached segments would have come
   out at a third of a hairline and the spine would have faded away above the
   reader instead of staying a ladder. The children carry it now, so the row
   itself stays at full strength and only the num, box and name dim. */
.rail .lv{position:relative;display:grid;grid-template-columns:14px 9px 1fr;
  align-items:center;gap:0 10px;padding:9px 0}
.rail .lv>*{opacity:.34;transition:opacity .3s var(--ease)}
.rail .lv .num{font-family:var(--mono);font-size:10px;color:var(--faint);text-align:left}
.rail .lv .dot{width:9px;height:9px;flex:none;border:1px solid var(--ink);border-radius:2px;
  background:var(--paper);transition:background .35s var(--ease),border-color .35s var(--ease)}
.rail .lv .nm{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase}
.rail .lv .tag{display:none;font-family:var(--mono);font-size:8.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--onlead);background:var(--lead);border-radius:2px;
  padding:2px 5px;grid-column:3;justify-self:start;margin-top:5px}
.rail .lv.on>*,.rail .lv.now>*{opacity:1}
.rail .lv.on .dot{background:var(--lead);border-color:var(--lead)}
.rail .lv.on .num{color:var(--text2)}
.rail .lv.now .nm{color:var(--ink);font-weight:500}
.rail .lv.now .tag{display:block}

/* ── the level bar ───────────────────────────────────────────────────────────
   "What if you had those five across the top? As you answer, the pills start
   filling up and you start leveling up." It replaces a1's left rail, which was
   saying the same thing next to a mosaic that was saying something narrower —
   "isn't the thing on the left duplicitous with the thing on the right".
   ────────────────────────────────────────────────────────────────────────── */
:root{ --bar-h:62px; }
.rail.off{display:none}
.levelbar{position:fixed;top:var(--nav-h);left:0;right:0;height:var(--bar-h);z-index:40;
  display:flex;align-items:center;gap:16px;padding:0 clamp(18px,2.4vw,34px);
  background:color-mix(in srgb,var(--paper) 94%,transparent);
  border-bottom:1px solid var(--line);backdrop-filter:none}
.lb-count{margin:0;flex:none;min-width:52px;font-family:var(--mono);font-size:13px;
  letter-spacing:.06em;color:var(--ink);font-variant-numeric:tabular-nums}
.lb-pills{position:relative;display:flex;align-items:center;gap:clamp(6px,1.1vw,18px);
  flex:1;min-width:0}
/* the rail the pills sit on — without it five outlined capsules read as five
   empty input fields rather than as rungs of one ladder */
.lb-pills::before{content:"";position:absolute;left:10px;right:10px;top:50%;height:1px;
  background:var(--line)}
.lvpill{position:relative;flex:0 1 auto;min-width:0;display:flex;align-items:center;gap:7px;
  padding:5px 12px 5px 7px;border:1px solid var(--line);border-radius:999px;background:var(--paper);
  transition:background .4s var(--ease),border-color .4s var(--ease)}
.lvpill b{width:16px;height:16px;flex:none;display:grid;place-items:center;border-radius:50%;
  background:var(--rail);font-family:var(--mono);font-size:9px;font-weight:500;color:var(--mute)}
.lvpill span{font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--mute);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.lvpill.on{background:var(--lead);border-color:var(--lead)}   /* same fill as every
     other selected control — see the note under the buttons */
.lvpill.on b{background:rgba(255,255,255,.28);color:#fff}
.lvpill.on span{color:#fff}
.lvpill.now{outline:2px solid var(--ink);outline-offset:1px}
@media (max-width:820px){
  .lb-count{min-width:0;font-size:11.5px}
  .lvpill span{display:none}
  .lvpill{justify-content:center;padding:7px 0}
  .lvpill b{font-size:11px}
}

/* ── the job, in three boxes ────────────────────────────────────────────────
   One box could not hold "an underwriter for corporate reinsurance for
   pharmaceutical equipment", and a dropdown of industries was rejected outright.
   ────────────────────────────────────────────────────────────────────────── */
.fields{display:grid;gap:12px;margin:22px 0 0;max-width:620px}
.field{display:grid;gap:6px}
.flab{font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--faint)}
.field input,.field select,.otherbox{width:100%;height:48px;padding:0 15px;border:1px solid var(--line);
  border-radius:var(--r);background:var(--card);font-family:var(--body);font-size:15.5px;color:var(--ink)}
.field input:focus,.field select:focus,.otherbox:focus{outline:2px solid var(--lead);outline-offset:1px}
/* box-sizing is declared rather than inherited: the height above has to match
   the text inputs exactly for the stack to read as one set of controls, and a
   1px border under content-box makes a select 50px against an input's 48. */
.field select{box-sizing:border-box;appearance:none;-webkit-appearance:none;cursor:pointer;
  /* The caret is drawn rather than left to the UA, because a native select
     arrow is the one part of this instrument that would look like a form. */
  background-image:linear-gradient(45deg,transparent 50%,var(--mute) 50%),
                   linear-gradient(135deg,var(--mute) 50%,transparent 50%);
  background-position:calc(100% - 19px) 21px,calc(100% - 14px) 21px;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:38px}
/* Unanswered reads quieter than answered — the placeholder convention, applied
   to a control that has no placeholder of its own. */
.field select:invalid,.field select[data-empty="1"]{color:var(--faint)}
.otherbox{margin:11px 0 0;max-width:420px}

/* ── the stepped bar ────────────────────────────────────────────────────────
   Five stops. "There's too many variables there, like 5.7, 5.6."
   ────────────────────────────────────────────────────────────────────────── */
.hoursrow{margin:22px 0 0;max-width:460px}
.hlab{margin:0 0 14px;font-size:14px;color:var(--text2)}
.hbar{position:relative;height:26px;cursor:pointer;touch-action:none}
.hbar:focus-visible{outline:2px solid var(--lead);outline-offset:4px}
.hline,.hfill{position:absolute;top:50%;left:0;height:3px;margin-top:-1.5px;border-radius:2px}
.hline{right:0;background:var(--line)}
.hfill{background:var(--lead);transition:width .18s var(--ease)}
.hdot{position:absolute;top:50%;width:13px;height:13px;margin:-6.5px 0 0 -6.5px;padding:0;
  border:1px solid var(--line);border-radius:50%;background:var(--card);cursor:pointer}
.hdot.on{background:var(--lead);border-color:var(--lead)}
.hknob{position:absolute;top:50%;width:24px;height:24px;margin:-12px 0 0 -12px;
  border:1px solid var(--ink);border-radius:5px;background:var(--card);pointer-events:none;
  box-shadow:0 1px 3px rgba(21,21,36,.12);transition:left .18s var(--ease)}
.hticks{display:flex;justify-content:space-between;margin-top:9px}
.hticks span{font-family:var(--mono);font-size:10.5px;color:var(--faint)}
.hticks span.on{color:var(--ink);font-weight:500}

/* Back is a real button now, sitting to the LEFT of Next: black rule, white
   ground, black label. It reads as the pair's other half rather than as a
   text link someone tucked beside it — but it is outlined where Next is
   filled, so which one is the forward move is never in question. */
/* The gap above the pair belongs to the ROW, not to Next. While .cta carried
   its own margin-top and Back did not, align-items:center measured Back
   against a box 28px taller than itself and sat it half that distance high —
   the two buttons were off by 14px for no reason anyone could see. */
.ctarow{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:28px}
.ctarow .cta{margin-top:0}
.back{display:inline-flex;align-items:center;height:50px;padding:0 20px;cursor:pointer;
  background:#fff;color:var(--ink);border:1px solid var(--ink);border-radius:var(--r);
  font-family:var(--body);font-size:15px;font-weight:500;
  transition:background .14s var(--ease),color .14s var(--ease)}
.back:hover{background:var(--ink);color:#fff}
.back:focus-visible{outline:2px solid var(--lead);outline-offset:2px}
@media (max-height:800px){ .back{height:46px} }

/*
  WHITE TEXT ON SIGNAL ORANGE.

  Two instructions, both explicit: "the orange bubbles should have white text in
  them, not black text \u2014 same goes for the continue button", and then, after a
  pass shipped on Blaze 4, "change the button color back to orange".

  For the record, because the next person to touch this will wonder: white on
  #FC7800 measures 2.59:1, against the 4.5:1 AA wants at this label size. The
  alternatives were Midnight on Signal (6.72:1) or white on #E21200 (4.86:1),
  and both were looked at and set aside \u2014 the first loses the white text, the
  second reads red rather than orange. Changing `color` on this one rule is the
  whole fix if that trade is ever re-made.
*/
.pill[aria-checked="true"],.cta{background:var(--lead);color:#fff}
.pill[aria-checked="true"]{border-color:var(--lead)}
/* The choice rows lost their letter chip, and that chip was carrying the whole
   selected state — an orange square against a white row. Without it the row
   fills like a pill, for the same reason the pill does: it is the only mark on
   the screen, and a border alone is not one. */
.opt[aria-checked="true"]{background:var(--lead);border-color:var(--lead);color:#fff}
/* Hover inverts rather than deepening the fill: white ground, Midnight label,
   and a 2px Signal ring in the same orange the resting button is filled with.
   The ring is inset box-shadow, not border, so the button does not grow 2px
   and shove the proof line on hover.

   The :not([disabled]) guard is load-bearing. .cta[disabled] resets background
   and color but never box-shadow, so an unguarded hover rule paints the orange
   ring onto the greyed-out Continue while it is still waiting for an answer. */
.cta:hover:not([disabled]){background:#fff;color:var(--ink);box-shadow:inset 0 0 0 2px var(--lead)}
.cta[disabled]{background:none;border:1px solid var(--line);color:var(--faint);cursor:default}
.cta[disabled] .ent{opacity:.45}

/* ── the count, and the affordance the spec asks to be visible ───────────── */
.hud{position:fixed;right:26px;top:calc(var(--nav-h) + 18px);z-index:20;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.14em;text-transform:uppercase;color:var(--mute)}
.kbd{position:fixed;left:216px;bottom:22px;z-index:20;font-family:var(--mono);font-size:10px;
  letter-spacing:.12em;color:var(--faint)}

/* ── results ─────────────────────────────────────────────────────────────── */
/* FIXED, not absolute. Absolute takes its containing block from whatever the
   mount happens to sit in — half a column in a1, a 500px plate in a3 — so the
   results rendered inside the question's furniture: the headline wrapped to four
   words and clipped mid-word, and in a1 the copy ran across the column divider.
   The results page is a page. It takes the viewport, minus the rail. */
.results{position:fixed;inset:0;top:var(--nav-h);left:190px;overflow-y:auto;
  padding:7vh 6vw 12vh;z-index:30;background:var(--paper)}
@media (max-width:1000px){ .results{left:0} }
@media (max-width:1000px){
  .kbd{display:none}
  .pop{left:16px;right:16px;justify-content:center}
  .pop-in{max-width:none}
}
.results .wrap{max-width:640px;margin:0 auto}
.results h1{font-family:var(--display);font-weight:500;font-size:clamp(30px,4vw,52px);
  letter-spacing:-.035em;line-height:1.04;margin:12px 0 0}
.results h2{font-family:var(--display);font-weight:500;font-size:clamp(21px,2.2vw,30px);
  letter-spacing:-.028em;margin:0}
.block{margin-top:42px;padding-top:26px;border-top:1px solid var(--line)}
.block:first-of-type{border-top:0;padding-top:0}
.block p{margin:12px 0 0;font-size:16px;line-height:1.62;color:var(--text2)}
.block .big{font-family:var(--display);font-weight:500;font-size:clamp(23px,2.5vw,34px);
  letter-spacing:-.028em;line-height:1.15;color:var(--ink);margin:10px 0 0}
.block ul{margin:14px 0 0;padding-left:18px}
.block li{font-size:15.5px;line-height:1.6;color:var(--text2);margin:6px 0}
.paste{margin:14px 0 0;padding:15px 17px;background:var(--rail);border:1px solid var(--line);
  border-radius:var(--r);font-family:var(--mono);font-size:12.5px;line-height:1.75;white-space:pre-wrap}
.note{margin-top:14px;padding-left:13px;border-left:2px solid var(--lead);
  font-size:14px;line-height:1.55;color:var(--mute)}

/* ── the gate ────────────────────────────────────────────────────────────── */
/* Scoped to the email box, not to every input on the screen — the opt-in is
   also an <input> and a 52px-tall full-width checkbox is not a checkbox. */
.gate input[type="email"]{width:100%;max-width:420px;margin:22px 0 0;height:52px;padding:0 16px;
  border:1px solid var(--line);border-radius:var(--r);background:var(--card);font-size:16px}
/* The label wraps the sentence, so the whole line is the hit target. */
.optin{display:flex;align-items:flex-start;gap:9px;max-width:420px;margin:13px 0 0;
  font-size:13.5px;line-height:1.5;color:var(--text2);cursor:pointer}
.optbox{flex:none;width:15px;height:15px;margin:2px 0 0;accent-color:var(--lead);cursor:pointer}
.gate ul{margin:12px 0 0;padding-left:18px}
.gate li{font-size:14.5px;line-height:1.6;color:var(--text2);margin:5px 0}
.gate .sub{margin-top:26px}

/* ── motion ──────────────────────────────────────────────────────────────── */
.screen{animation:rise .42s var(--ease) both}
@keyframes rise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){
  /* opacity and colour are kept; only movement goes — assessment.md §2 */
  .screen{animation:fade .3s ease both}
  @keyframes fade{from{opacity:0}to{opacity:1}}
  *{transition-duration:.01ms !important}
}


/* ── short windows ────────────────────────────────────────────────────────
   A 720-tall laptop is not a phone: the desktop layout is right, it just has
   less room. Everything vertical tightens; nothing is removed. Specificity is
   raised past `.dialrow` because each build sets its own dial margin. */
@media (max-height:800px){
  .side,.plate{padding-top:3.5vh;padding-bottom:3.5vh}
  .sub{margin-top:10px}
  .opts,.pills{margin-top:18px}
  body .dialrow{margin-top:16px}
  .cta{margin-top:20px;height:46px}
  .ctarow{margin-top:20px}
  .ask{padding-top:3vh;padding-bottom:3.5vh}
}


/* The required marker on q2's labels. Blaze, because it is the same "this one
   matters" signal the buy buttons carry, and the label around it stays quiet
   grey — a whole label in the accent would shout at four of five fields. */
.field .req{color:#FE7001;font-weight:600}
