/* SYSTEM: 2.0
 * ==========================================================================================
 * THE CLIENT INTAKE PORTAL -- STYLESHEET
 *
 * This is a CLIENT-FACING surface. Everything below follows from that one fact.
 *
 * 1. MOBILE FIRST, NOT MOBILE-TOLERANT. Every rule outside the one media query at the bottom
 *    is written for a phone held in one hand. The desktop layout is the adaptation, and it is
 *    twelve lines long. The client is going to open this from an email on a phone; that is the
 *    real screen and it gets the real design.
 *
 * 2. NO OPERATOR CHROME. There is no rail, no sidebar, no toolbar, no table. One column, one
 *    thing to do. The Client Manager stylesheet this palette comes from has all of those and
 *    they are all deliberately absent here.
 *
 * 3. THE STATUS COLOURS CARRY MEANING, AND ONLY THREE THINGS MAY SAY THEM.
 *      GREEN means done. Nothing else may be green -- not a heading, not a button, not a tick
 *      on something that is merely started. If green appears, a step is finished.
 *      BLUE means in progress. NEUTRAL means not started.
 *      THERE IS NO RED IN THIS FILE. Not as an error colour, not as a warning, not as a border.
 *      A client who cannot open their link has not done anything wrong, and a red screen tells
 *      them they have. The one failure surface in this project is styled exactly like the
 *      ordinary ones.
 *      *** THIS IS A DELIBERATE CLIENT-FACING CHOICE, NOT AN OMISSION. *** Both sibling 2.0
 *      tools define --red: #b3261e and both are right to -- an operator needs to be told a run
 *      failed. This surface has no failure that is the reader's fault, so it has no red, and
 *      the next person to reach for one should read this line first. Amber is absent on the same
 *      terms: nothing on a client screen has meant "warning" yet, and when something does it
 *      comes from the family's #9a6b00 rather than from a colour picker.
 *      DESIGN_REFERENCE.md §7b.
 *
 * 4. EVERY COLOUR IS A TOKEN. No hex below the token block. The brand navy and blue are copied
 *    character for character from itv-client-manager/css/app.css, which copied them from the
 *    company's own live stylesheet. If the brand changes it changes there first.
 *
 * 5. CONTRAST IS MEASURED, NOT ASSUMED. Every ratio in a comment below was computed off the two
 *    hex values it names, not estimated. The lowest pairing on the page is 4.61:1.
 *
 * 6. THE TWO TYPEFACES ARE THE FAMILY'S, SELF-HOSTED. Lexend for body, Bebas Neue for display.
 *    This file said "system font stack only" for the whole of its first month, and the argument
 *    was a good one -- see the TYPE block below for why it was still wrong, and what closes it.
 *
 * 7. EVERY VALUE THAT REPEATS IS A TOKEN, NOT JUST EVERY COLOUR. Sizes, leading, weights,
 *    tracking, radii, shadows and easing all live in the block below. There is no bare size in a
 *    rule any more; a rule that wanted a new one would have to add it here, in front of the
 *    others, which is the point.
 * ==========================================================================================
 */

/* ==========================================================================================
   00  THE TWO TYPEFACES -- SELF-HOSTED, AND WHY THE OLD RULE WAS WRONG
   ==========================================================================================

   THE RULE THIS REPLACES, IN FULL, BECAUSE IT WAS NOT A LAZY RULE:

       "System font stack only. A webfont is a second request before the client can read
        anything, and on a phone on a bad signal that is the difference between 'it opened'
        and 'it is broken'."

   Everything in that sentence is true and the conclusion still does not follow, for three
   reasons that only became available later:

   1. `font-display: swap` MEANS THE TEXT IS NEVER WAITING ON THE FONT. The fallback stack paints
      on the first frame and is swapped when the file lands. The failure the rule describes -- a
      client staring at nothing -- is the behaviour of `font-display: block`, which is the
      DEFAULT, and which is why the fear was well-founded before this line existed.

   2. THE FILES ARE HASHED AND IMMUTABLE (build.js, public/_headers). The second request is paid
      once, ever, per client. Every subsequent screen in the intake -- and there are four -- takes
      it from cache without a network round trip.

   3. IT IS 8.6KB, NOT A FONT SERVICE. Four woff2 subsets, in this repo, from
      `itv-aeo-tool/fonts` where they already were, `unicode-range`d so a client whose name is
      plain Latin never downloads the -ext half. No fonts.googleapis.com, no second origin, no
      render dependency on somebody else's uptime, and nothing to go stale.

   AND THE THING THE OLD RULE COST WAS NOT SMALL. Both sibling 2.0 tools name a real typeface
   first; this one named none, and that single fact was the largest reason a screenshot of this
   portal did not read as the same product as a screenshot of the AEO tool
   (DESIGN_REFERENCE.md §7a). A client-facing surface is the LAST place that should look like a
   different company.

   BOTH FAMILIES ARE OFL 1.1 AND THE LICENCE TEXT SHIPS BESIDE THEM -- public/fonts/OFL-Lexend.txt
   and public/fonts/OFL-BebasNeue.txt. That is what makes redistributing them legitimate rather
   than merely convenient; deleting either file is a licence violation, not a tidy-up.
   ========================================================================================== */

@font-face {
  font-family: 'Bebas Neue';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/bebas-neue-latin.441b026d.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
                 U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
                 U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Bebas Neue';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/bebas-neue-latin-ext.a724a4b6.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
                 U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
                 U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Lexend ships as ONE VARIABLE FILE per subset covering 100-900, which is why a whole range is
   declared rather than four separate faces: the browser instances the weight it is asked for out
   of one download.
 *
 * THE RANGE STOPS AT 700 HERE AND AT 600 IN THE AEO TOOL, AND THAT IS DELIBERATE ON BOTH SIDES.
 * That file caps at 600 because 600 is the heaviest weight its design uses, and an open `100 900`
 * would let a stylesheet reach a weight nobody chose. The same argument gives a different number
 * here: THIS surface sets its titles, its wordmark and its card headings at 700 -- a client-facing
 * page has fewer words and they have to carry further. The cap is still "what the design uses".
 *
 * IT MATTERS THAT IT IS NOT LEFT AT 600. A variable face asked for a weight above its declared
 * range does not fail and does not synthesise -- it CLAMPS. Every 700 in this file would have
 * rendered at 600, the page would have looked slightly soft, and nothing anywhere would have said
 * so. Verified in the browser rather than assumed: see MASTER_DOC §24. */
@font-face {
  font-family: 'Lexend';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/lexend-latin.1ec8f6ee.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
                 U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
                 U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Lexend';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/lexend-latin-ext.368c86e9.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
                 U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
                 U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ==========================================================================================
   01  TOKENS
   ========================================================================================== */

:root {
  /* ---- BRAND -- copied from itv-client-manager/css/app.css, not chosen here --------------- */
  --brand-navy:      #063a6c;   /* the header bar. THE company colour */
  --brand-blue:      #2494e0;   /* the bright half of the brand */
  --on-brand:        #ffffff;   /* text on navy -- 11.48:1 */
  --on-brand-dim:    #b9d9f5;   /* secondary text on navy -- 7.82:1 */

  /* ---- THE CALL TO ACTION: ORANGE. THE VIOLET IS DEAD. -------------------------------------
   *
   * Gerek's ruling, family-wide. The violet was this surface's own invention -- chosen so a
   * client-facing button would not look like an operator's Save -- and inventing a colour was the
   * mistake. THE COMPANY ALREADY HAS AN ACTION COLOUR and it is in the brand: legacy reserves
   * `--orange: #dd6b00` for "brand / CTA / action accents ONLY (RUN, Finalize, ...)". That is the
   * same rule the violet was carrying here, in the house colour instead of a made-up one.
   *
   * COPIED, NOT EYEBALLED, from `itv-aeo-tool/shared/itv-tokens.css` -- the file the AEO Article
   * Tool 2.0 draws from, which took them from the legacy design. --brand-navy and --brand-blue
   * below were ALREADY character for character identical to that file; the two tools have been
   * drawing from the same well the whole time and only the action colour differed.
   *
   * -------------------------------------------------------------------------------------------
   * THE TEXT ON IT IS BLACK, AND THAT IS A MEASUREMENT RATHER THAN A TASTE
   * -------------------------------------------------------------------------------------------
   *
   * WHITE ON #dd6b00 IS 3.40:1. It clears the 3:1 floor for LARGE text and fails the 4.5:1 floor
   * for normal text. There is no third answer: which of the two applies is decided by the SIZE and
   * the CASE of the type sitting on the fill, so this file now carries BOTH inks and each one is
   * locked to the condition that earns it.
   *
   * Measured across the candidates, on the fill AND on its hover, because a button under a cursor
   * still has to be readable:
   *
   *     ink        on #dd6b00   on #c25e00      both >= 4.5?
   *     #ffffff       3.40         4.29             no    <- NORMAL text. Legal only when large
   *     #101828       5.22         4.14             no    <- this file's own --ink
   *     #0d0a06       5.81         4.60             yes
   *     #000000       6.18         4.89             YES   <- and it invents nothing
   *
   * ORDINARY BUTTONS TAKE THE BLACK, and that arithmetic is unchanged: they are Lexend at the body
   * size, so the large-text allowance is not available to them and pure black is the only
   * candidate that clears 4.5:1 on the fill and on the hover without inventing a hex.
   *
   * THE COMMITTING BUTTON TAKES THE WHITE, AND ONLY BECAUSE IT NOW HAS A DISPLAY FACE. `.btn--cta`
   * sets Bebas Neue at --t-cta (24px) and `text-transform: uppercase` IN THE SAME RULE AS THE
   * FILL, so the size, the case and the ground cannot drift apart in a later edit. 24px is 18pt,
   * which is where large text begins, and every glyph on that button is at cap height -- so it is
   * genuinely large rather than nominally large.
   *
   * THIS IS THE ONE GENUINE ACCESSIBILITY FAILURE AVAILABLE IN THIS FILE, and it is available in
   * exactly one shape: white ink with the size taken off. DESIGN_REFERENCE.md §7b names it -- "do
   * not adopt white without adopting the display face". check.js does not take that on trust: it
   * reads the rendered size rule out of `.btn--cta` on every run, decides WHICH floor applies from
   * it, and fails if the size ever drops below the one that makes the white legal.
   *
   * Both brand orange values are kept exactly as the brand file defines them; the only thing
   * decided here is what is written on top of them, and under what condition. */
  --brand-orange:        #dd6b00;   /* legacy --orange / itv-tokens --cta. THE committing button */
  --brand-orange-strong: #c25e00;   /* hovered -- itv-tokens --cta-strong */
  --brand-orange-ink:    #b35700;   /* orange as TEXT or a border on a light ground -- 4.61:1 on --bg */
  --brand-orange-wash:   #fdf1e6;   /* the faintest orange */
  --on-orange:           #000000;   /* ORDINARY buttons -- 6.18:1 on the fill, 4.89:1 on the hover */
  /* THE NAME CARRIES THE PRECONDITION ON PURPOSE. This is not "the other white"; it is the ink
   * that is only legal under display type at 24px, and a rule reaching for it without setting
   * --font-display and --t-cta is reaching for a 3.40:1 failure. itv-tokens calls this --on-cta. */
  --on-orange-display:   #ffffff;   /* .btn--cta ONLY -- 3.40:1, which is AA LARGE and nothing else */

  /* THE FOCUS RING IS THE BRAND BLUE, from the same file. A ring is not an action, so it has no
   * business wearing the action colour -- and an orange ring around an orange button is invisible
   * at exactly the moment a keyboard user needs to see it. */
  --focus-ring:      rgba(36, 148, 224, .45);

  /* ---- SURFACES -------------------------------------------------------------------------- */
  --bg:              #f6f8fb;   /* the page */
  --panel:           #ffffff;   /* a card */
  --panel-2:         #f1f4f9;   /* a quiet fill */
  --line:            #e4e9f0;   /* hairline */
  --line-strong:     #d3dae4;
  --panel-3:         #e8edf4;   /* a quiet fill, pressed. Step 1's choice buttons on hover */

  /* ---- TEXT ------------------------------------------------------------------------------ */
  --ink:             #101828;   /* body     -- 17.75:1 on a card */
  --ink-dim:         #4e5a6a;   /* secondary --  7.01:1 on a card */
  --ink-mute:        #5a6675;   /* meta      --  5.85:1 on a card */

  /* ---- THE ACCENT: the brand's deep blue, for a CHOSEN state and for a link ----------------
   *
   * From `itv-aeo-tool/shared/itv-tokens.css`, character for character, like the rest. It is the
   * same #0e5aa6 as --doing-ink below, and they are kept as separate names on purpose: one means
   * "a client picked this", the other means "this step is in progress". A single token doing both
   * jobs is a token that cannot be changed for one of them.
   *
   * THIS BLOCK DID NOT EXIST UNTIL THE VIOLET WAS REMOVED, and its absence was a live defect for
   * one deploy: `.choice.is-on` and the new segmented control were both pointed at `var(--accent)`
   * on the assumption it was already here -- it is in Client Manager and in the AEO tool, not in
   * this repo. An undefined custom property does not error, it resolves to NOTHING, so a selected
   * button rendered transparent with dark text and still looked like a button. Caught by clicking
   * through the deployed page, not by reading it. See the token check in check.js, added the same
   * afternoon so it cannot happen twice. */
  --accent:          #0e5aa6;   /* white on it -- 6.93:1 */
  --accent-strong:   #063a6c;   /* hovered: straight to the company navy -- 11.48:1 */
  --on-accent:       #ffffff;

  /* ---- THE THREE STATUS COLOURS -----------------------------------------------------------
   *
   * ALL SIX OF THESE MOVED, AND NOT ONE OF THEM MOVED FAR. That is the entire point.
   *
   * Every value below used to be a NEAR miss on the family's: #116b39 against the family's
   * #1a7a4d, #e6f4ec against #e9f2ee, #e4eefb against #eef7fd, #eef1f6 against #e8edf4. Nobody
   * could see any one of them. What a viewer CAN see is the accumulation -- a green that is not
   * quite the green in the other two tools, on a page that is otherwise trying to be them -- and
   * A NEAR MISS READS AS SLOPPINESS IN A WAY A DELIBERATE DIFFERENCE DOES NOT, because there is
   * no way to tell it was a choice. DESIGN_REFERENCE.md §7a item 4.
   *
   * So they are the family's exact values now, copied from itv-client-manager/css/app.css and
   * itv-aeo-tool/shared/itv-tokens.css, which name them --green / --green-wash / --green-fill,
   * --blue-run / --blue-run-wash / --blue-run-fill and --neutral-ink / --neutral-bg. THE NAMES
   * STAY LOCAL because they say what the colour MEANS on this surface -- "done", not "green" --
   * and that is the rule §3 of this file's header depends on.
   *
   * RE-MEASURED, NOT ASSUMED. Every ratio below was recomputed against the new ground it sits on;
   * the done chip is the one that moved, from 5.81:1 to 4.68:1, and it still clears AA with room.
   * THE GREEN IS THE SACRED ONE AND IT IS NOW THE FAMILY'S GREEN -- #1a7a4d is what "done" means
   * in all three 2.0 tools, and white on it is 5.34:1, which is what the pressed-button flash
   * needs (see .btn.is-done). */
  --done-ink:        #1a7a4d;   /* family --green. On --done-bg -- 4.68:1. White on it -- 5.34:1 */
  --done-bg:         #e9f2ee;   /* family --green-wash */
  --done-edge:       #d1e4db;   /* family --green-fill */

  --doing-ink:       #0e5aa6;   /* family --blue-run, already exact. On --doing-bg -- 6.39:1 */
  --doing-bg:        #eef7fd;   /* family --blue-run-wash */
  --doing-edge:      #deeffa;   /* family --blue-run-fill */

  --todo-ink:        #4a5568;   /* family --neutral-ink. On --todo-bg -- 6.40:1 */
  --todo-bg:         #e8edf4;   /* family --neutral-bg */
  /* THE ONE EDGE THE FAMILY HAS NO VALUE FOR, so it is kept rather than invented. The family's
   * --neutral-line is #7d8a9c, a deliberately heavy 3.51:1 control boundary; taking it would have
   * made "not started" the loudest of the three chips, which is backwards. #dfe4ec sits a shade
   * under its own fill exactly as --done-edge and --doing-edge sit under theirs, so all three
   * chips still read as one set. */
  --todo-edge:       #dfe4ec;

  /* ---- SHAPE -------------------------------------------------------------------------------
   *
   * THE FAMILY'S THREE, AT THE FAMILY'S VALUES, MEANING WHAT THE FAMILY MEANS BY THEM.
   *
   * These were 8 / 12 / 16 -- every radius exactly one step rounder than the other two 2.0 tools.
   * The rounding was not the real problem. THE NAMES WERE: this file's --r-md was 12px, which is
   * itv-client-manager's --r-lg, so the same token name pointed at a different size in two repos
   * that copy rules between each other. A rule pasted across would silently change shape, look
   * fine, and nobody would ever find it. DESIGN_REFERENCE.md §7a item 3.
   *
   * The comments are Client Manager's own, verbatim, because the meaning is the thing being
   * adopted here and not merely the number. Anything reaching for a radius on this surface has to
   * answer "is it a chip, a control, or a card?" and the answer is already written down. */
  --r-sm:   6px;    /* a chip, a tag, a small pill's cousin */
  --r-md:   8px;    /* a control: input, button */
  --r-lg:   12px;   /* a card, a panel, a drawer */
  --r-pill: 999px;

  /* THE RESTING CARD SITS ON THE PAGE. IT DOES NOT FLOAT ABOVE IT.
   *
   * This was `0 1px 2px /.04, 0 6px 20px /.06` -- twenty pixels of blur against Client Manager's
   * three, and the single largest visual difference between a card here and a card there
   * (DESIGN_REFERENCE.md §7a item 2). Twenty pixels of soft grey under every card is not a detail
   * that shows up on close inspection; it is the first thing a screenshot says, on every screen.
   *
   * This is itv-client-manager's --shadow-sm, character for character. The second layer is what
   * makes it read as a seated edge rather than a hairline: 2px of near-contact plus 3px of
   * settle. */
  --shadow-card:  0 1px 2px rgba(16, 24, 40, .05), 0 1px 3px rgba(16, 24, 40, .04);
  --shadow-lift:  0 2px 4px rgba(16, 24, 40, .06), 0 12px 28px rgba(16, 24, 40, .10);
  --shadow-bar:   0 -2px 16px rgba(16, 24, 40, .08);   /* the fixed bar, lit from below */

  /* THE MODAL BACKDROP, AND IT DIMS WITH NAVY RATHER THAN WITH BLACK.
   *
   * Dark enough that the form behind it is plainly out of reach, light enough that the client can
   * still see their own answers underneath and knows what they are about to lock.
   *
   * The colour is the change: this was `rgba(16, 24, 40, .45)`, the ink black. Both siblings dim
   * with the company navy at the same .45, and they agree with each other about it -- which makes
   * it one of the few values in this whole file where "the family" has a single unambiguous
   * answer. One token, and it is the difference between a dialog that feels like part of the
   * product and one that feels like a browser default. */
  --scrim-fill:   rgba(6, 58, 108, .45);

  /* ---- SPACE -------------------------------------------------------------------------------
   *
   * *** A DELIBERATE CLIENT-FACING CHOICE, AND THE NAME IS PART OF IT ***
   *
   * The rhythm matches the family up to 16px and then opens out: 4 8 12 16 -- 24 32 48, against
   * the operator tools' 4 8 12 16 -- 20 24 32 40 56. Generous spacing is in the client-facing
   * brief and it is KEPT, not closed (DESIGN_REFERENCE.md §7b). There is no 20px step here
   * because nothing on this surface wants one.
   *
   * AND THAT IS EXACTLY WHY THESE ARE NOT CALLED --s-*. The family's --s-5 is 20px; this file's
   * fifth step is 24px. Renaming --gap-5 to --s-5 would be the mechanical half of "match the
   * family" performed at the cost of the honest half: a rule copied from Client Manager into this
   * repo, or out of it, would keep its token name and silently change its spacing. A different
   * name for a different ladder is the thing that makes the divergence survivable.
   *
   * So: --gap-* stays, on purpose, and this comment is the reason it stays. */
  --gap-1: 4px;
  --gap-2: 8px;
  --gap-3: 12px;
  --gap-4: 16px;
  --gap-5: 24px;   /* the family's fifth step is 20px -- see above */
  --gap-6: 32px;   /* the family's sixth step is 24px */
  --gap-7: 48px;   /* the family's seventh step is 32px */

  /* ---- TYPE: THE TWO FACES ------------------------------------------------------------------
   *
   * The stacks are itv-aeo-tool/shared/itv-tokens.css's, character for character.
   *
   * --font is Lexend, and it is everything on this site a client reads.
   *
   * --font-display is Bebas Neue: condensed, all-caps, letter-spaced. It is never used for a
   * sentence. ON THIS SURFACE IT HAS EXACTLY ONE JOB -- the committing button -- and that is a
   * narrower brief than it has in the AEO tool, where it also carries the header, the section
   * labels and the stat values. The reason is the no-operator-chrome rule: there are no section
   * labels here to set, and a client's own business name is not a thing to put in a condensed
   * all-caps face. The token is family-standard so a later screen CAN reach for it; nothing but
   * .btn--cta does today.
   *
   * THE FALLBACK STACKS ARE REAL AND THEY ARE LOAD-BEARING, not politeness. `Arial Narrow` and
   * `Avenir Next Condensed` are on essentially every Mac and Windows machine, so the frame before
   * the woff2 lands is still condensed rather than a reflow out of and back into a normal-width
   * face. And .btn--cta sets `text-transform: uppercase` in its own rule rather than leaning on
   * Bebas Neue having no lowercase -- so the CASE that earns the white ink its large-text
   * allowance survives the font failing to load at all. */
  --font-display: 'Bebas Neue', 'Oswald', 'Avenir Next Condensed', 'Arial Narrow',
                  'Helvetica Neue Condensed', sans-serif;
  --font: 'Lexend', -apple-system, BlinkMacSystemFont, 'Segoe UI Variable Text', 'Segoe UI',
          system-ui, Roboto, 'Helvetica Neue', Arial, sans-serif;

  /* ---- TYPE: THE SCALE -----------------------------------------------------------------------
   *
   * THIS FILE HAD NO TYPE SCALE AT ALL UNTIL NOW. Every size was a literal in the rule that used
   * it, which is survivable on a small surface and stops being survivable the moment a visual
   * page gets built -- a page inventing sizes is exactly how eleven sizes become nineteen, one
   * reasonable decision at a time. Adding the ladder BEFORE Step 4 is cheaper than retrofitting
   * it after (DESIGN_REFERENCE.md §7c).
   *
   * These are the eleven sizes this surface already used, named -- not a new ladder imposed on it.
   * Three near-duplicates were folded in on the way (1.3 and 1.4 leading into 1.25 and 1.45, and
   * a stray .08em label tracking onto the .8px the other label already used), because two values
   * a pixel apart are not a scale, they are the absence of one.
   *
   * *** --t-base IS 17px AND THAT IS A DELIBERATE CLIENT-FACING CHOICE ***
   * The family's base is 15px. The operator tools are read all day by somebody fluent in them;
   * this is read once, on a phone, by a chiropractor who is not looking at screens for a living.
   * The size is the accessibility decision, not the aesthetic one, and it is KEPT
   * (DESIGN_REFERENCE.md §7b). It also happens to be the iOS zoom floor for a text input -- see
   * .q__box -- so on this surface those two arguments arrive at the same number. */
  --t-xxs:   13px;   /* a chip, a section label, the save line under the bar */
  --t-xs:    14px;   /* the footer, a why-line */
  --t-sm:    15px;   /* meta, a muted line, an answer already given */
  --t-md:    16px;   /* a segment, a dialog's body, the back link */
  --t-base:  17px;   /* THE BODY. See above -- 17, not 15, and not 16 */
  --t-lg:    18px;   /* the wordmark, a finalized answer */
  --t-xl:    19px;   /* a question */
  --t-2xl:   20px;   /* a card title */
  --t-3xl:   21px;   /* a dialog title; a question on a wide screen */
  --t-title:    27px;   /* the page title, on a phone */
  --t-title-lg: 34px;   /* the page title, from 720px up */

  /* THE DISPLAY SIZE, AND IT IS THE ONLY ONE. 24px is 18pt, which is where WCAG's large-text
   * allowance begins, which is the entire reason white is legal on the orange. It is not a
   * styling number and it is not free to change -- see --on-orange-display above, and .btn--cta
   * below, where it is set in the same rule as the fill so the two cannot drift apart. */
  --t-cta:   24px;

  /* ---- TYPE: LEADING, WEIGHT, TRACKING -------------------------------------------------------
   *
   * --lh-body IS THE SECOND HALF OF THE 17px DECISION and is deliberate for the same reason: the
   * family reads 1.5 and 1.6, and a page read once on a phone gets the air. */
  --lh-tight:  1.25;   /* a title, a segment label -- something that must not wrap loosely */
  --lh-snug:   1.45;   /* a question, an answer: a line or two of consequence */
  --lh-normal: 1.5;    /* a paragraph inside a card */
  --lh-body:   1.55;   /* THE BODY. A deliberate client-facing softening -- see above */

  /* The family runs 300/400/500/600; this one runs 400/500/600/700 and skips the light. A page
   * with forty words on it has nothing for a 300 to do, and its titles have to carry the screen
   * on their own. The 700 is why the Lexend @font-face above declares `300 700` rather than the
   * AEO tool's `300 600` -- a variable face CLAMPS above its range instead of failing. */
  --w-normal: 400;
  --w-medium: 500;
  --w-semi:   600;
  --w-bold:   700;

  /* TRACKING COMES IN TWO KINDS AND THEY ARE NOT INTERCHANGEABLE.
   *
   * --ls-3 is the FAMILY's display-face value, from itv-tokens, at the number itv-components.css
   * spends on its own committing button. Bebas Neue without tracking is a wall; every use of it in
   * every 2.0 tool is tracked.
   *
   * ONLY THE THIRD STEP IS DEFINED, AND IT KEEPS ITS NUMBER. The family's ladder is 1 / 1.5 / 2 /
   * 3px and this surface spends exactly one rung of it. Declaring the other three "for later"
   * would put three tokens in this file that nothing reads, and the numbering is what makes that
   * safe to do: --ls-3 means the same thing here as it does in the other two repos, so --ls-1 and
   * --ls-2 can arrive later, from the family's values, without renumbering anything.
   *
   * The three below are body-face optical corrections, which is a different job: a 34px title
   * needs pulling in, an 18px wordmark and a 13px all-caps label need pushing out. They are named
   * for what they sit ON rather than by step number, so nothing can mistake one kind for the
   * other. */
  --ls-3: 2px;      /* .btn--cta, matching itv-components.css */

  --ls-title:    -.2px;   /* a large title, pulled in */
  --ls-wordmark:  .2px;   /* the wordmark, opened up a hair */
  --ls-label:     .8px;   /* a 13px all-caps label -- the only place caps appear outside the CTA */

  /* ---- MOTION --------------------------------------------------------------------------------
   *
   * Colour and border only, on a hover or a focus. Nothing on this site slides, fades in or
   * appears, and all of it is off under prefers-reduced-motion (see the reset below).
   *
   * THE TWO SIBLINGS DISAGREE HERE -- Client Manager eases at 120ms on a cubic-bezier, the AEO
   * tool at a flat 200ms -- so this is a pick rather than a copy. --ease takes Client Manager's,
   * because that is the file whose header calls itself the template and because 120ms is what a
   * hover should cost: fast enough to feel like the control responding rather than the page
   * animating.
   *
   * --ease-slow is a separate token because it does a separate job. The progress strip's fill is
   * not a hover; it is a width crossing real distance to say "one more of your answers landed",
   * and at 120ms that reads as a jump rather than as movement. 200ms is the AEO tool's value and
   * it is the right one for the only thing on this site that actually travels. */
  --ease:      120ms cubic-bezier(.4, 0, .2, 1);
  --ease-slow: 200ms ease;
}

/* ==========================================================================================
   02  RESET AND BASE
   ========================================================================================== */

*, *::before, *::after { box-sizing: border-box; }

/* THE `hidden` ATTRIBUTE ACTUALLY HIDES THINGS. A SAFETY NET, NOT THE FIX.
 *
 * `hidden` is not a property of an element; it is a UA stylesheet rule, `[hidden] { display:
 * none }`, with effectively no specificity -- so ANY author rule that sets `display` on the same
 * element silently defeats it. That shipped: `.card3__summary { display: flex }` beat it, and an
 * empty chip and a live "Change" link rendered on every unanswered Step 3 card while the code
 * setting `hidden = true` ran correctly every time.
 *
 * The card was fixed by CONSTRUCTION -- it attaches one presentation or the other and never
 * hides anything (see showOnly() in js/step3-render.js). This rule is here so the NEXT element
 * somebody hides cannot fail the same way silently. It is a floor, and it is not permission to
 * go back to hiding things that should not be in the document at all. */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;   /* iOS must not resize our type when the phone rotates */
}

body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font);
  /* 17px, not the family's 15. A DELIBERATE CLIENT-FACING CHOICE -- see --t-base and --lh-body in
     the token block, where the argument and the divergence are both written down. */
  font-size: var(--t-base);
  line-height: var(--lh-body);
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

/* Nothing on this site is decorative-motion. One transition, and it is off for anybody who has
   asked their machine for less. */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ==========================================================================================
   03  THE SHELL
   ========================================================================================== */

.site-header {
  background: var(--brand-navy);
  color: var(--on-brand);
  padding: var(--gap-4) var(--gap-4);
}

.wordmark {
  margin: 0;
  font-size: var(--t-lg);
  font-weight: var(--w-bold);
  letter-spacing: var(--ls-wordmark);
  color: var(--on-brand);
}

/* *** 680px IS A DELIBERATE CLIENT-FACING CHOICE *** and so is the header above it having no
   sticky and no toolbar. The operator tools run to a 1680-1700px ceiling with a rail down one
   side, because they have things to navigate BETWEEN. This has one column and one thing to do, so
   a rail here would be furniture and a sticky bar would be chrome with nothing in it. Keeping the
   family's page ceiling would not have made this look more like the family; it would have made a
   single column of questions float in the middle of a very wide empty page.
   DESIGN_REFERENCE.md §7b. */
.wrap {
  width: 100%;
  max-width: 680px;
  margin: 0 auto;
  padding: var(--gap-6) var(--gap-4) var(--gap-7);
}

.site-footer {
  padding: 0 var(--gap-4) var(--gap-6);
  text-align: center;
  color: var(--ink-mute);
  font-size: var(--t-xs);
}

/* ==========================================================================================
   04  PAGE HEAD AND COPY
   ========================================================================================== */

.page-title {
  margin: 0 0 var(--gap-3);
  font-size: var(--t-title);
  line-height: var(--lh-tight);
  font-weight: var(--w-bold);
  letter-spacing: var(--ls-title);
  /* A name can be long and it can be one unbroken word. Neither may push the page sideways. */
  overflow-wrap: anywhere;
}

.lede {
  margin: 0 0 var(--gap-5);
  color: var(--ink-dim);
  font-size: var(--t-base);
}

/* THE ONE-TIME THANK-YOU, under the welcome, for somebody who finalized a step seconds ago.
 *
 * It replaced a pop-up the client had to dismiss (see js/step1.js), so its whole job is to cost
 * them nothing: one line, no card, no icon, no button. It uses --done-ink because that is what
 * this project's green means and this sentence is about something being done -- it is not a
 * fourth status colour and it is not a success banner for an ordinary load, which §10 still
 * forbids. 6.20:1 on the page. */
.thanks {
  margin: 0 0 var(--gap-4);
  color: var(--done-ink);
  font-size: var(--t-base);
  font-weight: var(--w-semi);
}

.section-label {
  margin: 0 0 var(--gap-3);
  font-size: var(--t-xxs);
  font-weight: var(--w-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--ink-mute);
}

/* ==========================================================================================
   05  THE STEP LIST -- the whole point of the checklist screen
   ========================================================================================== */

.step-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--gap-3);
}

/*
 * ONE TAP TARGET PER STEP, AND IT IS THE WHOLE CARD.
 *
 * Not a "Start" link inside a card -- the card. A small link inside a large box is the single
 * most common way a phone screen becomes annoying: the thing that looks tappable is tappable
 * and the 90% of it that also looks tappable is not. min-height is 76px against a 44px floor,
 * because this is the only control on the screen and it can afford to be generous.
 */
.step-card {
  display: flex;
  align-items: center;
  gap: var(--gap-4);
  width: 100%;
  min-height: 76px;
  padding: var(--gap-4);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  color: inherit;
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: box-shadow var(--ease), border-color var(--ease), transform var(--ease);
}

.step-card:hover {
  border-color: var(--line-strong);
  box-shadow: var(--shadow-lift);
}

.step-card:active { transform: translateY(1px); }

.step-card:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
  border-color: var(--brand-blue);
}

/* The number. Quiet on purpose -- it is an ordering aid, not a label, and the client is looking
   for the words next to it. */
.step-num {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: var(--r-pill);
  background: var(--panel-2);
  color: var(--ink-dim);
  font-size: var(--t-sm);
  font-weight: var(--w-bold);
}

.step-body {
  flex: 1 1 auto;
  min-width: 0;   /* lets a long name wrap instead of stretching the flex row */
}

.step-name {
  display: block;
  font-size: var(--t-base);
  font-weight: var(--w-semi);
  color: var(--ink);
  overflow-wrap: anywhere;
}

.step-meta {
  display: block;
  margin-top: var(--gap-1);
  font-size: var(--t-xs);
  color: var(--ink-mute);
}

/* The chevron. A pure affordance; it says "this goes somewhere" without any words. */
.step-go {
  flex: 0 0 auto;
  width: 10px;
  height: 10px;
  border-right: 2px solid var(--ink-mute);
  border-bottom: 2px solid var(--ink-mute);
  transform: rotate(-45deg);
}

/* ==========================================================================================
   06  THE STATUS CHIP -- THE ONLY THING ON THIS SITE THAT MAY USE THE STATUS COLOURS
   ========================================================================================== */

.chip {
  display: inline-block;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  border: 1px solid;
  font-size: var(--t-xxs);
  font-weight: var(--w-semi);
  white-space: nowrap;
}

/* NOT STARTED. Neutral, and neutral is correct -- an untouched step is not a problem. */
.chip--todo  { color: var(--todo-ink);  background: var(--todo-bg);  border-color: var(--todo-edge); }

/* IN PROGRESS. Blue, the brand's own colour. */
.chip--doing { color: var(--doing-ink); background: var(--doing-bg); border-color: var(--doing-edge); }

/* DONE. The only green in the file. */
.chip--done  { color: var(--done-ink);  background: var(--done-bg);  border-color: var(--done-edge); }

/* ==========================================================================================
   07  CARDS AND BUTTONS
   ========================================================================================== */

.card {
  padding: var(--gap-5);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
}

.card > :first-child { margin-top: 0; }
.card > :last-child  { margin-bottom: 0; }

.card-title {
  margin: 0 0 var(--gap-3);
  font-size: var(--t-2xl);
  font-weight: var(--w-bold);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 0 var(--gap-5);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  font: inherit;
  font-weight: var(--w-semi);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--ease), border-color var(--ease);
}

.btn:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
}

/* THE ORDINARY ORANGE BUTTON. Lexend, body size, BLACK ink -- 6.18:1 on the fill and 4.89:1 on
   the hover. "Try again" on a dead-end screen is the only thing wearing this today: it is the one
   button on that screen and it recovers rather than commits, so it takes the colour without
   taking the display face. */
.btn--primary {
  background: var(--brand-orange);
  color: var(--on-orange);
}
.btn--primary:hover { background: var(--brand-orange-strong); }

/* ------------------------------------------------------------------------------------------
 * THE COMMITTING BUTTON -- AND ITS SIZE IS IN THE SAME RULE AS ITS COLOUR, ON PURPOSE
 * ------------------------------------------------------------------------------------------
 *
 * "Save and finalize", and the "Yes, finalize" inside the confirmation dialog. The two controls
 * in this app that lock a client's answers, and the only two things wearing white on the orange.
 *
 * WHITE ON --brand-orange IS 3.40:1. That clears the 3:1 floor for LARGE text and fails the
 * 4.5:1 floor for normal text, so THE SIZE AND THE CASE BELOW ARE NOT STYLING -- THEY ARE WHAT
 * MAKES THE COLOUR LEGAL. --t-cta is 24px, which is 18pt, which is where large text begins.
 * `text-transform: uppercase` puts every glyph at cap height, so it is genuinely large rather
 * than nominally large -- and, unlike relying on Bebas Neue having no lowercase, it holds even
 * on the frame before the woff2 lands and on a machine where it never does.
 *
 * THEY ARE WRITTEN TOGETHER BECAUSE APART THEY WOULD DRIFT. A later edit dropping this to 17px
 * to match the quiet button beside it would take the one control that commits a client's answers
 * below AA, and NOTHING ON THE SCREEN WOULD LOOK WRONG. That is the whole failure mode, and it is
 * why check.js reads this rule's font-size out of the deployed stylesheet, decides which contrast
 * floor applies from the number it finds, and fails on the smaller one.
 *
 * The padding is the family's shape at this size; the 52px floor from .btn still governs the tap
 * target, which is what a phone actually needs.
 * ------------------------------------------------------------------------------------------ */
.btn--cta {
  background: var(--brand-orange);
  color: var(--on-orange-display);
  font-family: var(--font-display);
  font-size: var(--t-cta);          /* LOAD-BEARING. Do not lower without re-measuring the ink */
  font-weight: var(--w-normal);     /* Bebas Neue has one weight and it is 400 */
  letter-spacing: var(--ls-3);
  text-transform: uppercase;        /* LOAD-BEARING with the size above -- cap height is the point */
}
.btn--cta:hover { background: var(--brand-orange-strong); }

.btn--quiet {
  background: var(--panel);
  color: var(--ink-dim);
  border-color: var(--line-strong);
}
.btn--quiet:hover { background: var(--panel-2); }

.btn--block { display: flex; width: 100%; }

/* ------------------------------------------------------------------------------------------
 * A BUTTON THAT ANSWERS FOR ITSELF
 *
 * Feedback belongs ON the control that was pressed. The save state used to live in a grey line
 * in the opposite corner of the bar; it was correct, live, and far enough away that Gerek
 * pressed Save three times on the live site believing it was dead. See js/button-state.js.
 * ------------------------------------------------------------------------------------------ */

/* The label is a span so its text can be swapped without rebuilding the button -- rebuilding
   would destroy the spinner and, worse, drop the keyboard's focus. */
.btn__label { display: inline-block; }

/* THE SPINNER EXISTS AT REST AND IS MERELY INVISIBLE. Collapsed to zero width with no margin, so
   entering the working state does not reflow the bar and slide the other button under a finger
   that may be about to tap again. */
.btn__spin {
  width: 0;
  height: 14px;
  margin-right: 0;
  border: 2px solid currentColor;
  border-radius: var(--r-pill);
  border-right-color: transparent;
  opacity: 0;
  transition: none;
}

.btn.is-working .btn__spin {
  width: 14px;
  margin-right: var(--gap-2);
  opacity: .55;
  animation: btn-spin .7s linear infinite;
}

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

/* WORKING. Dimmed and un-pressable, and the LABEL carries the whole message -- which is what
   keeps this honest under prefers-reduced-motion, where the reset at the top of this file stops
   the spinner turning and leaves a static ring. Somebody who has asked their machine for less
   motion still reads "Saving…". */
.btn.is-working {
  cursor: default;
  opacity: .85;
}

.btn--quiet.is-working { background: var(--panel-2); }

/* DONE. THE SANCTIONED GREEN, ruled by Gerek: an outcome the client asked for, on the control
   they pressed, for a second and a half.
 *
 * §10 says green means Done and nothing else may be green. That rule protects the STATUS CHIPS
 * -- it exists so a styling decision can never make a claim about a client's data. This is not a
 * new green: it is --done-ink itself, borrowed briefly, and it describes an event rather than a
 * record. White on it is 5.34:1 -- re-measured when --done-ink became the family's #1a7a4d. */
.btn.is-done,
.btn--quiet.is-done,
.btn--primary.is-done,
.btn--cta.is-done {
  background: var(--done-ink);
  border-color: var(--done-ink);
  color: var(--on-brand);
  opacity: 1;
}

/* The hover rules above are more specific than they look once a state class is on. Held, so a
   mouse resting on the button does not undo the green mid-flash. */
.btn--primary.is-done:hover,
.btn--cta.is-done:hover,
.btn--quiet.is-done:hover { background: var(--done-ink); }

/* NO TRANSITION INTO EITHER STATE, and this is a fix rather than a preference.
 *
 * `.btn` carries `transition: background var(--ease)` for hover, which is right for a hover and
 * wrong for this. Entering the done state sets the text to white and the background to green;
 * with the transition running, the background spends 150ms crossing from --panel to --done-ink
 * while the text is ALREADY white -- so the label is white-on-near-white and effectively
 * invisible for a fifth of a second. Measured in the browser: `backgroundColor` read
 * `rgb(255,255,255)` with `color` reading `rgb(255,255,255)` on the frame the class landed.
 *
 * The whole purpose of these two states is to be seen the instant they are entered, so they are
 * entered instantly. Leaving them keeps the transition -- fading back to the ordinary label is
 * the one moment here where a fade is the right answer. */
.btn.is-working,
.btn.is-done { transition: none; }

.btn:disabled { cursor: default; }

/* The back link on a step screen. A link, not a button -- going back is not an action with a
   consequence, and giving it a button's weight would suggest it is. It keeps a 44px target
   anyway, because it is the only way off this screen on a phone. */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-2);
  min-height: 44px;
  margin-bottom: var(--gap-3);
  color: var(--doing-ink);
  font-size: var(--t-md);
  font-weight: var(--w-semi);
  text-decoration: none;
}
.back-link:hover { text-decoration: underline; }
.back-link:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 3px; border-radius: var(--r-sm); }

.back-arrow {
  width: 9px;
  height: 9px;
  border-left: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
}

/* ==========================================================================================
   08  THE WAITING STATE
   ========================================================================================== */
/*
 * A calm line of text and nothing else. No spinner, no skeleton, no progress bar.
 *
 * It is also NOT announced the instant the page paints: the CSS delays it, so a fast lookup --
 * which is most of them -- shows nothing at all rather than flashing "one moment" for 80ms.
 * A flicker reads as a fault.
 */
.waiting {
  color: var(--ink-mute);
  font-size: var(--t-base);
  opacity: 0;
  animation: fade-in .2s ease .5s forwards;
}

@keyframes fade-in { to { opacity: 1; } }

/* ==========================================================================================
   09  UTILITIES
   ========================================================================================== */

.stack   { display: flex; flex-direction: column; gap: var(--gap-4); }
.mt-5    { margin-top: var(--gap-5); }
.mt-6    { margin-top: var(--gap-6); }
.muted   { color: var(--ink-mute); font-size: var(--t-sm); }

/* Visible to a screen reader, invisible on screen. Used for the live region that announces a
   screen change to somebody who cannot see that the page has redrawn. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================================
   10  WIDER SCREENS -- the adaptation, and it is deliberately small
   ========================================================================================== */

@media (min-width: 720px) {
  .site-header { padding: var(--gap-4) var(--gap-6); }
  .wrap        { padding: var(--gap-7) var(--gap-5) var(--gap-7); }
  .page-title  { font-size: var(--t-title-lg); }
  .step-card   { padding: var(--gap-5); min-height: 84px; }
  .btn--block  { display: inline-flex; width: auto; }
}

/* ==========================================================================================
   11  STEP 1 -- THE FORM
   ------------------------------------------------------------------------------------------
   Mobile first, and on this page that is not a slogan: twenty questions on a phone held in one
   hand, at the end of a working day. Every tap target here is at least 48px tall, every text
   box is big enough to see three lines of what you typed, and nothing is a small grey link.

   NO RED. Not for the secret steer, not for an unsaved state, not for a refusal. A client who
   pastes something they shouldn't, or loses their signal, has not done anything wrong -- and the
   one colour that says "you have made a mistake" is the one colour this site does not own.
   The steer is amber-free too: it uses the ordinary quiet fill and bold ink, which reads as
   "look at this" without reading as "you are in trouble".

   GREEN STAYS SACRED. It appears on this page in exactly one place: the finished note.
   ========================================================================================== */

.form { margin-top: var(--gap-5); }

.form__section { margin-bottom: var(--gap-6); }

.form__section-title {
  margin: 0 0 var(--gap-3);
  font-size: var(--t-xxs);
  font-weight: var(--w-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--ink-mute);
}

/* ---- one question ---------------------------------------------------------------------- */

.q {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  padding: var(--gap-5) var(--gap-4);
  margin-bottom: var(--gap-4);
}

/* THE QUESTION IS THE BIGGEST THING IN THE CARD, and the pre-filled value is inside it. The
   whole design of this step is that a wrong value in front of somebody's eyes gets corrected in
   four seconds -- which does not happen if it is set at the size of body copy. */
.q__text {
  margin: 0 0 var(--gap-4);
  font-size: var(--t-xl);
  line-height: var(--lh-snug);
  font-weight: var(--w-semi);
  color: var(--ink);
}

.q__why {
  margin: var(--gap-4) 0 0;
  font-size: var(--t-xs);
  line-height: var(--lh-normal);
  color: var(--ink-mute);
}

.q__body { display: block; }

/* ---- the two buttons ------------------------------------------------------------------- */

.q__choices {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap-3);
}

.choice {
  min-height: 52px;
  padding: var(--gap-3) var(--gap-4);
  font: inherit;
  font-size: var(--t-md);
  font-weight: var(--w-semi);
  color: var(--ink);
  background: var(--panel-2);
  border: 1.5px solid var(--line-strong);
  border-radius: var(--r-md);
  cursor: pointer;
  text-align: center;
  -webkit-tap-highlight-color: transparent;
}

.choice--wide {
  display: block;
  width: 100%;
  margin-top: var(--gap-3);
  text-align: left;
  line-height: var(--lh-snug);
}

.choice:hover { background: var(--panel-3); }

.choice:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
}

/* THE CHOSEN ONE IS THE BRAND ACCENT BLUE, and it is deliberately NOT the orange.
 *
 * Orange is reserved for the one control on a screen that COMMITS something -- itv-tokens.css
 * says so in as many words, and this page would otherwise put nine orange fills above the single
 * orange button that actually finalizes. A picked choice is a state, not an action.
 *
 * And still not green: green on this site means a whole step is Done, and a picked button is not
 * a finished anything. White on --accent is 6.93:1. */
.choice.is-on {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.choice.is-on:hover { background: var(--accent-strong); border-color: var(--accent-strong); }

/* ---- the boxes -------------------------------------------------------------------------- */

.q__fix { margin-top: var(--gap-3); }

.q__box {
  display: block;
  width: 100%;
  box-sizing: border-box;
  min-height: 96px;
  padding: var(--gap-3) var(--gap-4);
  font: inherit;
  font-size: var(--t-base);          /* 17px or larger, or iOS zooms the whole page on focus */
  line-height: var(--lh-normal);
  color: var(--ink);
  background: var(--panel);
  border: 1.5px solid var(--line-strong);
  border-radius: var(--r-md);
  resize: vertical;
}

.q__box:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 1px;
  border-color: var(--brand-blue);
}

.q__box--extra { margin-top: var(--gap-2); }

.q__extra-label {
  margin: var(--gap-4) 0 0;
  font-size: var(--t-sm);
  font-weight: var(--w-semi);
  color: var(--ink-dim);
}

/* ---- the secret steer -- a notice, never an alarm ---------------------------------------- */

.q__steer {
  margin: var(--gap-3) 0 0;
  padding: var(--gap-3) var(--gap-4);
  font-size: var(--t-sm);
  line-height: var(--lh-normal);
  font-weight: var(--w-semi);
  color: var(--ink);
  background: var(--panel-2);
  border: 1px solid var(--line-strong);
  border-left: 4px solid var(--brand-blue);
  border-radius: var(--r-sm);
}

/* ---- the services list ------------------------------------------------------------------ */

.q__checks { display: block; }

.check {
  display: flex;
  align-items: center;
  gap: var(--gap-3);
  min-height: 52px;
  padding: var(--gap-2) var(--gap-3);
  border-radius: var(--r-md);
  cursor: pointer;
}

.check:hover { background: var(--panel-2); }

/* A 24px box, because the default is about 13px and this is a phone. */
.check__input {
  width: 24px;
  height: 24px;
  flex: 0 0 auto;
  accent-color: var(--accent);
  cursor: pointer;
}

.check__label { font-size: var(--t-base); line-height: var(--lh-snug); color: var(--ink); }

/* ---- the bottom bar --------------------------------------------------------------------- */

/* ALWAYS ON SCREEN. A save button twenty questions down the page is a save button that is not
   found, and the client who does not find it is the client who loses their evening's work. */
.bar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  gap: var(--gap-2);
  padding: var(--gap-3) var(--gap-4) calc(var(--gap-3) + env(safe-area-inset-bottom));
  background: var(--panel);
  border-top: 1px solid var(--line);
  box-shadow: var(--shadow-bar);
}

/* `auto 1fr`, NOT `1fr 1fr`. Two equal columns on a 375px phone leaves about 150px a side, and
   "Save and finalize" does not fit in it -- it wrapped to two lines and sat half behind the edge
   of its own button. Seen on the deployed page at 375x812, not reasoned about. So "Save draft"
   takes the width its words need and the longer label gets everything else. */
/* THE LINE AND THE BUTTONS ARE ONE GROUP. This wrapper is the whole fix for the bottom-left
   problem: previously the bar's two children were pushed apart by `space-between` at desktop
   width, leaving the save text a screen away from the button it described. */
.bar__actions {
  display: flex;
  flex-direction: column;
  gap: var(--gap-2);
}

.bar__buttons { display: grid; grid-template-columns: auto 1fr; gap: var(--gap-3); }

.bar__buttons .btn {
  width: 100%;
  min-height: 52px;
  padding: 0 var(--gap-4);
  white-space: nowrap;
}

/* QUIET. Small, grey, and it holds "Saved just now" -- no banner, no toast, no colour. A save
   that announces itself teaches somebody to watch for it, and then a save that is merely fast
   looks like a save that did not happen. It reserves its line so the buttons never jump. */
.bar__state {
  margin: 0;
  /* THE ONE LEADING IN THIS FILE THAT IS NOT A SCALE STEP, AND IT IS NOT AN OVERSIGHT. 18px is
     not "1.38 of 13px"; it is the same number as the min-height directly above it, which is what
     makes the reserved line and the line that arrives in it exactly the same height. Expressed as
     a ratio it would drift the moment --t-xxs moved, the row would gain a pixel, and the two
     buttons under it would step down the screen mid-save. A fixed leading matched to a fixed box
     is the correct tool here; a token would be the wrong one. */
  min-height: 18px;
  font-size: var(--t-xxs);
  line-height: 18px;
  color: var(--ink-mute);
  text-align: center;
}

/* The page has to be able to scroll clear of the fixed bar. */
body:has(.bar) .wrap { padding-bottom: 148px; }

/* ==========================================================================================
   STEP 3 -- THE ACCOUNT CARDS
   ==========================================================================================
   Nine questions, most of which are "no". The card starts as one question with three answers and
   grows only for the ones that turn out to be the client's -- a page showing nine account-name
   boxes at once reads as nine jobs. */

.card3-list {
  display: flex;
  flex-direction: column;
  gap: var(--gap-4);
  margin-top: var(--gap-5);
}

.card3 {
  padding: var(--gap-5);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
}

/* FOLDED, NOT HIDDEN. An answered card keeps its name and shows what was said, on one line, with
   a way back in. The client can see they answered it and can still change their mind.
   FOLDING IS INSTANT -- no height transition. A card that animates shut on every answer turns
   nine quick taps into nine little waits, and the movement is the thing being complained about,
   not the thing being enjoyed. */
.card3--folded { padding: var(--gap-4) var(--gap-5); background: var(--panel-2); box-shadow: none; }
.card3--folded .card3__why { display: none; }

.card3__summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap-2) var(--gap-3);
  margin: var(--gap-2) 0 0;
}

.card3__said { font-size: var(--t-sm); color: var(--ink-mute); overflow-wrap: anywhere; }

/* A LINK, NOT A BUTTON. Reopening a card undoes nothing and commits nothing; a button's weight
   would suggest otherwise. 44px so it is still a thumb target. */
.card3__change {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-left: auto;
  color: var(--accent);
  font-size: var(--t-sm);
  font-weight: var(--w-semi);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
}
.card3__change:hover { color: var(--accent-strong); }
.card3__change:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 3px; border-radius: var(--r-sm); }

/* ==========================================================================================
   THE SEGMENTED CONTROL -- one switch, not three buttons
   ==========================================================================================
   Three flat buttons in a row read as three separate things a client could press in any
   combination. A segmented control reads as ONE question with one answer in it, which is what
   this actually is -- and it says so to a screen reader too: role="radiogroup" around
   role="radio", arrow keys to move, one tab stop for the whole group.

   THE SEGMENTS ARE EQUAL WIDTH BY FLEX-BASIS ZERO, not by content. That is what stops the tick
   appearing on selection from resizing the chosen segment and shoving the others sideways under
   a finger that is still on the screen. */

.seg {
  display: flex;
  border: 1.5px solid var(--line-strong);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--panel);
}

.seg__opt {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--gap-2);
  min-height: 56px;
  padding: var(--gap-2) var(--gap-3);
  border: 0;
  border-left: 1.5px solid var(--line-strong);
  background: transparent;
  font: inherit;
  font-size: var(--t-md);
  font-weight: var(--w-semi);
  line-height: var(--lh-tight);
  color: var(--ink);
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.seg__opt:first-child { border-left: 0; }
.seg__opt:hover { background: var(--panel-2); }

/* THE FOCUS RING IS DRAWN INSIDE, because the group clips its children -- an outline drawn
   outward would be cut off by `overflow: hidden` and a keyboard user would see nothing. */
.seg__opt:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: -3px;
}

/* SELECTED: the brand accent blue, and deliberately NOT the orange -- see .choice.is-on. */
.seg__opt[aria-checked="true"] {
  background: var(--accent);
  color: var(--on-accent);
}

.seg__opt[aria-checked="true"]:hover { background: var(--accent-strong); }

/* The tick is decoration; the aria-checked state is what is actually announced. */
/* `line-height: 1` is a glyph-box reset rather than a leading choice -- the tick is one character
   sitting beside a label and it must not add height to the row. Not a scale step, deliberately. */
.seg__tick { font-size: var(--t-sm); line-height: 1; }

/* ---- the nested panel: visually INSIDE the choice that opened it ---- */
.card3__nest {
  margin-top: var(--gap-4);
  padding: var(--gap-1) 0 0 var(--gap-4);
  border-left: 3px solid var(--brand-blue);
}

.card3__nest-gap { margin-top: var(--gap-4); }

/* ---- THE STICKY PROGRESS STRIP ----------------------------------------------------------
 * Slim, quiet, and it stays. On a nine-card page "how much is left" is the first thing to
 * scroll off, and it is the one thing a client wants while they are working.
 *
 * z-index BELOW the save bar's 20, deliberately: a sticky top strip and a fixed bottom bar
 * cannot meet at any sane viewport height, and if they ever did the bar is the one that must
 * win -- it holds the buttons. */
.progress-strip {
  position: sticky;
  top: 0;
  z-index: 15;
  margin: var(--gap-2) 0 var(--gap-5);
  padding: var(--gap-3) 0 var(--gap-3);
  /* OPAQUE, or the cards scroll through it. --bg is the page, so it reads as the page. */
  background: var(--bg);
  border-bottom: 1px solid var(--line);
}

/* At least body size and medium weight -- it is a status a client reads at a glance, not a
   caption. The old version was 15px --ink-mute and got lost against the why-lines. */
.progress-strip__label {
  margin: 0 0 var(--gap-2);
  font-size: var(--t-base);
  font-weight: var(--w-semi);
  color: var(--ink-dim);
}

.progress-strip__track {
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--panel-3);
  overflow: hidden;
}

/* BRAND BLUE, NEVER GREEN. Green means a whole step is Done, and answering the ninth card is
   not finishing the step -- finalizing is. A bar that filled to green would promise that. */
.progress-strip__fill {
  height: 100%;
  width: 0;
  background: var(--brand-blue);
  border-radius: var(--r-pill);
  /* The one movement on this strip, and it is the width following the number. The global
     reduced-motion reset at the top of this file switches it off. */
  transition: width var(--ease-slow);
}

/* ---- the finished step, read-only ---- */
.card3--done { padding: var(--gap-4) var(--gap-5); }
.card3__name-done {
  margin: 0 0 var(--gap-1);
  font-size: var(--t-md);
  font-weight: var(--w-semi);
  color: var(--ink-dim);
}
.card3__done-id {
  margin: var(--gap-2) 0 0;
  font-size: var(--t-sm);
  color: var(--ink-mute);
  overflow-wrap: anywhere;
}

/* ---- the finished step ------------------------------------------------------------------- */

/* THE ONE GREEN ON THIS PAGE. */
.note {
  margin-top: var(--gap-5);
  padding: var(--gap-4);
  background: var(--done-bg);
  border: 1px solid var(--done-edge);
  border-radius: var(--r-lg);
}

.note__title { margin: 0 0 var(--gap-1); font-size: var(--t-base); font-weight: var(--w-bold); color: var(--done-ink); }

.q__support { margin: 0; font-size: var(--t-sm); line-height: var(--lh-normal); color: var(--done-ink); }
.q__support a { color: var(--done-ink); font-weight: var(--w-semi); }

.q--done { padding: var(--gap-4); }
.q--done .q__text { font-size: var(--t-md); font-weight: var(--w-semi); color: var(--ink-dim); margin-bottom: var(--gap-2); }

.q__answer {
  margin: 0;
  font-size: var(--t-lg);
  line-height: var(--lh-snug);
  font-weight: var(--w-semi);
  color: var(--ink);
  white-space: pre-wrap;
}

.q__answer--none { font-weight: var(--w-medium); color: var(--ink-mute); }

/* ---- the modal --------------------------------------------------------------------------- */

.scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: var(--gap-4);
  background: var(--scrim-fill);
}

.dialog {
  width: 100%;
  max-width: 460px;
  padding: var(--gap-5) var(--gap-4) calc(var(--gap-4) + env(safe-area-inset-bottom));
  background: var(--panel);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lift);
}

.dialog__title { margin: 0 0 var(--gap-3); font-size: var(--t-3xl); line-height: var(--lh-tight); color: var(--ink); }
.dialog__body  { margin: 0 0 var(--gap-5); font-size: var(--t-md); line-height: var(--lh-body); color: var(--ink-dim); }
.dialog__actions { display: grid; gap: var(--gap-3); }
.dialog__actions .btn { min-height: 52px; }

body.is-modal { overflow: hidden; }

@media (prefers-reduced-motion: no-preference) {
  .scrim  { animation: scrim-in .16s ease-out; }
  .dialog { animation: dialog-in .2s ease-out; }
}

@keyframes scrim-in  { from { opacity: 0; } to { opacity: 1; } }
@keyframes dialog-in { from { transform: translateY(12px); opacity: 0; } to { transform: none; opacity: 1; } }

/* ---- wider screens ----------------------------------------------------------------------- */

/* NARROW: THE SEGMENTS STACK, AND THEY STACK INSIDE THE BORDER.
   The group keeps its single outline and its single radius; only the flow direction and which
   edge carries the divider change. That is the difference between a switch that got taller and
   three buttons that happen to be touching. Below 560px "We don't use this" cannot share a row
   with two others without hyphenating. */
@media (max-width: 559px) {
  .seg { flex-direction: column; }
  .seg__opt { border-left: 0; border-top: 1.5px solid var(--line-strong); min-height: 52px; }
  .seg__opt:first-child { border-top: 0; }
}

@media (min-width: 720px) {
  .q            { padding: var(--gap-5); }
  .q__text      { font-size: var(--t-3xl); }
  .q__choices   { grid-template-columns: auto auto; justify-content: start; }
  .choice       { min-width: 190px; }
  /* RIGHT-ALIGNED AS ONE GROUP, not spread to the two corners. `flex-end` is doing the work that
     `space-between` used to undo: the quiet line now sits immediately beside the buttons, which
     is the only place a person who just clicked one is looking. */
  .bar          { flex-direction: row; align-items: center; justify-content: flex-end; padding: var(--gap-4) var(--gap-6); }
  .bar__actions { flex-direction: row; align-items: center; gap: var(--gap-4); }
  .bar__state   { text-align: right; }
  .bar__buttons { grid-template-columns: auto auto; }
  .card3        { padding: var(--gap-5) var(--gap-6); }
  .bar__buttons .btn { min-width: 170px; }
  body:has(.bar) .wrap { padding-bottom: 120px; }
  .scrim        { align-items: center; }
}
