/* ===========================================================================
   Instinctive HealthPass — visual system
   ===========================================================================

   One stylesheet, no build step, no framework. Everything below is driven from
   the tokens in `:root`, so the whole product re-themes from about thirty values.

   The palette is not invented here. It is the documented IHP system — the same
   hex values as the published brand documents and policy pages — so the portal
   matches the leaflet in a member's hand and the agreement they signed:

     Navy      #0E3A5E   leads. Headings, primary buttons, the sidebar.
     Teal      #2E8FB0   accents. Keylines, active states, focus ring.
     Teal ink  #1F6E8C   the text-safe teal. Links, and any teal that carries
                         words or needs 4.5:1 — raw teal is 3.7:1.
     Amber     #D79A2B   interrupts, decoratively. Callout borders and nothing
                         else: it is 2.5:1 on white and can never carry text.
     Amber ink #8A5E12   the text-safe amber, for warning wording.

   Roughly 70% neutral surface, 20% navy, 8% teal, 2% amber on any screen. Every
   ratio the brand guide claims was re-measured here and every one of them holds:
   navy 11.8:1, teal-ink 5.7:1, amber-ink 5.7:1, slate 5.5:1, ink 15.9:1.

   Type is the system stack, which is what the published documents use. There is
   deliberately no display face: the guide lists one as an optional refinement
   that is "not yet brand", and names the Source Sans 3 / Nunito Sans family if
   one is ever wanted. That would be a change to `--font-display` alone.

   Light is the default, because a first-time visitor should see the product the
   printed material describes. Dark is a real second palette, derived from the
   documented navy rather than a neutral slate, so it reads as the brand at night
   instead of as a generic dark mode. On that ground navy cannot carry an accent,
   so the roles swap: the teal family leads and navy becomes the surface.

   Three rules the whole thing obeys:

     1. Colour is never the only signal. Every status carries a word and a shape
        as well as a hue, because roughly one man in twelve cannot separate the
        red from the green and this product decides whether somebody is covered.
     2. Money is tabular. Figures line up on the decimal, everywhere, so two
        prices can be compared by looking rather than by reading.
     3. Motion is a garnish. Everything animated is decorative, and all of it
        stops under `prefers-reduced-motion`.
   =========================================================================== */

:root {
  color-scheme: light;

  /* The documented palette, by its own names, so a rule can say what it means. */
  --navy: #0e3a5e;
  --navy-dark: #0b2f4c;
  --teal: #2e8fb0;
  --teal-ink: #1f6e8c;
  --amber: #d79a2b;
  --amber-ink: #8a5e12;
  --cream: #fff6e8;
  --mist: #d9e2e9;
  --paper: #f7f9fb;
  --slate: #5b6b7a;

  --bg: var(--paper);
  --bg-2: #eef3f7;
  --surface: rgba(255, 255, 255, 0.92);
  --surface-solid: #ffffff;
  --surface-2: #edf2f6;
  --line: var(--mist);
  --line-strong: #bccdd9;

  --ink: #222222;
  --ink-dim: #3a4a57;
  --muted: var(--slate);

  /* Navy leads: it is what the brand puts every heading and every primary
     button in, and it is the only button fill. */
  --brand: var(--navy);
  --brand-ink: #ffffff;
  --brand-dim: var(--navy-dark);
  --brand-glow: rgba(46, 143, 176, 0.18);

  /* Teal accents. `--accent` is the keyline and the active state; anything that
     carries words uses `--accent-ink`, which is the documented text-safe teal. */
  --accent: var(--teal);
  --accent-ink: var(--teal-ink);
  --wordmark: var(--teal-ink);
  --wash: var(--brand-glow);

  --success: #1e7a46;
  --success-bg: #eaf6ef;
  /* Warnings speak in amber ink and wash in cream. Raw amber never carries a
     word — it is a 4px left border and a dot, and that is all. */
  --warn: var(--amber-ink);
  --warn-bg: var(--cream);
  --danger: #b42318;
  --danger-bg: #fceeec;
  --info: var(--teal-ink);
  --info-bg: #eaf4f8;

  --shadow: 0 1px 3px rgba(14, 58, 94, 0.1);
  --shadow-lift: 0 6px 18px rgba(14, 58, 94, 0.14);

  --radius: 14px;
  --radius-sm: 9px;
  --radius-pill: 100px;

  /* The teal focus ring, on every focusable thing. */
  --ring: 0 0 0 3px rgba(46, 143, 176, 0.45);

  --font: Poppins, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-display: var(--font);
  /* Poppins everywhere the eye reads prose, but not here, and this is measured
     rather than a preference. Poppins digit advances at 600 weight are
     0:65 1:36 2:58 3:60 4:67 5:64 6:63 7:54 8:65 9:63 -- the "1" is barely half
     the "4" -- and `font-variant-numeric: tabular-nums` returns byte-identical
     widths, because the face ships no `tnum` feature to switch on. Money columns
     in the payroll and commission tables are read by scanning down them, so a
     31px spread per glyph makes the column ragged and the existing tabular-nums
     declarations silently stop doing anything. The prominent figures a person
     actually looks at -- the dashboard stat numbers -- read `--font-display` and
     are Poppins; only the narrow aligned columns stay here. */
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Two measures, because they answer different questions: how wide a screen of
     cards may get, and how wide a paragraph may get before it is hard to read. */
  --measure: 70rem;
  --prose: 51.25rem;
}

/* ---------------------------------------------------------------------------
   The dark palette, twice
   ---------------------------------------------------------------------------
   Once for "the operating system says dark and nobody has overridden it", once
   for "somebody pressed Dark". CSS cannot share one declaration block across a
   media query and an attribute selector, and `light-dark()` — which would collapse
   this to one line per token — is too new to stake a production palette on.

   So they are duplicated deliberately, kept adjacent, and must be edited together.
   Nothing else in this file needs to know: every rule below reads the tokens.

   Every value here was measured against its own ground: the lightest teal that
   still reads as teal is 7.4:1 on the surface, and nothing in the set is below
   5:1.
   --------------------------------------------------------------------------- */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
  color-scheme: dark;

  --navy: #0e3a5e;
  --navy-dark: #082a47;
  --teal: #4fb8d6;
  --teal-ink: #6ec6e0;
  --amber: #d79a2b;
  --amber-ink: #e8b968;
  --cream: rgba(215, 154, 43, 0.14);
  --mist: rgba(120, 170, 200, 0.18);
  --paper: #061a2b;
  --slate: #98b2c6;

  --bg: var(--paper);
  --bg-2: #0a2338;
  --surface: rgba(12, 44, 71, 0.78);
  --surface-solid: #0c2c47;
  --surface-2: rgba(18, 58, 90, 0.7);
  --line: var(--mist);
  --line-strong: rgba(120, 170, 200, 0.34);

  --ink: #e7eff5;
  --ink-dim: #c3d6e4;
  --muted: var(--slate);

  /* Roles swap on a dark ground: navy cannot carry an accent against it, so the
     teal family leads and navy becomes the surface family above. */
  --brand: #6ec6e0;
  --brand-ink: #061a2b;
  --brand-dim: #8ed6ea;
  --brand-glow: rgba(110, 198, 224, 0.24);

  --accent: #4fb8d6;
  --accent-ink: #6ec6e0;
  --wordmark: #7ecfe6;
  --wash: var(--brand-glow);

  --success: #5fd69c;
  --success-bg: rgba(95, 214, 156, 0.14);
  --warn: #e8b968;
  --warn-bg: rgba(215, 154, 43, 0.14);
  --danger: #ff8e82;
  --danger-bg: rgba(255, 142, 130, 0.14);
  --info: #7ec4de;
  --info-bg: rgba(126, 196, 222, 0.14);

  --shadow: 0 1px 0 rgba(255, 255, 255, 0.04) inset,
            0 18px 40px -28px rgba(0, 0, 0, 0.9);
  --shadow-lift: 0 1px 0 rgba(255, 255, 255, 0.07) inset,
                 0 28px 60px -30px rgba(0, 0, 0, 0.95);

  --ring: 0 0 0 3px rgba(110, 198, 224, 0.5);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --navy: #0e3a5e;
  --navy-dark: #082a47;
  --teal: #4fb8d6;
  --teal-ink: #6ec6e0;
  --amber: #d79a2b;
  --amber-ink: #e8b968;
  --cream: rgba(215, 154, 43, 0.14);
  --mist: rgba(120, 170, 200, 0.18);
  --paper: #061a2b;
  --slate: #98b2c6;

  --bg: var(--paper);
  --bg-2: #0a2338;
  --surface: rgba(12, 44, 71, 0.78);
  --surface-solid: #0c2c47;
  --surface-2: rgba(18, 58, 90, 0.7);
  --line: var(--mist);
  --line-strong: rgba(120, 170, 200, 0.34);

  --ink: #e7eff5;
  --ink-dim: #c3d6e4;
  --muted: var(--slate);

  /* Roles swap on a dark ground: navy cannot carry an accent against it, so the
     teal family leads and navy becomes the surface family above. */
  --brand: #6ec6e0;
  --brand-ink: #061a2b;
  --brand-dim: #8ed6ea;
  --brand-glow: rgba(110, 198, 224, 0.24);

  --accent: #4fb8d6;
  --accent-ink: #6ec6e0;
  --wordmark: #7ecfe6;
  --wash: var(--brand-glow);

  --success: #5fd69c;
  --success-bg: rgba(95, 214, 156, 0.14);
  --warn: #e8b968;
  --warn-bg: rgba(215, 154, 43, 0.14);
  --danger: #ff8e82;
  --danger-bg: rgba(255, 142, 130, 0.14);
  --info: #7ec4de;
  --info-bg: rgba(126, 196, 222, 0.14);

  --shadow: 0 1px 0 rgba(255, 255, 255, 0.04) inset,
            0 18px 40px -28px rgba(0, 0, 0, 0.9);
  --shadow-lift: 0 1px 0 rgba(255, 255, 255, 0.07) inset,
                 0 28px 60px -30px rgba(0, 0, 0, 0.95);

  --ring: 0 0 0 3px rgba(110, 198, 224, 0.5);
}

/* ---------------------------------------------------------------------------
   The display face: Poppins
   ---------------------------------------------------------------------------
   Adopted on request, and the request was for it everywhere rather than for
   headings alone, so `--font` carries it too and `--font-display` keeps reading
   `--font`. Every heading and every paragraph in the product resolves through
   those two tokens, which is why this is a dozen lines here and no edits
   anywhere else in the stylesheet.

   Self-hosted, not linked from Google. A `<link>` to fonts.googleapis.com would
   put a third-party request on every page of a health product, which hands a
   visitor's IP address and the page they are on to someone who is not us, for no
   benefit we cannot get locally. It is also a second DNS lookup and a
   render-blocking round trip on the critical path. Eight files, 68KB in total,
   served by WhiteNoise under the same far-future cache header as the CSS.

   Four weights because the stylesheet asks for exactly four -- 400, 500, 600 and
   700 -- and shipping the other five would be bytes nothing renders. Two subsets
   each: `latin` for the product, `latin-ext` because subscriber names carry
   accents and a name that renders in a fallback face beside one that does not
   looks like a bug. The `unicode-range` pairs are Google's own, so a page of
   plain English never downloads the accented file at all.

   `font-display: swap` is deliberate. The alternative is invisible text while the
   font loads, and somebody checking in at a front desk should be able to read
   their own name immediately, in the fallback, rather than wait for a typeface.
   --------------------------------------------------------------------------- */

@font-face {
  font-family: Poppins;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/poppins-400-latin.9212f6f9860f.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: Poppins;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/poppins-400-latin-ext.90926c36b712.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;
}

@font-face {
  font-family: Poppins;
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/poppins-500-latin.a09f2fccfee3.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: Poppins;
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/poppins-500-latin-ext.1f24684cbd72.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;
}

@font-face {
  font-family: Poppins;
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/poppins-600-latin.72993dddf88a.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: Poppins;
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/poppins-600-latin-ext.a575b6d9df98.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;
}

@font-face {
  font-family: Poppins;
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/poppins-700-latin.25b0e113ca7c.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: Poppins;
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/poppins-700-latin-ext.367d2aa05bf0.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;
}

/* ---------------------------------------------------------------------------
   Reset and base
   --------------------------------------------------------------------------- */

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

html { -webkit-text-size-adjust: 100%; }

/* Belt and braces on top of the fixes above: no element gets to widen the page,
   and any table too wide for a phone scrolls inside its own panel rather than
   taking the layout with it. */
img, svg, video, table, pre { max-width: 100%; }
.panel, .result, .wizard, .hero { overflow-wrap: break-word; }

body {
  margin: 0;
  min-height: 100vh;
  font: 0.84375rem/1.6 var(--font);
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

/* The room the panels sit in. Two very soft pools of light, fixed so they do
   not travel with the scroll — a background that scrolls reads as a picture,
   one that stays put reads as depth. Purely decorative and behind everything,
   so it never sits between a reader and a word. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(50rem 32rem at 12% -8%, var(--brand-glow), transparent 65%),
    radial-gradient(46rem 30rem at 96% 4%, var(--violet-glow), transparent 62%),
    linear-gradient(180deg, var(--bg-2), var(--bg) 42%);
}

main {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 2rem 1.25rem 5rem;
}

/* The concept's scale, taken from its stylesheet rather than from the brand
   guide's document scale: 27px page title, 15px card title, 13.5px body,
   12.5px card copy, 11px labels.

   The guide says body copy is never below 16px. That is a house rule in the guide
   and not, as I first claimed, a requirement of the WCAG 2.1 AA commitment IHP
   publishes — that standard sets no minimum font size. Its text criteria are
   contrast, resizing to 200%, and reflow, all of which this holds: every ratio in
   this file is measured, sizes are in rem so they scale with the browser's own
   setting, and the layout reflows to a single column. So the denser scale costs
   nothing against the published statement, which is what makes this a taste call
   rather than a trade. It was called as a trade, wrongly, and reverted on request. */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  line-height: 1.25;
  letter-spacing: -0.01em;
  text-wrap: balance;
  color: var(--brand);
}
/* Device 2, the teal keyline. The brand's most recognisable move: every page
   title carries a 3px teal rule under it. */
h1 {
  font-size: 1.6875rem;
  font-weight: 600;
  margin: 0 0 0.9rem;
  padding-bottom: 0.5rem;
  border-bottom: 3px solid var(--accent);
}
h2 { font-size: 1.25rem; margin: 0 0 0.4rem; }
h3 { font-size: 0.9375rem; font-weight: 600; margin: 1.1em 0 0.2em; }
h4 { font-size: 0.875rem; margin: 1em 0 0.2em; }

/* Device 1, the kicker: a small navy overline above a title. `.eyebrow` is the
   name several screens already use for the same thing. */
.kicker, .eyebrow {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--brand);
  margin: 0 0 0.25rem;
}

/* The lead under a page title. */
.help, .lede {
  font-size: 0.84375rem;
  line-height: 1.55;
  color: var(--muted);
  max-width: var(--prose);
  margin: 0 0 1.1rem;
}

p { margin: 0 0 0.85rem; max-width: var(--prose); }
a { color: var(--brand); text-underline-offset: 0.18em; }
a:hover { color: var(--brand-dim); }

code, kbd, samp, .mono { font-family: var(--mono); font-size: 0.92em; }
/* A block somebody is meant to select and copy — the environment lines on CRM setup,
   a rendered email on the demo outbox. It had no treatment at all, so it read as
   loose monospaced prose rather than as a thing with edges to drag across. */
pre {
  margin: 0.75rem 0;
  padding: 0.875rem 1rem;
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-family: var(--mono);
  font-size: 0.75rem;
  line-height: 1.7;
  color: var(--ink);
}

/* Money and counts, everywhere. Two figures in a column have to line up on the
   decimal or comparing them means reading them. */
dd, td, .amount, .total, .price-summary, .facts, .data, .report-table {
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   The shell
   ---------------------------------------------------------------------------
   A navy rail down the left, a white bar across the top, and the work between
   them. Every signed-in role gets it — Member, Employer, Sales, Front desk,
   Admin — so there is one shell to get right rather than five.

   The rail is a FIXED navy surface in both schemes, like the hero band: it is
   the brand's own colour and it does not flip. So nothing inside it reads a page
   token. Its own five locals are declared on `.side` and everything within uses
   those, which is what stops the dark-mode failure this file has now shipped
   twice elsewhere.

   Below 60rem the rail becomes an off-canvas drawer. That is done with a
   checkbox and sibling selectors rather than JavaScript — this product ships
   none, and a menu that needs a script is a menu that fails when the script
   does.
   --------------------------------------------------------------------------- */

.app {
  --rail: 15rem;
  display: grid;
  grid-template-columns: var(--rail) minmax(0, 1fr);
  grid-template-areas:
    "side topbar"
    "side work";
  grid-template-rows: auto minmax(0, 1fr);
  min-height: 100vh;
}
.side { grid-area: side; }
.topbar { grid-area: topbar; }
.work {
  grid-area: work;
  min-width: 0;
  /* A container, so the content's own breakpoints describe the column it sits in
     rather than the window. With the rail taking 15rem, a viewport query is
     wrong by 240px for every signed-in screen: a table would be told it had
     60rem to lay out in when it actually had 45. Only `body::before` is
     fixed-position and it hangs off <body>, so this containment costs nothing. */
  container-type: inline-size;
  container-name: work;
}

.side {
  --rail-ink: #dceaf2;        /* the rail's body text — 9.6:1 on the navy */
  --rail-link: #b7d3e3;       /* a resting destination — 7.5:1 */
  --rail-label: #8faec4;      /* a group heading — 5.1:1 */
  --rail-line: rgba(255, 255, 255, 0.1);
  --rail-hover: rgba(255, 255, 255, 0.08);

  display: flex;
  flex-direction: column;
  gap: 0.06rem;
  padding: 1.25rem 0.75rem 1rem;
  /* Navy, top to bottom, exactly as the brand's masthead does it. */
  background: linear-gradient(190deg, #0e3a5e, #082a47);
  color: var(--rail-ink);
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  height: 100dvh;
  overflow-y: auto;
  z-index: 60;
}

.side .brand {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin: 0 0 0.75rem;
  padding: 0.25rem 0.5rem 1.125rem;
  border-bottom: 1px solid var(--rail-line);
  font-family: var(--font-display);
  font-size: 0.96875rem;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: #ffffff;
  text-decoration: none;
  white-space: nowrap;
}
/* The real mark. Decorative and hidden from assistive technology, because the
   wordmark beside it already says the name — announcing both reads it twice. */
.brand-mark {
  width: 2rem;
  height: 2rem;
  flex: 0 0 auto;
  border-radius: 9px;
  display: block;
}
/* The wordmark's second half in teal, which is the mark's own emphasis. Teal on
   navy is 3.7:1 — fine for a bold wordmark, and the word is repeated in the page
   title anyway, so nothing depends on reading it. */
.side .brand strong { color: #7ecfe6; font-weight: 700; }
.brand-name { display: block; }

.nav-group { margin-bottom: 0.6rem; }
.nav-group-title {
  margin: 0.75rem 0 0.3rem 0.75rem;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--rail-label);
}
.nav-group ul { display: block; margin: 0; padding: 0; list-style: none; }

.side a {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 32px;
  padding: 0.4375rem 0.6875rem;
  border-radius: 8px;
  color: var(--rail-link);
  font-size: 0.8125rem;
  font-weight: 500;
  text-decoration: none;
  transition: background 0.15s, color 0.15s;
}
.side a:hover { background: var(--rail-hover); color: #ffffff; }
.side .icon { width: 1.05em; height: 1.05em; flex: 0 0 auto; opacity: 0.8; }
.side a:hover .icon { opacity: 1; }

/* The section you are in, drawn as well as announced. Teal ink rather than raw
   teal: white on raw teal is 3.7:1, and a 14px label needs 4.5:1. The brand
   guide says exactly this — white sits on navy and on teal-ink, never on teal. */
.side a[aria-current] {
  background: #1f6e8c;
  color: #ffffff;
  font-weight: 600;
}
.side a[aria-current] .icon { opacity: 1; }

/* How many are waiting, on the link itself. */
.count {
  margin-left: auto;
  display: inline-grid;
  place-items: center;
  min-width: 1.45em;
  padding: 0 0.4em;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.16);
  color: #ffffff;
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.side a[aria-current] .count { background: rgba(255, 255, 255, 0.24); }

/* Whose account this is, pinned to the foot of the rail — which is what `auto`
   on a column flex item does with the leftover space. */
.whoami-block {
  margin: auto 0 0;
  padding: 0.85rem 0.4rem 0;
  border-top: 1px solid var(--rail-line);
  display: flex;
  align-items: center;
  gap: 0.55rem;
  flex-wrap: wrap;
}
.whoami {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0;
  min-height: 0;
  color: var(--rail-ink);
}
.whoami:hover { background: none; color: #ffffff; }
.whoami .who { display: flex; flex-direction: column; line-height: 1.3; }
.whoami .name { font-size: 0.8125rem; font-weight: 600; color: var(--rail-ink); }
.whoami .role { font-size: 0.6875rem; font-weight: 400; color: var(--rail-label); }
.whoami .avatar {
  display: grid;
  place-items: center;
  width: 1.7rem;
  height: 1.7rem;
  flex: 0 0 auto;
  border-radius: 50%;
  background: #2e8fb0;
  color: #ffffff;
  font-weight: 700;
  font-size: 0.75rem;
}
/* Lined up under the name rather than under the avatar, so it reads as part of
   the identity block instead of a stray link in the corner. */
.whoami-block form { margin: 0; flex: 0 0 auto; width: 100%; padding-left: 2.25rem; }
.whoami-block button.link { color: var(--rail-link); font-size: 0.8125rem; }
/* The identity itself carries no underline — it is a name, and underlining it
   made it read as a link in a sentence. The sign-out control keeps one. */
.whoami { text-decoration: none; }
.whoami-block button.link:hover { color: #ffffff; }
.signin-block { margin: auto 0 0; padding: 0.85rem 0.4rem 0; border-top: 1px solid var(--rail-line); }
.signin-block a { color: var(--rail-ink); }

/* The top bar: white, sticky, and page actions at its right end. */
.topbar {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 60px;
  padding: 0.7rem clamp(0.9rem, 3vw, 2.25rem);
  background: var(--surface-solid);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 5;
}
.topbar .spacer { flex: 1 1 auto; }
.topbar .button { min-height: 40px; padding: 0.5rem 1rem; }
/* Nothing to put in it. Sixty pixels of empty white with a rule under it is
   chrome that says nothing, so on a wide screen there simply is no bar. */
.topbar.bare { min-height: 0; padding: 0; border-bottom: 0; background: none; }

/* The concept's content box: full width of the column, its own padding, no
   centred measure. Prose blocks still cap themselves at `--prose` so a paragraph
   never runs the width of a wide monitor; the cards are grids and use the room. */
main {
  width: 100%;
  max-width: none;
  margin: 0;
  padding: 1.625rem 2.25rem 4.375rem;
}
@media (max-width: 67.5rem) { main { padding: 1.5rem 1.375rem 3.75rem; } }
@media (max-width: 47.5rem) { main { padding: 1.125rem 0.875rem 3.75rem; } }

/* --- the drawer, below 60rem ---------------------------------------------
   The checkbox lives next to `.app` so a sibling selector can reach the rail.
   It is off-screen rather than `display: none`, because a hidden input cannot
   be focused and this is the only way to open the menu from a keyboard. */
.nav-toggle { position: absolute; left: -9999px; }
.nav-open, .nav-shade { display: none; }

@media (max-width: 60rem) {
  .app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "topbar"
      "work";
  }
  .side {
    position: fixed;
    top: 0;
    left: 0;
    width: 15.5rem;
    height: 100dvh;
    transform: translateX(-100%);
    transition: transform 0.22s ease;
  }
  .nav-toggle:checked ~ .app .side { transform: translateX(0); box-shadow: 0 0 46px rgba(4, 20, 36, 0.45); }
  /* The label is the hamburger. A checkbox is announced as a checkbox, so it
     carries its own accessible name and pressed state. */
  .nav-open {
    display: inline-grid;
    place-items: center;
    width: 44px;
    height: 44px;
    flex: 0 0 auto;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--surface-solid);
    color: var(--brand);
    cursor: pointer;
  }
  .nav-toggle:focus-visible ~ .app .nav-open { box-shadow: var(--ring); }
  /* Tapping anywhere else closes it: the shade is a second label for the same
     checkbox, so it needs no script either. */
  .nav-toggle:checked ~ .app .nav-shade {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 55;
    background: rgba(8, 32, 55, 0.45);
  }
  .topbar .brand-small { display: flex; }
  /* On a phone the bar earns its keep whatever else is in it: it holds the only
     way to open the navigation. */
  .topbar.bare {
    min-height: 60px;
    padding: 0.7rem clamp(0.9rem, 3vw, 2.25rem);
    border-bottom: 1px solid var(--line);
    background: var(--surface-solid);
  }
}

@media (prefers-reduced-motion: reduce) {
  .side { transition: none; }
}

/* On a wide screen the rail is always there, so the opener and the shade are
   not just hidden — they must not be reachable by keyboard either. */
@media (min-width: 60.0625rem) {
  .nav-toggle { display: none; }
  .brand-small { display: none; }
}

/* The icon sprite: definitions only, nothing to draw. Taken out of flow rather
   than `display: none`, which has historically broken <use> references. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* The small wordmark that appears in the top bar once the rail is a drawer, so
   the brand does not disappear behind a hamburger. */
.brand-small {
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--ink-dim);
  text-decoration: none;
  white-space: nowrap;
}
.brand-small strong { font-weight: 700; color: var(--brand); }
.brand-small img { width: 1.625rem; height: 1.625rem; border-radius: 7px; display: block; }

.site-footer {
  margin-top: 2rem;
  padding: 1.75rem clamp(0.9rem, 3vw, 2.25rem) 3rem;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.8125rem;
}
.site-footer p { max-width: var(--prose); margin: 0 auto 0.75rem; }
.site-footer strong { color: var(--ink); }

/* A preference, not a destination, so it lives down here rather than in the
   navigation. Segmented, because the three states are mutually exclusive and the
   one in effect should be readable at a glance. */
.theme-switch {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  margin-top: 1.25rem;
  font-size: 0.8125rem;
}
.theme-switch > span[role="group"] {
  display: inline-flex;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  overflow: hidden;
}
.theme-switch button {
  min-height: 34px;
  padding: 0.28rem 0.85rem;
  border: 0;
  border-left: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
}
.theme-switch button:first-child { border-left: 0; }
.theme-switch button:hover { color: var(--ink); background: var(--surface-2); }
.theme-switch button[aria-pressed="true"] {
  background: var(--info-bg);
  color: var(--accent-ink);
  font-weight: 700;
}

/* The public pages: no rail, so the shell is one column and the top bar carries
   the wordmark and the join button, which is what a marketing header is. */
.wide .app {
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    "topbar"
    "work";
}
.wide .side { display: none; }
.wide .nav-open { display: none; }
.wide .brand-small { display: flex; }

/* ---------------------------------------------------------------------------
   Surfaces
   --------------------------------------------------------------------------- */

/* The card. `.panel` is the name the templates use and `.card` is the concept's;
   they are the same thing, so they are the same rule.

   Solid rather than translucent, and with no specular line along the top edge.
   Both of those were mine: a blurred backdrop and a hairline of light made a
   panel read as a pane of glass, which is a different product from the one in the
   concept. Flat white on a tinted ground is what the concept does, and converting
   this one rule converts every screen that uses a panel. */
.panel, .card, .result, .wizard, .hero {
  position: relative;
  background: var(--surface-solid);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.25rem 1.375rem;
  margin: 0 0 1rem;
}

.panel > :last-child, .card > :last-child, .wizard > :last-child, .hero > :last-child { margin-bottom: 0; }
.panel h2, .card h2, .panel h3:first-child, .card h3:first-child { margin-top: 0; }

/* `warn` is the one spelling for a container that needs attention — `.panel.warn`
   and `.callout.warn`. There were two, `warn` and `warning`, and the CSS only knew
   the minority one: eleven warning panels, including "Your coverage has ended" on
   the member dashboard and every escalation on the work queue, rendered as
   ordinary panels with no warning treatment at all. The class inventory could not
   see it either, because `warn` *is* defined — as part of `.callout.warn`, a
   compound selector those panels never matched. */
.panel.warn {
  border-color: color-mix(in oklab, var(--warn) 42%, transparent);
  background: linear-gradient(var(--warn-bg), transparent 60%), var(--surface);
}
.panel.warn > h1, .panel.warn > h2, .panel.warn > h3 { color: var(--warn); }

.eyebrow {
  font-family: var(--font-display);
  margin: 0 0 0.35rem;
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brand);
}

/* ---------------------------------------------------------------------------
   The hero band
   ---------------------------------------------------------------------------
   The brand's masthead: a full band of navy with white type and a 4px teal rule
   along the bottom. It is the one shape somebody recognises from the leaflet
   before they have read a word, and it is what the published document pages put
   at the top of every page.

   It is a FIXED surface — navy in both schemes — so it cannot read the page
   tokens, which flip. That mistake has shipped twice on this band: once as a
   headline gradient running to `--brand`, which is navy in light and bright teal
   in dark, so half the sentence went teal-on-teal at about 1.2:1.

   Everything inside therefore reads from these locals, set once here. Same rule
   the membership card follows, for the same reason. If you add anything inside
   `.hero`, colour it from these.
   --------------------------------------------------------------------------- */
.hero {
  --hero-ink: #cfdde9;          /* body copy on the navy — 8.4:1 */
  --hero-head: #ffffff;         /* headings and the kicker's brighter partner */
  --hero-kicker: #bfe0ee;       /* the documented masthead kicker — 7.9:1 */
  --hero-card: #ffffff;
  --hero-card-ink: #222222;
  --hero-card-muted: #5b6b7a;
  --hero-card-strong: #0e3a5e;

  padding: clamp(1.75rem, 5vw, 3rem);
  overflow: hidden;
  background: #0e3a5e;
  border: 0;
  border-bottom: 4px solid #2e8fb0;
  border-radius: var(--radius);
  color: var(--hero-ink);
}
/* No opacity on anything sitting on the navy. Fading ink is how a measured 8.4:1
   quietly becomes an unmeasured 4.1:1; hierarchy comes from size and weight
   instead, which costs no contrast. */
.hero .eyebrow, .hero .kicker { color: var(--hero-kicker); }
.hero .help, .hero .fine, .hero p { color: var(--hero-ink); }
.hero h1 {
  font-size: clamp(2rem, 1.2rem + 2.6vw, 2.5rem);
  max-width: 30ch;
  color: var(--hero-head);
  /* The band already carries the teal rule along its own bottom edge; a second
     one under the headline is the device used twice in six inches. */
  border-bottom: 0;
  padding-bottom: 0;
}
.hero .claims li {
  background: var(--hero-card);
  border: 1px solid rgba(255, 255, 255, 0.24);
  color: var(--hero-card-ink);
}
.hero .claims strong { color: var(--hero-card-strong); }
.hero .claims .fine { color: var(--hero-card-muted); }
/* On the navy the secondary button becomes white-on-navy rather than teal-ink on
   white, because a white card floating on the band reads as a hole. */
.hero .button {
  background: transparent;
  color: var(--hero-head);
  border-color: rgba(255, 255, 255, 0.55);
}
.hero .button:hover { background: rgba(255, 255, 255, 0.12); color: var(--hero-head); border-color: #fff; }
.hero .button.primary {
  background: var(--hero-card);
  color: var(--hero-card-strong);
  border-color: var(--hero-card);
}
.hero .button.primary:hover { background: #e8f1f6; color: var(--hero-card-strong); border-color: #e8f1f6; }
.hero a { color: var(--hero-kicker); }
.hero > p { max-width: 56ch; font-size: 1.125rem; }
.hero .fine { max-width: 56ch; }

/* Three things the product does, side by side on a desktop. */
.claims {
  display: grid;
  gap: 0.9rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  list-style: none;
  margin: 2rem 0 0;
  padding: 0;
}
.claims li {
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.claims strong { display: block; margin-bottom: 0.3rem; color: var(--brand); }
.claims .fine { margin: 0; }

/* The facilities. A cell per site, every cell the same shape: town, name, kind,
   and — on the ones not open yet — the opening date pinned to the foot of the
   cell so that every date in a row sits on one line.

   `margin-top: auto` on the date is what does that, and it is the whole fix. The
   previous version put the date inline after the town, so its position depended on
   how long the name happened to be and no two cells agreed. */
.places {
  display: grid;
  gap: 0.75rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  list-style: none;
  margin: 0.875rem 0 0;
  padding: 0;
}
.places li {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.125rem;
  padding: 0.875rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
/* The thing somebody is actually looking for, so it leads. */
.places .town {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--accent-ink);
}
.places strong {
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
}
.places .kind { font-size: 0.75rem; color: var(--muted); }
/* Pushed to the bottom of the cell, which is what aligns them across a row. */
.places .opens {
  margin-top: auto;
  padding-top: 0.625rem;
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--warn);
}
/* Not open yet, and it has to look that way at a glance rather than only if you
   read the date — somebody scanning for their own town should not have to. */
.places.upcoming li, .places li.upcoming { background: var(--bg); border-style: dashed; }

/* A rule between "open today" and "on the way". Without it the second heading sits
   flush against the last open facility and reads as another entry in the list. */
.places + h3 {
  margin-top: 1.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line-strong);
}

/* Device 3, the amber callout: cream wash, 4px amber left border, and nothing
   else. Reserved for must-read notices — disclosures, exclusions, deadlines. If
   everything is a callout then nothing is. Amber is the border and never the
   words; the words are amber ink. */
.callout {
  border: 0;
  border-left: 4px solid var(--amber);
  background: var(--cream);
  border-radius: 4px;
  padding: 0.875rem 1.125rem;
  margin: 1rem 0;
  color: var(--ink);
}
.callout > :last-child { margin-bottom: 0; }
.callout.warn { color: var(--warn); }
.callout.info { border-left-color: var(--accent); background: var(--info-bg); }
.callout.success { border-left-color: var(--success); background: var(--success-bg); }
.callout.err, .callout.danger { border-left-color: var(--danger); background: var(--danger-bg); }

/* ---------------------------------------------------------------------------
   Long-form legal text

   Its own block because these pages are the only ones in the app that are prose
   first: a measure narrow enough to read a paragraph without losing your place,
   and headings that break the wall up rather than shout.

   `.plain` is the plain-words summary that sits above each section. Deliberately
   distinct from `.callout` — a callout is a warning about the thing you are
   reading, and this is a translation of it. Tinted, not boxed, so it reads as
   part of the document instead of an interruption in it.
   --------------------------------------------------------------------------- */
.legal { max-width: 46rem; }
.legal h2 {
  font-size: 1.15rem;
  margin: 2rem 0 0.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  color: var(--brand);
}
.legal h2:first-of-type { border-top: 0; padding-top: 0; }
.legal p { margin: 0.7rem 0; }
.legal ul { margin: 0.5rem 0 1rem; padding-left: 1.4rem; }
.legal li { margin: 0.3rem 0; }

.plain {
  background: var(--bg-2);
  border-left: 3px solid var(--accent);
  border-radius: 0 6px 6px 0;
  padding: 0.75rem 1rem;
  margin: 0.75rem 0 1.25rem;
}
.plain > :last-child { margin-bottom: 0; }
.plain p { margin: 0.4rem 0; }
.plain .eyebrow { margin-bottom: 0.35rem; }

.two-column { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; align-items: start; }
@container work (max-width: 56rem) { .two-column { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------------------
   The digital health card
   ---------------------------------------------------------------------------
   The one screen a member holds up to another human being, so it is the one that
   has to survive being read across a counter, in a hurry, on a cracked phone,
   possibly by somebody who has already decided the answer.

   Navy in both schemes — a FIXED surface, so every colour in here is a literal or
   one of the locals below. This is the third surface in this file that has to
   obey that rule and the reason is the same each time: a card that reads its
   colours from the page goes unreadable the moment somebody switches to dark.

   The status is never colour alone. It is a word in capitals, on its own ground,
   with its own shape — because the question this card answers decides whether
   somebody gets seen, and roughly one man in twelve cannot tell the green from
   the red.
   --------------------------------------------------------------------------- */

.health-card {
  --card-ink: #ffffff;
  --card-body: #cfdde9;         /* 6.7:1 on the lighter end of the gradient */
  --card-label: #b2c7d8;        /* 5.3:1 — the guide's own #9FB8CC lands on 4.50 */
  --card-line: rgba(255, 255, 255, 0.16);

  position: relative;
  max-width: 26rem;
  padding: 1.5rem 1.5rem 1.35rem;
  border-radius: 12px;
  /* The documented member-card gradient, exactly. */
  background: linear-gradient(135deg, #0e3a5e 0%, #134a76 100%);
  color: var(--card-body);
  box-shadow: 0 6px 18px rgba(14, 58, 94, 0.14);
}
.health-card .kicker { color: #bfe0ee; margin: 0; }
.health-card .name {
  margin: 0.6rem 0 0;
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--card-ink);
}
.health-card .lbl {
  display: block;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--card-label);
}

/* The answer. Capitals and a solid ground, because at a desk this gets read
   before anything else on the card and often instead of everything else. */
.health-card .card-state { margin: 0.9rem 0 0; }
.health-card .state-pill {
  display: inline-block;
  padding: 0.3rem 0.9rem;
  border-radius: var(--radius-pill);
  font-size: 0.875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
}
.health-card.is-active .state-pill { background: #1e7a46; color: #ffffff; }
/* Red rather than amber, and the word rather than the colour. An expired card and
   a card that was never paid for are the same answer to the only question being
   asked, which is whether to see this person on it. */
.health-card.is-inactive .state-pill { background: #b42318; color: #ffffff; }
.health-card .card-reason {
  margin: 0.65rem 0 0;
  max-width: 40ch;
  font-size: 0.875rem;
  color: var(--card-ink);
}

.health-card .card-number { margin: 1.1rem 0 0; }
.health-card .card-number .mono {
  display: block;
  margin-top: 0.15rem;
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--card-ink);
}

.health-card .card-rows {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem 1.75rem;
  margin-top: 1.1rem;
  font-size: 0.875rem;
  color: var(--card-body);
}
.health-card .card-covers { margin: 1.1rem 0 0; font-size: 0.875rem; max-width: none; }
.health-card .keyline {
  display: block;
  height: 3px;
  margin-top: 1.2rem;
  border-radius: 2px;
  background: #2e8fb0;
}

/* At a front desk. Bigger where it matters and only where it matters: the name
   and the verdict, which are the two things being checked. */
.health-card.desk { max-width: 34rem; }
.health-card.desk .name { font-size: 1.75rem; }
.health-card.desk .state-pill { font-size: 1.125rem; padding: 0.4rem 1.2rem; }
.health-card.desk .card-number .mono { font-size: 1.5rem; }

/* Printed, somebody wants it in a wallet. The gradient is dropped for flat navy —
   a printer renders a gradient as a band of dots — and the rest of the page goes
   with it. */
@media print {
  .health-card {
    max-width: 3.375in;
    background: #0e3a5e !important;
    box-shadow: none;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  .health-card .card-rows { gap: 0.5rem 1rem; }
}

/* ---------------------------------------------------------------------------
   Buttons
   --------------------------------------------------------------------------- */

/* Navy is the only button fill and amber is never a button — both are rules from
   the brand guide, not preferences. The secondary is a teal-ink outline on white,
   which is the documented pair. 44px minimum height throughout, because the
   published Accessibility Statement commits to it. */
.button {
  font-family: var(--font-display);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5ch;
  min-height: 44px;
  padding: 0.75rem 1.375rem;
  border: 1.5px solid var(--accent-ink);
  border-radius: var(--radius-sm);
  background: var(--surface-solid);
  color: var(--accent-ink);
  font: inherit;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.14s, color 0.14s, border-color 0.14s;
}
.button:hover {
  background: var(--info-bg);
  color: var(--accent-ink);
  border-color: var(--accent-ink);
}

.button.primary {
  background: var(--brand);
  border-color: var(--brand);
  color: var(--brand-ink);
}
.button.primary:hover {
  background: var(--brand-dim);
  border-color: var(--brand-dim);
  color: var(--brand-ink);
}

/* Quiet: no border, for the third action in a row where two outlines would read
   as two equal choices. */
.button.quiet { border-color: transparent; background: transparent; }

/* The way out of the portal, in the top bar beside the page action.
 *
 * Quiet, because it is a destination sitting next to an action and should lose that
 * contest. On a narrow screen the label shortens to "Website" rather than disappearing:
 * a phone is exactly where somebody is most likely to have arrived from the site and
 * want to get back, and the browser's own back button does not survive a sign-in. */
.return-to-site { white-space: nowrap; }
@media (max-width: 47.5rem) {
  .return-to-site { font-size: 0; padding-left: 0.75rem; padding-right: 0.75rem; }
  .return-to-site::after { content: "Website"; font-size: 0.9375rem; }
}
.button.quiet:hover { background: var(--info-bg); border-color: transparent; }

/* Red is for destructive and for error, and for nothing else. */
.button.danger { border-color: var(--danger); background: var(--danger); color: #ffffff; }
.button.danger:hover { border-color: var(--danger); background: #91190f; color: #ffffff; }

.button[disabled], .button[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}

button.link {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--brand);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 0.18em;
}
form.inline { display: inline; }

/* A dropdown and the button that commits it, as one control.
   **The defect this fixes.** `form.inline` is `display: inline`, which gives no layout
   control at all -- so a `<select>` took its width from its longest option ("Both
   GoHighLevel and portal leads") and the Set button beside it was pushed past the edge
   of its table cell and clipped by the next column, reading as "Se". The account holder
   saw it on the team screen the day it deployed.
   Flex, so the select may shrink and the button may not: `min-width: 0` is the part that
   matters, because a flex item's default `min-width: auto` refuses to go below its
   content's intrinsic width, which is exactly what pushed the button out. */
.cell-set { display: flex; align-items: center; gap: 0.4rem; }
/* **Sized to its content, not to its cell, and this is the second attempt.**
   `flex: 1 1 auto; min-width: 0` fixed the clipping and then squeezed the two selects
   down to "No new" and "N", which is one unreadable thing traded for another. The
   answer was already in this file: `main table` is `display: block; overflow-x: auto`,
   so a data table that does not fit is *meant to scroll* rather than squash. So the
   select takes the width it needs, the cell grows to hold it, and the table scrolls --
   which is what the nine-column discount log already does. */
.cell-set > select { flex: 0 0 auto; width: auto; min-width: 9rem; }
.cell-set > button { flex: 0 0 auto; }

/* A short number, its unit and the button that commits it, on one line.
   Stacking them was the first attempt and it doubled the height of the tallest cell in
   the widest table in the product, which pushed every row past a hundred pixels. Every
   control here is `min-height: 44px` by design, so a cell that stacks two of them is a
   cell that sets the row height for all nine columns. */
.cell-line { display: flex; align-items: center; gap: 0.4rem; white-space: nowrap; }
.cell-line label { display: flex; align-items: center; gap: 0.3rem; margin: 0; }
/* `size="3"` is advice a stylesheet overrides; this is the width a percentage needs. */
.cell-line input[type="text"] { width: 4.25rem; text-align: center; }

/* Two actions in one cell, told apart. Rendered as bare `display: inline` with a
   newline between them, "Remove access" and "Resend" sat one space apart and both
   underlined, so they read as a single four-word link. A middot and a gap is what
   separates them everywhere else in the app. */
main td > form.inline + form.inline::before,
main td > form.inline + .link::before,
main td > .link + form.inline::before {
  content: "·";
  margin: 0 0.5rem;
  color: var(--muted);
  text-decoration: none;
  display: inline-block;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  align-items: center;
  margin: 1.2rem 0 1rem;
}
.actions:last-child { margin-bottom: 0; }
/* A form inside an action row is a row too. Two forms side by side in `.actions` —
   "run this" and "mark it done, here is why" — stacked their own input above their
   own button, because a form is a block and only its parent was a flex container. */
.actions > form { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin: 0; }
.actions > form input[type="text"] { width: auto; max-width: 14rem; }
.row { display: flex; flex-wrap: wrap; gap: 0.6rem; }

/* ---------------------------------------------------------------------------
   Forms
   --------------------------------------------------------------------------- */

label {
  display: block;
  margin: 0.9rem 0 0.3rem;
  font-weight: 500;
  color: var(--ink-dim);
}
label .fine, label .help { font-weight: 400; display: block; margin-top: 0.25rem; }

input, select, textarea {
  width: 100%;
  /* The same 44px a button is. A control row mixing a 35px select with a 44px
     button looked misaligned however it was aligned — on the discount log and the
     employer picker both — and 44px is the target size these want anyway. */
  min-height: 44px;
  padding: 0.62rem 0.75rem;
  font: inherit;
  color: var(--ink);
  background: color-mix(in oklab, var(--bg) 55%, var(--surface-solid));
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  transition: border-color 0.15s, box-shadow 0.15s;
}
input::placeholder, textarea::placeholder { color: var(--muted); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: var(--ring);
}
textarea { min-height: 6rem; resize: vertical; }

/* A checkbox is not a text field. It was inheriting the 12px horizontal padding
   above, which put roughly 50px of nothing between every box and its own label —
   visible on every filter row and every consent tick in the product. */
input[type="radio"], input[type="checkbox"] {
  min-height: 0;
  width: auto;
  padding: 0;
  margin: 0 0.4rem 0 0;
  accent-color: var(--accent);
  box-shadow: none;
}
input[type="file"] { padding: 0.5rem; background: transparent; }

fieldset {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.5rem 1.1rem 1.1rem;
  margin: 1.1rem 0;
}
legend { padding: 0 0.45rem; font-weight: 600; color: var(--ink); }

/* Control's per-person controls, and the two faults the account holder reported on
   3 September 2026: the page ran off the right of the screen, and the country picker sat
   on top of the "Telephone number" label beside it.

   **The overlap and most of the width were one thing, and it was the `nowrap` exemption
   list above** -- see the comment on `main table`. Nothing here fixes those; they are
   fixed by letting a form in a cell wrap like the prose it contains.

   What is left for this block is the administrators row, which carried four
   `form.inline` side by side -- suspend, remove the role, force a new password, delete
   the login -- plus two panels. Scrolling sideways is right for a wide *data* table and
   wrong for a column of actions: "Delete the login" was somewhere off to the right.

   Stacked, one action per line. The `·` separator between consecutive inline forms
   disappears without a new rule, because its selector is `main td > form.inline +
   form.inline` and these are no longer direct children of the cell -- which is the
   argument for wrapping them in a container rather than adding an override that has to
   be kept in step.

   **Two rules were tried here and removed, and measuring each is the only reason they
   are not still in the file.** A `width: 26rem` on the panel, on the theory that a
   shrink-to-fit cell gave percentages nothing to resolve against; and explicit
   flex-column labels, on the theory that the label-above-control layout was too
   fragile. Once the `nowrap` list was corrected the label rule changed **nothing**
   measurable, and the width bound made a 1024px screen *worse* -- 217px of overflow
   against 60px, and 136 elements past the viewport against none -- because a definite
   width forces the cell wide when the screen is narrow. A theory that predicts a real
   defect can still be the wrong theory. */
/* And the other half of the same report: Control's tables now stop short of the right
   edge instead of running past it.

   `main table` is `display: block; overflow-x: auto` so a wide *data* table scrolls
   rather than wrapping every cell into four lines -- the nine-column discount log is
   why, and that rule stays exactly as it is. But `display: block` leaves the internal
   table layout shrink-to-fit, so a table whose content is *narrower* than its container
   stops early. Measured at a 1990px viewport: the table box was 1617px and its rows
   1357px, which is the 260px of white space the account holder reported.

   **This is the second half of the nowrap fix, not a new idea.** Control's cells only
   became narrow when the exemption let its forms wrap; before that they were 3126px
   wide and the table filled by overflowing. One change made it wrap and this one makes
   it fill.

   **Scoped to the two tables rather than changing `main table`, and the measurement is
   why.** `display: table` fills beautifully here and takes away the ability to scroll,
   which is the one thing the nine-column log needs. Verified with a nine-column table
   on the same page: these two fill at 1990, 1440, 1024 and 800 with the header aligned
   and no scroll, while the data table beside them still scrolls 291px at 1440 and 679px
   at 1024. One page's measurement is not evidence about another page's table.

   **And only two of Control's five tables carry it, which is a line rather than a
   preference.** `display: table` fills and takes away the scroll, so it is safe exactly
   where the content can *wrap*. These two can, because the same fix let their forms
   wrap. The other three -- "Who can get past this screen" and the two When/Who/What
   logs -- hold `nowrap` data, so filling them would overflow a date or an address out
   of its cell instead of scrolling the table, which is the worse of the two and is what
   `display: block` was put there to prevent. They stay as they are. */
.fills-the-width { display: table; }

.staff-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 0.55rem; }
.staff-actions > form.inline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin: 0;
}
.staff-actions > form.inline input[type="text"] { max-width: 12rem; }

/* Every label in a Control panel sits above its control, rather than some inline and
   some not. **This fixes nothing and is not pretending to** -- it was measured against
   the overflow and the overlap and changed neither, which is why the note above records
   it as removed. What it does change is the look: without it a label wraps above its
   control only when the two cannot share a line, so "Sign-in address" ends up above its
   box and the shorter "Full name" beside it, and a column of fields lines up raggedly.
   Stating the column makes it uniform at every width.
   `:not(.inline)` because the "keep sign-in" tick is a label too and belongs on one line
   with its own sentence. */
.staff-actions label:not(.inline),
main table td form.stack label:not(.inline) {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.25rem;
}
main table td form.stack label:not(.inline) > input,
main table td form.stack label:not(.inline) > select,
main table td form.stack label:not(.inline) > textarea { width: 100%; }

/* A short field in a table cell stays short. `input { width: 100% }` is right for a
   form and wrong in a table: the eighteen-character reason box on the sales team
   screen filled its whole column and pushed the Offboard link onto its own line. */
main table input[type="text"], main table input[type="search"] { width: auto; max-width: 100%; }

/* Checkbox and its sentence on one line, aligned on the first line of text
   rather than centred — a two-line label centred against a box looks broken. */
.acknowledge, .inline-label, label.checkbox {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  font-weight: 400;
  color: var(--ink);
}
.acknowledge input, .inline-label input, label.checkbox input { margin: 0.35rem 0 0; }
/* Help text under the sentence, not beside it. These labels are flex rows, so a
   help span became a third column and the explanation ran off to the right of the
   thing it explained — on Add a salesperson it was two sentences wide, level with
   the checkbox. `flex-wrap` plus a full-basis span puts it on its own line, and
   the indent lines it up under the sentence rather than under the box. */
.acknowledge, .inline-label, label.checkbox { flex-wrap: wrap; }
.acknowledge > .field-help, .inline-label > .field-help, label.checkbox > .field-help,
.acknowledge > .fine, .inline-label > .fine, label.checkbox > .fine {
  flex: 0 0 100%;
  margin: 0.25rem 0 0;
  padding-left: 1.5rem;
}

/* The same alignment for help text that has to sit *outside* the label rather than
   inside it. The pricing step's prepay note carries a link to the Agreement, and a
   link inside a <label> selects the control when it is clicked — so it is a sibling,
   and this lines it up under the option's text rather than under the radio. Shares the
   1.5rem above deliberately: two indents that nearly agree look like a mistake. */
.fine.indent, .field-help.indent { padding-left: 1.5rem; margin-top: 0.25rem; }
/* The figures are a summary of what was entered above, not another field, so they
   need a gap the fields between them do not have — rendered without it, the first
   row of the total hugged the discount-code box as though it were its help text. */
form .price-summary { margin: 1.4rem 0 0; }
/* A bare form is not a panel and carries no bottom margin, so the next section's
   heading sat directly on the last control — on Price a deal, "Codes you have
   created" looked like a label for the button above it. */
form + h2, form + h3, form + section { margin-top: 1.9rem; }
form .acknowledge { margin-top: 1.2rem; }


/* ---------------------------------------------------------------------------
   Signing in
   ---------------------------------------------------------------------------
   Every auth screen — sign in, sign up, both password resets, the two password
   changes — is one card, centred, on the brand's own furniture: navy header with
   the kicker and the title, white body with the fields.

   Styled by the class the six screens already shared rather than by editing six
   templates, so they cannot drift apart. `.auth-shell` centres it, `.auth-head`
   is the navy band, and the header is a FIXED navy surface, so everything in it
   is a literal.
   --------------------------------------------------------------------------- */

.auth-shell {
  max-width: 30rem;
  margin: clamp(1rem, 5vh, 3.5rem) auto;
}
.auth-head {
  padding: 1.5rem 1.75rem 1.35rem;
  border-radius: var(--radius) var(--radius) 0 0;
  background: linear-gradient(160deg, #0e3a5e, #123f6b);
  border-bottom: 4px solid #2e8fb0;
  color: #cfdde9;
}
.auth-head .kicker { color: #bfe0ee; }
.auth-head h1 {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 1.625rem;
  color: #ffffff;
}
.auth-head p { margin: 0.5rem 0 0; max-width: 34ch; color: #cfdde9; font-size: 0.9375rem; }

.auth-form {
  max-width: none;
  margin: 0;
  padding: 1.6rem 1.75rem 1.75rem;
  border: 1px solid var(--line);
  border-top: 0;
  border-radius: 0 0 var(--radius) var(--radius);
  background: var(--surface-solid);
  box-shadow: var(--shadow);
}
.auth-form > button, .auth-form > .button { width: 100%; }
/* The links under the card: alternatives to signing in, not part of the form. */
.auth-aside {
  margin: 1.1rem 0 0;
  text-align: center;
  font-size: 0.9375rem;
  color: var(--muted);
}
.auth-aside a { color: var(--accent-ink); font-weight: 600; }

/* Google sign-in. New furniture rather than a change to any of the above: these two
   classes exist because the button does, and they are built from the same tokens as
   everything else so it reads as part of the card rather than bolted to it.

   The rule with "or" through it is doing real work. Without it the two buttons stack
   and read as a two-step process — fill this in, *then* press Google — which is the
   commonest way a social login gets ignored. */
.auth-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1.1rem 0;
  color: var(--muted);
  font-size: 0.875rem;
  text-transform: lowercase;
}
.auth-divider::before, .auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

/* Deliberately not `.primary`. There is one primary action on these screens and it is
   the form's own button; a second filled button would make the member choose between
   two things that look equally intended. */
.button.google {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  width: 100%;
  background: var(--surface-solid);
}
.button.google svg { flex: none; }

/* Django's own form output. The allauth screens render `{{ form.as_div }}` rather
   than field-by-field markup, because their field names are allauth's and not all of
   them are pinned by our settings — so these three classes are the ones Django
   generates, and they need to look like the rest of the product. */
.auth-form div:has(> label) { margin-bottom: 0.9rem; }
.helptext {
  display: block;
  margin-top: 0.3rem;
  color: var(--muted);
  font-size: 0.9rem;
}
.helptext ul, ul.helptext { margin: 0.3rem 0 0; padding-left: 1.2rem; }
ul.errorlist {
  list-style: none;
  margin: 0.4rem 0 0;
  padding: 0.5rem 0.75rem;
  border: 1px solid color-mix(in oklab, var(--danger) 45%, transparent);
  border-radius: var(--radius-sm);
  background: var(--danger-bg);
  color: var(--danger);
  font-size: 0.9rem;
}
/* A submit button that is not inside `.actions` still needs the space `.actions`
   would have given it — on the sign-in page it sat flush against the "forgotten
   your password" line below it. */
.auth-form > button, .auth-form > .button { margin: 1.4rem 0 0; }

/* A field that reads as a sentence — "Extend by [30] days" — so the label flows
   inline with its own input rather than stacking above a full-width box. Only the
   form was styled `.inline` before, which left the label inside it stacking and the
   input filling the line, so the sentence came apart into three rows. */
label.inline {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  margin: 0 0.5rem 0 0;
  font-weight: 400;
}
label.inline input, label.inline select { width: auto; }

/* A vertical run of fields with one rhythm, rather than each label bringing its
   own margin. */
.stack { display: flex; flex-direction: column; gap: 0.15rem; }
.stack > label { margin-top: 0.9rem; }
.stack > .actions { margin-top: 1.2rem; }

/* The country picker beside the number it belongs to, because they are one field even
   though they post as two. `.stack > label` sets the top margin, so the wrapper takes
   it and the two labels inside do not stack their own on top of each other. The picker
   is given a fixed basis rather than sharing evenly: a country list is long and the
   number is what somebody is actually typing, so the number gets the room. */
.stack > .field-pair { margin-top: 0.9rem; display: flex; gap: 0.75rem; flex-wrap: wrap; }
.field-pair > label { margin-top: 0; }
.field-pair > label:first-child { flex: 0 1 15rem; min-width: 0; }
.field-pair > label:first-child select { width: 100%; }
.field-pair > label:last-child { flex: 1 1 12rem; min-width: 0; }
@media (max-width: 34rem) {
  /* Below this the two sit on one line only by squeezing the number to nothing. */
  .stack > .field-pair { flex-direction: column; gap: 0.6rem; }
}
/* A column flex container stretches its children, which is right for a text input
   and wrong for a button — "Create account" was as wide as the form. */
.stack > button, .stack > .button { align-self: flex-start; margin-top: 1.3rem; }

/* A one-time code is read off a screen and typed a character at a time, so it
   gets room and spacing rather than being crammed into a normal text box. */
.code-input {
  max-width: 11rem;
  font-family: var(--mono);
  font-size: 1.6rem;
  letter-spacing: 0.32em;
  text-align: center;
}
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1rem;
  align-items: flex-end;
  margin: 0 0 1.25rem;
}
.filters label { margin: 0; font-size: 0.9rem; }
.filters input, .filters select { min-width: 9rem; width: auto; }
.filters .button { margin-top: 0; }

/* ---------------------------------------------------------------------------
   Text utilities and status
   --------------------------------------------------------------------------- */

.muted { color: var(--muted); }
/* 13px meta, the bottom of the documented scale. `.fine` is the smallest text
   the product has, and it is never the only place something is said. */
.fine { color: var(--muted); font-size: 0.75rem; line-height: 1.5; }
/* `.help` is the 18px lead above, but the same word is used for field help — and
   an 18px hint under a 16px input reads as the more important of the two. */
label .help, .field .help, .filters .help { font-size: 0.875rem; max-width: none; margin: 0.25rem 0 0; }
.error { color: var(--danger); }
.credit { color: var(--brand); font-weight: 600; }
/* Scoped to text elements on purpose. `.panel.warn` is a *container* that uses the
   same word, and an unscoped colour rule turned every line inside it orange. */
p.warn, span.warn, li.warn, strong.warn { color: var(--warn); }

.status {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.1875rem 0.625rem 0.1875rem 0.5rem;
  border-radius: var(--radius-pill);
  border: 0;
  background: var(--surface-2);
  color: var(--muted);
  font-size: 0.71875rem;
  font-weight: 700;
  white-space: nowrap;
}
/* The dot, from the element rather than from markup — which is how it reaches
   every badge in the product without editing forty templates. It takes the
   badge's own colour, so each variant gets a matching dot for free. */
.status::before {
  content: "";
  width: 6px;
  height: 6px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: currentColor;
}
.badge-success { background: var(--success-bg); color: var(--success); }
.badge-warning { background: var(--warn-bg); color: var(--warn); }
.badge-danger { background: var(--danger-bg); color: var(--danger); }
.badge-info { background: var(--info-bg); color: var(--info); }
/* Neutral: a draft, a cancellation, something settled and not worth a colour.
   `status_badge` has returned "secondary" since it was written and nothing styled
   it, so these fell through to the plain treatment by accident. Same result,
   deliberately. */
.badge-secondary { background: var(--surface-2); color: var(--muted); }

/* Lead temperature. A left bar as well as a hue, because these three are read
   in a column at speed and hue alone is the one signal some readers do not
   receive at all. */
.status.badge-hot { border-left: 4px solid var(--danger); }
.status.badge-warm { border-left: 4px solid var(--warn); }
.status.badge-cold { border-left: 4px solid var(--info); }

.messages {
  list-style: none;
  max-width: var(--measure);
  margin: 1.1rem auto 0;
  padding: 0 1.25rem;
}
.messages li {
  padding: 0.75rem 1rem;
  margin: 0 0 0.55rem;
  border: 1px solid var(--line-strong);
  border-left: 3px solid var(--info);
  border-radius: var(--radius-sm);
  background: var(--surface);
  backdrop-filter: blur(10px);
  color: var(--ink);
}
.messages li.error { border-left-color: var(--danger); background: linear-gradient(var(--danger-bg), var(--danger-bg)), var(--surface-solid); }
.messages li.success { border-left-color: var(--success); background: linear-gradient(var(--success-bg), var(--success-bg)), var(--surface-solid); }
/* `warning` here, not `warn`: Django's messages framework emits the tag, so this
   one spelling is not ours to choose. */
.messages li.warning { border-left-color: var(--warn); background: linear-gradient(var(--warn-bg), var(--warn-bg)), var(--surface-solid); }

/* ---------------------------------------------------------------------------
   Figures: prices, facts, tables
   --------------------------------------------------------------------------- */

.price-summary dl, .facts, dl.data {
  display: grid;
  /* `minmax(0, …)` on both, so a long note under a figure wraps inside the panel
     instead of sizing the column to its longest line and overflowing. */
  grid-template-columns: minmax(0, 1fr) minmax(0, auto);
  /* No column gap: the total's rule is drawn on both cells, and a gap between
     them left it as two floating lines instead of one. The dd's padding does the
     separating instead. */
  gap: 0.4rem 0;
  margin: 0;
}
.price-summary dt, .facts dt, dl.data dt { color: var(--muted); }
.price-summary dd, .facts dd, dl.data dd {
  margin: 0;
  padding-left: 1.5rem;
  text-align: right;
}
.price-summary dd .fine, .facts dd .fine { display: block; text-align: right; }

.price-summary .total, .facts dt.total, .facts dd.total {
  font-weight: 700;
  font-size: 1.12rem;
  color: var(--ink);
  padding-top: 0.35rem;
  border-top: 1px solid var(--line);
}
.price-summary dd.total, .facts dd.total { color: var(--brand); }

/* What a negotiated deal actually charges, per billing cycle. Price a deal only.

   Deliberately **not** `.facts`, which was the obvious reuse and is wrong here: that
   pattern is a two-column grid with a right-aligned `dd`, built for a label against a
   figure. These `dd`s are sentences — "3 yearly charges of $824.17, then $1,300.00 a
   year from 9 Mar 2028" — and right-aligning a wrapped sentence against a label
   column makes it unreadable at any width. Stacked, full width, label above. */
.deal-shape { margin: 0 0 0.75rem; }
.deal-shape dt {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 0.7rem;
}
.deal-shape dd {
  margin: 0.15rem 0 0;
  /* Overriding the `.price-summary dd` rules above rather than relying on order:
     those set `padding-left` and `text-align: right`, and both are wrong for prose. */
  padding-left: 0;
  text-align: left;
}
.deal-shape dd .fine {
  display: block;
  margin-top: 0.35rem;
  /* The one place a `.fine` on this screen is a warning rather than an aside — it is
     what stops a rep saying "six months" to somebody paying yearly. Given the callout
     tint so it does not read as small print to be skipped. */
  padding: 0.5rem 0.6rem;
  border-left: 3px solid var(--warn);
  background: var(--warn-bg);
  text-align: left;
}

/* Every table in the content, by element rather than by class. Fourteen of the
   twenty-five tables in this product carried no class and so were styled by the
   browser and nobody else — the sales team, the front desk, the check-in log, an
   employer's roster, the credit ledger. Three classes were doing the work of a
   default. `.report-table`, `.data` and `.diff` still select, because a screen
   may want to say what kind of table it is, but nothing depends on them. */
main table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.94rem;
  /* Scrolls whenever it does not fit, rather than below a width somebody guessed
     at. Four columns of money have a minimum width; under it a squashed column is
     unreadable and a clipped one is invisible. This was keyed to 40rem, and the
     business summary's table needs 55 — so between the two it clipped by 20px,
     which is exactly the kind of thing a fixed breakpoint gets wrong. At widths
     where it does fit, `width: 100%` still fills and nothing scrolls. */
  display: block;
  overflow-x: auto;
}
/* At every width, not below a breakpoint. This was keyed to 40rem, on the idea
   that only a narrow screen squashes a table — but the discount log has nine
   columns, and at 72rem it wrapped a date to two lines, a code to two lines and an
   email to two, giving four-line rows nobody can read across. A data table that
   does not fit should scroll; wrapping every cell is the worse of the two. Prose
   inside a cell still wraps, whether `fine` is on the cell or on a span in it —
   otherwise one column of explanation makes the whole table twice as wide as the
   screen. */
main table { white-space: nowrap; }
/* **The exemption list is the fragile part, and it had drifted.** It named `.fine`,
   `td.fine` and `p`, and the account holder reported Control running off the right of
   the screen on 3 September 2026 because those panels use neither: a `.field-help` span
   and a `<label>`. Inherited `nowrap` meant a label and its control could never go onto
   separate lines the way they do everywhere else, and the help text ran on one line for
   ever -- measured, the administrators table wanted **3126px** against a 675px cell.
   `form` is added to cover the shape rather than the instance. A form inside a cell is
   controls and prose; it is never tabular data, so it should never have been in the
   nowrap set, and a fifth thing that needs exempting will otherwise arrive the same
   way this fourth one did. */
main table td .fine, main table td.fine, main table td p,
main table td .field-help, main table td form { white-space: normal; }
main th, main td {
  padding: 0.55rem 0.65rem;
  text-align: left;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
main th {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
main tbody tr:hover { background: var(--surface-2); }
main td .fine { display: block; }
/* Kept so a template can still name what a table is; the styling above no longer
   needs it. */
.report-table, table.data, table.diff { border-collapse: collapse; }

.diff .before { color: var(--muted); text-decoration: line-through; }
.diff .after { color: var(--brand); font-weight: 600; }

/* ---------------------------------------------------------------------------
   Lists
   --------------------------------------------------------------------------- */

.search-form { margin: 1.25rem 0 2rem; max-width: 42rem; }
.search-form input[type="search"] { font-size: 1.1rem; padding: 0.7rem 0.9rem; }

.search-results, .documents, .dependent-list, .funnel {
  list-style: none;
  margin: 0;
  padding: 0;
}
.search-results li, .dependent-list li {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: baseline;
  justify-content: space-between;
  padding: 0.85rem 1rem;
  margin: 0 0 0.6rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  transition: border-color 0.15s, transform 0.12s;
}
.search-results li:hover, .dependent-list li:hover {
  border-color: var(--brand);
  transform: translateX(2px);
}
.search-results li.muted, .dependent-list li.muted { display: block; }

/* Which pricing band a calculator figure landed in. Quiet and above the prices: it is
   context for them rather than a claim of its own, and a reader only looks at it when
   they are checking that their number was read the way they meant it. */
/* Giving a lead an owner, from the row on the lead report. Inline and quiet: it sits at
   the end of a line of pills and must not read as the point of the row — the lead is,
   and the owner is one fact about it. */
.assign-lead {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0 0 0 0.4rem;
}
.assign-lead select {
  margin: 0;
  padding: 0.15rem 0.4rem;
  font-size: 0.8rem;
  width: auto;
}
.assign-lead .button { padding: 0.2rem 0.6rem; font-size: 0.8rem; }

.calc-result .band {
  margin: 0 0 0.75rem;
  color: var(--muted);
  font-size: 0.9rem;
}

.documents li::before { content: "📄 "; }

/* Documents a member sent in answer to a request, waiting to be filed onto their
   policy. Set apart from the list above it because the two mean different things: that
   list is what is *on* the record, this is what is one press away from being on it, and
   run together they read as one list where half the rows have a stray button.

   Tinted rather than bordered — a border here would be the fourth nested box inside a
   panel that already has one, which is the chrome problem `.own-insurance` records. */
.attachable {
  margin-top: 0.85rem;
  padding: 0.75rem 0.85rem;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.attachable > p { margin-top: 0; }
.attachable .rows li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
.attachable form { margin: 0; }

/* The abandoned-signup funnel: a bar per stage, sized by share, so where people
   stop is visible without reading the numbers. */
.funnel li {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.2rem 1rem;
  padding: 0.45rem 0;
  border-bottom: 1px solid var(--line);
}
.funnel li:last-child { border-bottom: 0; }

/* ---------------------------------------------------------------------------
   The application wizard
   --------------------------------------------------------------------------- */

.wizard { padding: clamp(1.25rem, 4vw, 2rem); }

/* A rail rather than a list. Its job is a way back: a subscriber handed a
   finished application landed on the review step needing to tick a box that
   lives two steps earlier, with nothing on the page that went there. Steps not
   yet reached are plain text, not disabled links, so nothing invites a click
   that would jump the server's checks. */
.step-nav { margin: 0 0 1.4rem; }
.step-nav .progress {
  margin: 0 0 0.5rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}
.step-nav ol {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 0.85rem;
}
.step-nav li {
  padding: 0.22rem 0.65rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  color: var(--muted);
}
.step-nav li a { text-decoration: none; }
.step-nav li.done { border-color: var(--line-strong); }
.step-nav li.done a { color: var(--ink-dim); }
.step-nav li.done:hover { border-color: var(--brand); }
.step-nav li.current {
  border-color: var(--brand);
  background: var(--brand-glow);
  color: var(--ink);
  font-weight: 600;
}
.step-nav li.ahead { opacity: 0.6; }

/* Staff filling somebody else's application in. Violet, not the brand teal, and
   deliberately loud: the one mistake this screen invites is forgetting whose
   account you are typing into. */
.wizard.assisted {
  border-color: color-mix(in oklab, var(--violet) 55%, transparent);
  box-shadow: var(--shadow), 0 0 0 1px color-mix(in oklab, var(--violet) 30%, transparent);
}
.assisted-banner {
  border: 1px solid color-mix(in oklab, var(--violet) 50%, transparent);
  background: linear-gradient(var(--violet-glow), transparent), var(--surface-2);
  border-radius: var(--radius-sm);
  padding: 0.85rem 1.1rem;
  margin: 0 0 1.25rem;
}
.assisted-banner p { margin: 0.25rem 0; }
.assisted-banner strong { color: var(--violet); }

.dependent-list li strong { color: var(--ink); }

/* ---------------------------------------------------------------------------
   Choosing: prices, payment methods, locations
   ---------------------------------------------------------------------------
   All three are the same problem — pick one of a few things, and be able to
   compare them without scrolling between them. Selection is shown with an
   outline and a glow rather than a fill, so it survives a monochrome screen and
   anybody who cannot separate two tints. */

.price-options { display: grid; gap: 0.9rem; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); margin: 1.25rem 0; }
.price-option {
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: 1.15rem 1rem;
  text-align: center;
  background: var(--surface-2);
}
.price-option.selected { border-color: var(--brand); box-shadow: var(--ring); }
.price-option .amount {
  font-family: var(--font-display);
  display: block;
  margin: 0.3rem 0;
  font-size: 2.1rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--ink);
}
.price-option .per { font-size: 0.95rem; font-weight: 400; color: var(--muted); }
.price-option .save { margin: 0; color: var(--brand); font-size: 0.9rem; font-weight: 600; }

.pay-option {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin: 0 0 0.8rem;
  padding: 1rem 1.1rem;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  font-weight: 400;
  cursor: pointer;
}
.pay-option:has(input:checked) { border-color: var(--brand); box-shadow: var(--ring); }
.pay-option input { margin: 0.4rem 0 0; }
.pay-option strong { font-size: 1.05rem; color: var(--ink); }
.pay-option-body { flex: 1; min-width: 0; }
.pay-option .facts { margin: 0.6rem 0 0; }
@container work (min-width: 46rem) {
  /* `.stack` sets a column direction, so the row has to be asked for explicitly —
     without it the two totals sat one under the other, and the whole point of the
     screen is comparing them side by side. */
  form.stack:has(.pay-option) {
    display: flex;
    flex-flow: row wrap;
    gap: 0.8rem;
  }
  form.stack .pay-option { flex: 1 1 20rem; margin: 0; }
  form.stack:has(.pay-option) .actions { flex: 1 1 100%; }
}

/* Where the clerk is working. Targets big enough for somebody standing at a
   counter, and one press to answer — a select plus a submit is two, and this is
   the screen they meet every morning. */
.where .location-choice {
  display: grid;
  gap: 0.7rem;
  grid-template-columns: 1fr;
  margin-top: 1.25rem;
}
@container work (min-width: 40rem) {
  .where .location-choice { grid-template-columns: 1fr 1fr; }
}
.location-option {
  display: block;
  text-align: left;
  cursor: pointer;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
  font: inherit;
  color: var(--ink);
  transition: border-color 0.15s, box-shadow 0.15s, transform 0.12s;
}
.location-option:hover, .location-option:focus-visible {
  border-color: var(--brand);
  transform: translateY(-2px);
}
.location-option.current { border-color: var(--brand); box-shadow: var(--ring); }
.location-option strong { display: block; font-size: 1.05rem; }
.location-option .fine { color: var(--muted); }

/* The one fact a clerk must be able to check without hunting for it: every
   visit they record for the rest of the shift lands here. */
.here-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: baseline;
  justify-content: space-between;
  margin: 0 0 1.35rem;
  padding: 0.7rem 1.1rem;
  border: 1px solid color-mix(in oklab, var(--brand) 40%, transparent);
  border-radius: var(--radius-sm);
  background: linear-gradient(90deg, var(--brand-glow), transparent 70%), var(--surface-2);
  color: var(--ink);
}
.here-bar strong { color: var(--brand); }

/* Agreeing a price on the way back in. Set apart from the code field above it
   because they are alternatives, not a sequence — that field takes a code
   somebody already made, this makes one. */
.agree-price {
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.agree-price p.fine { margin-top: 0.4rem; }

/* ---------------------------------------------------------------------------
   The work queue

   The screen an administrator lives on. It is a *triage* view, so the visual
   order has to be the cost order: money leaving the business now, then money
   that will fail at renewal, then paperwork. Colour carries the same ranking —
   red, amber, plain — and never carries it alone, because roughly one man in
   twelve cannot tell the first two apart. Every panel says which it is in words
   and shows its own count.
   --------------------------------------------------------------------------- */

/* A decorative line under the page title, echoing the heartbeat in the mark.
   Nothing reads it and nothing depends on it. */
.pulse { display: block; width: 100%; height: 1.25rem; margin: 0.25rem 0 1.5rem; color: var(--accent); opacity: 0.55; }

/* The numbers, as one band rather than four cards: they are read across, not
   individually, and four bordered boxes make four things to look at. Navy in
   both schemes — a FIXED surface, so every colour in here is a literal. */
.vitals {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0;
  margin: 0 0 1.625rem;
  border-radius: 16px;
  overflow: hidden;
  /* The concept's band, with a pool of teal light across it. Fixed navy in both
     schemes, so every colour in here is a literal.

     The teal is at 0.15, which is the concept's own effective strength — it draws
     the glow at 0.30 inside a layer set to opacity 0.5. Worth matching rather than
     eyeballing: at 0.25 the 11px labels on the brightest point of the pool fall to
     4.37:1, and at the 0.42 I first tried, 3.54:1. At 0.15 they hold 4.90:1. */
  background:
    radial-gradient(circle at 12% 30%, rgba(46, 143, 176, 0.15), transparent 45%),
    linear-gradient(120deg, #0e3a5e, #0b2f4c);
  color: #eaf4fb;
}
.vitals > div { padding: 1.25rem 1.625rem; border-left: 1px solid rgba(255, 255, 255, 0.1); }
/* A <dd> carries `margin-inline-start: 40px` from the browser's own stylesheet.
   Left in, every caption sat 40px right of the number it describes. */
.vitals dd { margin: 0; }
/* The concept's own names for the three parts of a figure, so ported markup reads
   as it was written. */
.vital { padding: 1.25rem 1.625rem; border-left: 1px solid rgba(255, 255, 255, 0.1); }
.vital:first-child { border-left: 0; }
.vital-label { font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: #9cbbd3; }
.vital-value {
  display: flex;
  align-items: baseline;
  gap: 0.375rem;
  margin: 0.5rem 0 0.375rem;
  font-family: var(--font-display);
  font-size: 1.5625rem;
  font-weight: 700;
  line-height: 1.15;
  color: #ffffff;
  font-variant-numeric: tabular-nums;
}
.vital-value small { font-size: 0.75rem; font-weight: 500; color: #9cbbd3; }
.vital-delta { font-size: 0.71875rem; font-weight: 600; }
/* Three readings, and each says which it is in words as well as in colour. */
.vital-delta.up { color: #7fe0c4; }
.vital-delta.risk { color: #f0a48f; }
.vital-delta.flat { color: #9cbbd3; }
/* A link in here inherits the global `a { color: var(--brand) }`, which is navy —
   navy on navy, invisible. Every fixed navy surface needs to say this for itself:
   the surface can declare its own text colours but not what an element rule
   somewhere else will inherit into it. Underlined, because on a band this dense
   colour alone is not enough to read as a link. */
.vitals a, .health-card a {
  color: #ffffff;
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
.vitals a:hover, .health-card a:hover { color: #ffffff; }
.vitals > div:first-child { border-left: 0; }
.vitals dt { font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: #9cbbd3; }
.vitals .n { font-family: var(--font-display); font-size: 1.5625rem; font-weight: 700; line-height: 1.15; margin: 0.5rem 0 0.375rem; }
.vitals .note { font-size: 0.71875rem; color: #9cbbd3; }
/* A figure that is bad news, marked as such rather than left to be inferred
   from a colour nobody agreed to read. */
.vitals .bad .n, .vitals .bad .note { color: #f0a48f; }

/* A tinted alert is a FIXED light surface: the pink and the amber are the point
   of it, so they do not flip with the scheme. That means nothing inside may read
   a token that does flip — the page ink goes near-white in dark mode and the
   prose disappears onto its own background, which is exactly what happened to
   the hero band. Locals, or literals, and nothing else. */
.alert {
  --alert-ink: #222222;
  --alert-muted: #5b6b7a;
  --alert-chip: #ffffff;
  --alert-chip-ink: #222222;
  --alert-chip-line: #d9e2e9;
  --alert-chip-muted: #5b6b7a;
  position: relative;
  margin: 0 0 1.25rem;
  padding: 1.25rem 1.4rem;
  border: 1px solid;
  border-radius: var(--radius);
  color: var(--alert-ink);
}
.alert p, .alert li { color: var(--alert-ink); }
.alert p { max-width: 68ch; }
.alert .fine, .alert .help, .alert .muted { color: var(--alert-muted); }
.alert .button.primary {
  background: #0e3a5e;
  border-color: #0e3a5e;
  color: #ffffff;
}
.alert .button.primary:hover { background: #0b2f4c; border-color: #0b2f4c; }
/* The count, in the corner, in the panel's own colour. Big enough to read from
   the top of the page: how many is the first thing you want and the last thing
   you should have to count. */
.alert .tally {
  position: absolute;
  top: 1rem;
  right: 1.25rem;
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* The documented washes and inks, not ones picked by eye: error #B42318 on
   #FCEEEC, amber ink #8A5E12 on cream #FFF6E8. The left border is the brand's
   callout device at the panel scale. */
.alert.stop { background: linear-gradient(180deg, #fceeec, #ffffff 70%); border-color: #f0c7be; }
.alert.stop h2, .alert.stop .tally { color: #b42318; }
.alert.gap { background: linear-gradient(180deg, #fff6e8, #ffffff 70%); border-color: #efd3a3; }
.alert.gap h2, .alert.gap .tally { color: #8a5e12; }

/* Who is affected, named. A count on its own is a number to worry about; the
   names are the thing you act on, and four of them fit where a table would not. */
.chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.9rem 0 1.1rem; padding: 0; list-style: none; }
.chips li {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  padding: 0.3rem 0.7rem;
  border-radius: var(--radius-pill);
  font-size: 0.88rem;
  /* Outside an alert these fall back to the page tokens, so the same component
     works on a plain panel. */
  background: var(--alert-chip, var(--surface-solid));
  color: var(--alert-chip-ink, var(--ink));
  border: 1px solid var(--alert-chip-line, var(--line-strong));
}
.chips .id { font-family: var(--mono); font-size: 0.8rem; color: var(--alert-chip-muted, var(--muted)); }

/* A queue as rows rather than a bulleted list. These are things to act on, and a
   bullet list runs the name, the status and the count together into one line of
   prose you have to read to the end of. A row per item, status pushed to the far
   edge, so a column of statuses can be scanned without reading any of them. */
.rows { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.rows li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
/* The right-hand figure in a label-and-figure row: it must not shrink, because a
   squashed amount is a wrong amount. `:not(:first-child)` is the whole correction.
   Without it the rule also caught a row with a *single* child, and `flex: 0 0 auto`
   on the only child means "size to content and never shrink" — so a one-child row
   grew to whatever its longest line needed and pushed the page wider than the phone.

   Measured on 29 August 2026 after the account holder sent Eri Ezeume's savings page
   from a phone: viewport 485px, document 640px, and a `.qrow` inside `.rows li`
   reporting 590px wide inside a 411px parent. That is where the clipped
   "Paid — $2367..." and "See what you sent" went. Everything above `.qrow` measured
   correctly, which is why reading the CSS was not finding it.

   `.rows` wraps a single `.qrow` on several screens, so this is not only the savings
   page. */
.rows li > :last-child:not(:first-child) { flex: 0 0 auto; text-align: right; }
/* A row whose only child is the content: fill the row and be allowed to shrink. */
.rows li > :only-child { flex: 1 1 auto; min-width: 0; }
/* An empty queue is good news, not a row. */
.rows li.muted { display: block; padding: 0.15rem 0; border: 0; background: none; }

/* An icon in a row, which until the support front door only existed inside the
   rail. `.side .icon` sized it there, so an <svg class="icon"> anywhere else drew
   at the SVG default of 300x150 -- a bug the template audit cannot see, because the
   class does have a rule, just not one that applies here. */
.rows .icon { width: 1.25rem; height: 1.25rem; flex: 0 0 auto; color: var(--muted); opacity: 0.7; }

/* The paperwork, two abreast when there is room. Below that it stacks, because a
   20rem minimum is about where a name and a status stop fitting on one line. */
.grid2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); gap: 1.25rem; }

/* ---------------------------------------------------------------------------
   The concept's components
   ---------------------------------------------------------------------------
   Ported from the redesign concept's own stylesheet, with its palette translated
   onto the documented brand tokens. Where the concept conflates a meaning with
   its brand colour — it uses one cyan for both "brand" and "good" — the brand
   guide's own semantic wins, so an Active pill is the documented green rather
   than the accent, and a warning is amber ink on cream.

   These are the pieces the other thirteen screens are built from. Anything
   sitting on a flipping surface reads a token; anything on a fixed navy surface
   uses a literal, same rule as the rail, the masthead and the health card.
   --------------------------------------------------------------------------- */

/* The page heading block: title, subtitle, and an action at the far right. */
.page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-bottom: 1.125rem;
}
.page-sub { color: var(--muted); font-size: 0.84375rem; margin-top: 0.375rem; max-width: 41.25rem; line-height: 1.55; }
.crumb {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-bottom: 0.625rem;
  font-size: 0.75rem;
  color: var(--muted);
}
.crumb:hover { color: var(--brand); }
/* A run of cards under a quiet heading, for a screen with two or three parts. */
.section-title {
  margin: 1.75rem 0 0.75rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}
.section-title:first-child { margin-top: 0; }

.grid { display: grid; gap: 1rem; }
/* `start`, not the grid's default stretch. Two cards of unequal content stretched
   to the taller one leaves the shorter with a third of its height empty — the
   member's Billing card was three lines in a box as tall as the health card beside
   it. Cards sizing to their content is what the concept shows. */
.grid-2 { display: grid; gap: 1rem; grid-template-columns: 1fr 1fr; align-items: start; }
/* A grid cell holding several cards stacked, rather than one card per cell.
   The lead workspace needs it: what you do goes down the left, what was said goes
   down the right, and letting four cards flow into a two-column grid put the
   conversation beside a different card depending on whether the application panel
   existed — and left an empty cell when it did. The gap matches `.grid`'s own so a
   column of cards is spaced like the row of them beside it. */
.card-column { display: flex; flex-direction: column; gap: 1rem; min-width: 0; }
/* A row whose left item is the health card. The card is deliberately 26rem — wider
   and it stops reading as a card — so an equal split left 14rem of nothing inside
   the left column and squeezed the prose on the right. */
.grid-card { display: grid; gap: 1.25rem; grid-template-columns: 26rem 1fr; align-items: start; }
@container work (max-width: 47.5rem) { .grid-card { grid-template-columns: 1fr; } }
.grid-3 { display: grid; gap: 1rem; grid-template-columns: repeat(3, 1fr); }
@container work (max-width: 67.5rem) { .grid-3 { grid-template-columns: repeat(2, 1fr); } }
@container work (max-width: 47.5rem) { .grid-2, .grid-3 { grid-template-columns: 1fr; } }

/* The card. `.panel` is the name the templates already use; `.card` is the
   concept's, kept so ported markup reads as it was written. */
.card {
  padding: 1.25rem 1.375rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-solid);
  box-shadow: var(--shadow);
}
.card > h3:first-child, .card > h2:first-child { margin-top: 0; }
/* A card the reader has to act on, rather than one they are reading. One accent border
   and nothing else: the panel is already first on the page, so anything louder competes
   with the page heading it sits under. Used by the member dashboard's "we still need
   these from you" panel, which is the only card in the product with that job. */
.card.attention {
  border-left: 3px solid var(--warn, var(--accent));
  background: var(--surface-solid);
}
/* A card's title with a status beside it. The concept puts the pill on the title's
   line rather than under it, so the state is read with the name and not after it.
   `baseline` and not `center`: the pill is shorter than the heading, and centring it
   against a heading that wraps to two lines floats it into the middle of nowhere. */
.card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 0.625rem;
}
.card-head > h3 { margin: 0; }
.card-head > .pill { flex: 0 0 auto; }

.card-desc { font-size: 0.78125rem; color: var(--muted); line-height: 1.55; margin-bottom: 0.875rem; }
/* A card whose point is one action: the explanation on the left, the button on
   the right, rather than a card whose whole body is a button. */
.action-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.875rem;
}
.action-card .card-desc { margin-bottom: 0; max-width: 52ch; }
.action-card > .button { flex: 0 0 auto; }

/* A status, as a word with a dot beside it. Both the brand guide and the concept
   land on this shape, and for the same reason: a status must never be carried by
   colour alone. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.1875rem 0.625rem 0.1875rem 0.5rem;
  border-radius: var(--radius-pill);
  font-size: 0.71875rem;
  font-weight: 700;
  white-space: nowrap;
}
.pill .dot, .status .dot { width: 6px; height: 6px; border-radius: 50%; flex: 0 0 auto; }
.pill.good { background: var(--success-bg); color: var(--success); }
.pill.good .dot { background: var(--success); }
.pill.warn { background: var(--warn-bg); color: var(--warn); }
.pill.warn .dot { background: var(--amber); }
.pill.risk { background: var(--danger-bg); color: var(--danger); }
.pill.risk .dot { background: var(--danger); animation: pulse-dot 1.6s ease-in-out infinite; }
.pill.info { background: var(--info-bg); color: var(--info); }
.pill.info .dot { background: var(--accent); }
.pill.neutral { background: var(--surface-2); color: var(--muted); }
.pill.neutral .dot { background: var(--muted); }
@keyframes pulse-dot { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

/* A queue row: a coloured square, a title, a line of detail. The workhorse of
   every list on every screen that is not a table. */
.qrow {
  display: flex;
  align-items: flex-start;
  gap: 0.875rem;
  padding: 0.875rem 0.25rem;
  border-bottom: 1px solid var(--line);
}
.qrow:last-child { border-bottom: none; }
.qicon {
  display: grid;
  place-items: center;
  width: 2.125rem;
  height: 2.125rem;
  flex: 0 0 auto;
  margin-top: 1px;
  border-radius: 9px;
}
.qicon svg { width: 1.0625rem; height: 1.0625rem; }
/* Two spellings for each tone. The concept's is good/warn/risk/neutral; the one
   the models already speak — `status_badge` on Membership and Application — is
   success/warning/danger/secondary. Aliasing them here means a screen can tone an
   icon straight from a model property, instead of every template carrying its own
   if-chain to translate between the two. */
.qicon.good, .qicon.success { background: var(--success-bg); color: var(--success); }
.qicon.warn, .qicon.warning { background: var(--warn-bg); color: var(--warn); }
.qicon.risk, .qicon.danger { background: var(--danger-bg); color: var(--danger); }
.qicon.info { background: var(--info-bg); color: var(--info); }
.qicon.neutral, .qicon.secondary { background: var(--surface-2); color: var(--muted); }
.qbody { flex: 1; min-width: 0; }
.qtitle { font-size: 0.84375rem; font-weight: 600; color: var(--ink); margin-bottom: 0.125rem; }
.qtitle a { text-decoration: none; }
.qtitle a:hover { text-decoration: underline; }
.qmeta { font-size: 0.75rem; color: var(--muted); }

/* A label and a figure, in a column of them. */
.stat-block { margin-bottom: 0.25rem; }
.stat-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5625rem 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.8125rem;
}
.stat-row:last-child { border-bottom: none; }
.stat-row .label { color: var(--muted); }
.stat-row .val { font-family: var(--mono); font-weight: 600; font-size: 0.8125rem; font-variant-numeric: tabular-nums; }
.stat-row .val.risk { color: var(--danger); }
.stat-row .val.good { color: var(--success); }

/* A share, drawn. The number is always beside the bar rather than only in it —
   a bar on its own is a shape somebody has to estimate. */
.barlist { display: flex; flex-direction: column; gap: 0.625rem; margin-top: 0.375rem; }
.bar-item .bar-top { display: flex; justify-content: space-between; font-size: 0.78125rem; margin-bottom: 0.3125rem; }
.bar-item .bar-top .val { font-family: var(--mono); color: var(--muted); font-variant-numeric: tabular-nums; }
.bar-track { height: 8px; border-radius: var(--radius-pill); background: var(--surface-2); overflow: hidden; }
.bar-fill { height: 100%; border-radius: var(--radius-pill); background: var(--accent); }
.bar-fill.good { background: var(--success); }
.bar-fill.warn { background: var(--amber); }
.bar-fill.risk { background: var(--danger); }
.bar-fill.info { background: var(--info); }

/* The enrollment funnel, as stages of decreasing width. */
.funnel { display: flex; flex-direction: column; gap: 0.375rem; margin-top: 0.5rem; }
.funnel-step { display: flex; align-items: center; gap: 0.75rem; }
.funnel-label { width: 6.875rem; flex: 0 0 auto; text-align: right; font-size: 0.75rem; color: var(--muted); }
.funnel-bar-wrap { flex: 1; height: 2.125rem; border-radius: 8px; background: var(--surface-2); overflow: hidden; }
.funnel-bar {
  display: flex;
  align-items: center;
  height: 100%;
  padding: 0 0.75rem;
  border-radius: 8px;
  background: linear-gradient(90deg, #1f6e8c, #2e8fb0);
  color: #ffffff;
  font-family: var(--mono);
  font-size: 0.78125rem;
  font-weight: 600;
}
.funnel-bar.risk { background: linear-gradient(90deg, #91190f, #b42318); }
.funnel-bar.info { background: linear-gradient(90deg, #164f72, #3e6fa6); }
/* A stage with nobody in it still needs its label read, so the bar keeps a
   minimum width rather than collapsing to a zero-width strip with a digit
   hanging off it. */
.funnel-bar { min-width: 2.75rem; }
.funnel-pct { width: 5.625rem; flex: 0 0 auto; font-family: var(--mono); font-size: 0.75rem; color: var(--muted); }

/* Help under a field or a card, at the bottom of the scale. */
.field-help { margin: 0.625rem 0 0; font-size: 0.71875rem; color: var(--muted); line-height: 1.5; }
/* The compact version: where people drop out, stage by stage. */
.funnel-mini { display: flex; align-items: stretch; gap: 0.25rem; margin-top: 0.875rem; }
.fm-step {
  flex: 1;
  padding: 0.875rem 0.375rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg);
  text-align: center;
}
.fm-step .fm-drop { font-family: var(--mono); font-size: 0.6875rem; font-weight: 600; color: var(--danger); margin-bottom: 0.25rem; }
.fm-step .fm-name { font-size: 0.71875rem; color: var(--muted); margin-top: 0.375rem; }
.fm-step .fm-thermo { width: 6px; border-radius: 4px; margin: 0 auto; background: var(--line-strong); }

/* One lead, as a row you can act on. */
.lead-card {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1rem 1.125rem;
  margin-bottom: 0.625rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-solid);
}
.lead-avatar {
  display: grid;
  place-items: center;
  width: 2.375rem;
  height: 2.375rem;
  flex: 0 0 auto;
  border-radius: 50%;
  background: linear-gradient(160deg, #0e3a5e, #1f6e8c);
  color: #ffffff;
  font-weight: 700;
  font-size: 0.8125rem;
}
.lead-main { flex: 1; min-width: 0; }
.lead-name-row { display: flex; align-items: center; gap: 0.5625rem; margin-bottom: 0.1875rem; flex-wrap: wrap; }
.lead-name { font-weight: 600; font-size: 0.875rem; }
.lead-contact { font-size: 0.75rem; color: var(--muted); }
.lead-meta { font-size: 0.75rem; color: var(--muted); margin-top: 0.1875rem; }
/* The call form, folded shut. A list of twenty leads should be a list, not twenty
   forms — and `<details>` gets that with no JavaScript. The summary is styled as
   the button it stands in for, with the marker removed so it does not carry a
   triangle as well. */
/* The heading over one row of pre-cleared texts. Four rows of buttons need labels
   or they read as one long wall — and `.actions` carries its own generous margin,
   which between a label and the row it labels is a gap that breaks the pairing. */
/* A numbered list of actions, in the guide and anywhere else that wants one.
 *
 * The name is borrowed from the training manuals' own stylesheet, which is a separate
 * file — so this is a second definition of a look, not a second authority over one
 * document. Deliberately **no `.steps strong` rule**: the manuals carried
 * `.steps strong { display: block }` for a bold lead-in and it reached every bold
 * phrase inside a step, so three shipping documents had sentences broken across
 * lines for a month. If a lead-in ever wants that here, scope it to
 * `> li > strong:first-child` and nothing wider. */
.steps { margin: 0.9rem 0 1.1rem; padding-left: 1.4rem; }
.steps > li { margin: 0 0 0.6rem; }
.steps > li:last-child { margin-bottom: 0; }

/* The handbook, which opens in its own tab and so has no rail.
 *
 * A reading measure rather than the app's full width: 34rem of prose is about
 * seventy characters a line, and the reason this page exists is that somebody
 * reads it rather than scans a table. `main table` still applies, so the price
 * ladder and the who-decides-what tables behave exactly as they do everywhere. */
.guide-page { background: var(--surface-2); }
.guide { max-width: 46rem; margin: 0 auto; padding: 2.5rem 1.5rem 4rem; }
.guide-head { margin-bottom: 2rem; }
.guide-eyebrow {
  margin: 0 0 0.35rem;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.guide-head h1 { margin: 0 0 0.5rem; }
.guide-promise { margin: 0 0 0.75rem; font-size: 1.0625rem; color: var(--muted); }

/* Contents that jump within the page. In a tab with no navigation this is the only
   way to get about, so it is a box rather than a run of links. */
.guide-contents {
  margin: 0 0 2.25rem;
  padding: 1rem 1.25rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface-solid);
}
.guide-contents ol { margin: 0; padding-left: 1.25rem; }
.guide-contents li { margin: 0.2rem 0; }

/* Every section is a question, so each one starts a block a reader can land on from
   the contents list without wondering whether they are in the right place. */
.guide-body > section { margin: 0 0 2.5rem; }
.guide-body > section > h2 {
  padding-bottom: 0.4rem;
  border-bottom: 2px solid var(--brand);
}
.guide-body p.lead { font-size: 1.0625rem; font-weight: 600; }
/* **The guide's tables are prose and must wrap.** `main table { white-space: nowrap }`
 * is right for a report — a wrapped date column is worse than a scrollbar — and wrong
 * for a two-column "what this control is for" table, where the second column is a
 * sentence. Without this the guide's widest tables ran off the right edge, which is
 * the same defect the account holder reported on Control on 3 September 2026, from
 * the same rule, reached through a different element.
 *
 * Scoped to `.guide` rather than extending that rule's exemption list: the list is
 * about *what is inside a cell* on a data table, and this is a different claim —
 * every table on this page is prose. Found by screenshotting the render, not by
 * reading the stylesheet, which is how the Control one was found too. */
/* A callout's heading, which the global `h4` rule gets wrong on this page. That rule
   is `font-size: 0.875rem; margin: 1em 0 0.2em` — sized for a card label, so inside a
   guide callout the heading came out *smaller* than the paragraph beneath it and 0.2em
   from it, and the two read as one blob. Found by screenshotting the render; it was
   wrong in every handbook since the first one shipped, not only the rewritten pages.
   Was scoped to `.guide` on 6 September 2026, on the argument that changing `h4`
   "would reach every screen in the product for the sake of one document". **Widened to
   every callout on 9 September 2026, and the argument is narrower than the one it
   replaces**: this reaches `h4` inside a `.callout` and nothing else, and a callout
   heading smaller than its own body text is wrong wherever it appears. The lead
   workspace has carried two of them since the reply-owed control went in — a screen
   the account holder reads daily and no guide could ever have covered. */
.callout h4 { font-size: 1.0625rem; margin: 0 0 0.5rem; }
.callout > h4:first-child { margin-top: 0; }

.guide table { white-space: normal; }
/* No `td:first-child { nowrap }` here, and it was removed on 6 September 2026 rather
   than narrowed. It had been added to keep a short label ("premium") on one line, and a
   short label fits anyway — so the rule only ever *did* anything when the cell was too
   long for its column, which is precisely when wrapping is the right answer. It was
   caught twice in one day by measuring: two tables past a 420px viewport, then the
   member guide's two-column "your insurance / your membership" table wanting 876px in a
   688px column at desktop width, both of them first columns holding a whole sentence.
   The rewritten guides put prose in the first column far more often than the first
   version did. */
.guide table td, .guide table th { vertical-align: top; }


.guide-foot { margin-top: 3rem; padding-top: 1.25rem; border-top: 1px solid var(--line); }

/* Section 5 of the sales guide is a price table on a phone. Without this the page
   is the one screen in the product somebody reads on a handset in a car park. */
@media (max-width: 34rem) {
  .guide { padding: 1.5rem 1rem 3rem; }
}

.snippet-group { margin: 1rem 0 0.2rem; font-weight: 600; color: var(--ink); }
.snippet-group + .actions { margin-top: 0.35rem; margin-bottom: 0.35rem; }

.lead-action { flex: 0 0 auto; }
.lead-action > summary { list-style: none; cursor: pointer; }
.lead-action > summary::-webkit-details-marker { display: none; }
.lead-action[open] > summary { margin-bottom: 0.75rem; }
.lead-action[open] { flex: 1 1 18rem; }
.lead-action form { margin: 0; }
.lead-action textarea { min-height: 3.5rem; }

/* A family member's own insurance, folded shut behind a real button.
   Same shape as `.lead-action` above and for the same reason: a list of family
   members should be a list, not four open forms. The difference is that this one
   used to be a `class="fine"` summary — small, grey, and worded as a statement —
   and the feature was reported as missing rather than as hidden. A conditional
   control still has to look like a control. */
.own-insurance { flex: 0 0 auto; }
.own-insurance > summary { list-style: none; cursor: pointer; }
.own-insurance > summary::-webkit-details-marker { display: none; }
/* Full width once open, so the form is not squeezed into the right-hand third of
   the row it hangs off. */
.own-insurance[open] { flex: 1 1 100%; }
.own-insurance[open] > summary { margin-bottom: 0.75rem; }
.own-insurance form { margin: 0; }
/* Closed, the generic `details` chrome puts a bordered tinted box around a single
   button, inside a row, inside a card — three nested boxes for one control. Open,
   that same chrome is what groups the form, so it is dropped only while shut. */
.own-insurance:not([open]) {
  border-color: transparent;
  background: none;
  padding: 0;
  margin: 0;
}

/* The thermometer in the mini funnel. Its height is the share lost, which makes
   the tall one findable without reading six percentages — but the percentage is
   printed above it, because a bar alone is a shape somebody has to estimate. */
.fm-thermo.cold { background: var(--accent); }
.fm-thermo.warm { background: var(--amber); }
.fm-thermo.hot { background: var(--danger); }
.fm-step .fm-thermo { min-height: 0.25rem; max-height: 3rem; }
.fm-step .heat { margin-top: 0.5rem; }
/* Already called. Dimmed rather than hidden: it is still a lead, and hiding it is
   how the same person gets rung twice by two reps. */
.lead-card.contacted { background: var(--bg); }

/* How warm a lead is. A word and a dot, not a temperature colour on its own. */
.heat {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.1875rem 0.5625rem;
  border-radius: var(--radius-pill);
  font-size: 0.6875rem;
  font-weight: 700;
}
.heat .dot { width: 6px; height: 6px; border-radius: 50%; }
.heat.cold { background: var(--info-bg); color: var(--info); }
.heat.cold .dot { background: var(--accent); }
.heat.warm { background: var(--warn-bg); color: var(--warn); }
.heat.warm .dot { background: var(--amber); }
.heat.hot { background: var(--danger-bg); color: var(--danger); }
.heat.hot .dot { background: var(--danger); }

/* The pipeline board. Scrolls sideways rather than squashing: seven stages do not
   fit a laptop, and a squashed column is unreadable. */
.board-scroll { display: flex; gap: 0.75rem; overflow-x: auto; padding-bottom: 0.375rem; }
.board-col {
  min-width: 11.875rem;
  padding: 0.875rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--bg);
}
.board-col h4 { font-size: 0.8125rem; font-weight: 700; margin: 0 0 0.125rem; }
.board-col .tag { font-size: 0.65625rem; letter-spacing: 0.03em; text-transform: uppercase; color: var(--muted); }
.board-col .empty { margin-top: 1.5rem; text-align: center; font-size: 1.375rem; color: var(--line-strong); }
/* One person on the board. */
.board-item {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  margin-top: 0.5rem;
  padding: 0.5rem 0.625rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-solid);
  font-size: 0.78125rem;
}
.board-item .mono { color: var(--muted); font-size: 0.71875rem; }
/* The won column. This is where the money is, so the board says so rather than
   leaving somebody to add up the last column themselves. */
.board-col.won { background: var(--success-bg); border-color: color-mix(in oklab, var(--success) 30%, transparent); }
.board-col.won .tag { color: var(--success); }
.board-total {
  margin: 1.25rem 0 0;
  font-family: var(--mono);
  font-size: 0.9375rem;
  font-weight: 700;
  text-align: center;
  color: var(--success);
}

/* A note under a form or a board, at the bottom of the scale. */
.form-note { margin: 0.75rem 0 0; font-size: 0.71875rem; color: var(--muted); line-height: 1.55; max-width: 44rem; }

/* A row that opens. `<details>` rather than a click handler, so it works with no
   JavaScript — the concept used onclick and this product ships none. */
.expand-row { margin-bottom: 0.5rem; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; background: var(--surface-solid); }
.expand-head {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.8125rem 1rem;
  cursor: pointer;
  list-style: none;
}
.expand-head::-webkit-details-marker { display: none; }
.expand-head::after {
  content: "";
  margin-left: auto;
  width: 0.4rem;
  height: 0.4rem;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(-45deg);
  transition: transform 0.15s;
}
.expand-row[open] .expand-head::after { transform: rotate(45deg); }
.expand-name { font-weight: 600; font-size: 0.84375rem; }
.expand-email { font-size: 0.75rem; color: var(--muted); }
.expand-body {
  padding: 0.75rem 1rem 0.9375rem;
  border-top: 1px solid var(--line);
  font-size: 0.78125rem;
  color: var(--muted);
}

/* Nothing here yet, said properly. An empty table with headings reads as a
   failure; this reads as a state. */
.empty-state {
  padding: 3.75rem 2.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-solid);
  box-shadow: var(--shadow);
  text-align: center;
}
.empty-state .icon {
  display: grid;
  place-items: center;
  width: 3.25rem;
  height: 3.25rem;
  margin: 0 auto 1.125rem;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--bg);
  color: var(--muted);
}
.empty-state h3 { margin: 0 0 0.5rem; font-size: 1.125rem; }
.empty-state p { max-width: 25rem; margin: 0 auto; font-size: 0.84375rem; color: var(--muted); line-height: 1.6; }

/* A neutral notice at the top of a screen. Teal-ink on the info wash, which is
   the documented pair. */
.info-banner {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.9375rem 1.125rem;
  margin-bottom: 1.25rem;
  border: 1px solid color-mix(in oklab, var(--accent) 35%, transparent);
  border-radius: 12px;
  background: var(--info-bg);
  color: var(--info);
  font-size: 0.8125rem;
}

/* Table extras the concept uses: right-aligned monospaced figures, and a rep's
   name over their code. */
main td.num, main th.num { font-family: var(--mono); text-align: right; font-variant-numeric: tabular-nums; }
.rep-name { font-weight: 600; }
.rep-code { display: block; font-family: var(--mono); font-size: 0.6875rem; color: var(--muted); }

/* ---------------------------------------------------------------------------
   Sales, CRM and the public calculator
   --------------------------------------------------------------------------- */

/* Columns that scroll sideways rather than squashing. A board with seven stages
   does not fit a phone, and a squashed column is unreadable. */
.pipeline { display: flex; gap: 0.8rem; overflow-x: auto; padding-bottom: 0.6rem; }
.pipeline-column {
  flex: 0 0 13rem;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.75rem 0.85rem;
}
.pipeline-column h3 { margin: 0 0 0.2rem; font-size: 0.95rem; }
.pipeline-column ul { list-style: none; margin: 0.45rem 0 0; padding: 0; }
.pipeline-column li { padding: 0.4rem 0; border-top: 1px solid var(--line); font-size: 0.9rem; }
.pipeline-column li:first-child { border-top: 0; }

/* A link or code to be read aloud or copied. Monospaced, wrapped anywhere,
   because these are long and a horizontal scrollbar hides the end of them. */
.share-link {
  display: block;
  padding: 0.65rem 0.8rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: color-mix(in oklab, var(--bg) 55%, var(--surface-solid));
  color: var(--brand);
  font-size: 0.9rem;
  overflow-wrap: anywhere;
}

.calc-result { margin-top: 1.5rem; }
.quote-capture { margin-top: 1.25rem; }
.quote-capture summary { cursor: pointer; color: var(--brand); font-weight: 500; }

.decision { margin-top: 1.25rem; }

details {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.75rem 1rem;
  margin: 0 0 1rem;
  background: var(--surface-2);
}
details[open] { border-color: var(--line-strong); }
summary { cursor: pointer; }

/* ---------------------------------------------------------------------------
   The demo instance
   --------------------------------------------------------------------------- */

/* Slim, and unmistakably not part of the product. It has to be readable enough
   that nobody files a bug against the wrong build, and quiet enough that it
   does not become the first thing in every screenshot. */
.demo-banner {
  padding: 0.55rem 1.25rem;
  text-align: center;
  font-size: 0.88rem;
  color: var(--ink);
  background: linear-gradient(90deg, var(--violet-glow), var(--brand-glow));
  border-bottom: 1px solid var(--line-strong);
}
.demo-banner strong { color: var(--ink); }
.demo-banner a { color: var(--ink); text-decoration: underline; }
.demo-banner .fine { color: var(--ink-dim); }

.demo-logins table { width: 100%; border-collapse: collapse; margin: 0.85rem 0; }
.demo-logins th, .demo-logins td {
  text-align: left;
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
.demo-logins thead th {
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}

/* ---------------------------------------------------------------------------
   Accessibility
   --------------------------------------------------------------------------- */

/* Keyboard users get a way past the navigation; it stays hidden for everyone
   else until focused. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 0.75rem 1rem;
  background: var(--surface-solid);
  color: var(--ink);
  border: 2px solid var(--brand);
  border-radius: var(--radius-sm);
}
.skip-link:focus { left: 0.5rem; top: 0.5rem; }

/* A visible focus ring on every interactive element. Browsers hide the default
   for mouse users; keyboard users need it back. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--brand);
  outline-offset: 2px;
  border-radius: 3px;
}

main:focus { outline: none; }

/* Available to screen readers, invisible on screen — for labels and status text
   that would be redundant visually. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
  .search-results li:hover, .dependent-list li:hover,
  .button:hover, .location-option:hover { transform: none; }
  .member-card .sheen { display: none; }
}

/* Ask for more contrast and the decoration goes: no translucency, no blur, no
   soft grey. */
@media (prefers-contrast: more) {
  :root {
    --surface: var(--surface-solid);
    --surface-2: var(--surface-solid);
    --muted: var(--ink-dim);
    --line: var(--line-strong);
  }
  body::before { display: none; }
  .panel, .result, .wizard, .hero, .messages li { backdrop-filter: none; }
  .panel::before, .wizard::before, .hero::before { display: none; }
}

/* ---------------------------------------------------------------------------
   The join screen (Isaac, 23 August 2026)

   Split down the middle: what this is on the left, which of the two doors you
   want on the right. The two doors were already the whole content of the page —
   "myself and my family" or "through my employer" — and the redesign is about
   making the choice look like a decision worth a moment rather than two stacked
   panels of prose.

   Built from the project's own tokens rather than the hex values in the brief.
   The brief asked for #063B63 and #00B7D8; the documented brand navy and teal
   are #0e3a5e and #2e8fb0, they are what every other screen uses, and Isaac's
   instruction was to prefer the portal's own rules where the two disagree. Two
   navies a shade apart on adjacent screens is worse than either navy.

   `.join-hero` is a FIXED navy surface in both colour schemes, so it is declared
   in `FIXED_SURFACES` in scripts/audit_templates.py and everything inside it is
   coloured from a literal. A page token would flip underneath it in dark mode
   and put dark text on dark navy.

   The photograph: `.join-figure` is a gradient today, and the slot is deliberate.
   It used to also layer a background-image naming `../img/join-hero.jpg` — a file
   that does not exist — on the reasoning that a browser falls back to the gradient
   silently. Browsers do.
   `collectstatic` does not: production uses manifest storage, which resolves every
   stylesheet reference at collect time and fails the build on one it cannot find.
   That failure is worth keeping, so the reference is gone rather than the check.

   To add the photograph: drop the file in `static/img/`, then add it back as a
   layer here with its own `background-size` and `background-position` entry. Two
   lines, and the build will tell you if the filename is wrong.
   --------------------------------------------------------------------------- */

.join-shell {
  display: grid;
  gap: clamp(1rem, 2.5vw, 1.75rem);
  align-items: stretch;
  margin: 0 auto;
  max-width: 78rem;
}

@media (min-width: 62rem) {
  .join-shell { grid-template-columns: 1.02fr 1fr; }
}

/* The left half. Fixed navy: every colour below is a literal. */
.join-hero {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--radius);
  background: linear-gradient(158deg, #0e3a5e 0%, #0b2f4c 62%, #08263d 100%);
  box-shadow: var(--shadow);
  color: #cfdde9;
}

.join-hero-top { padding: clamp(1.4rem, 3vw, 2.25rem) clamp(1.4rem, 3vw, 2.4rem) 0; }

.join-mark {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0 0 clamp(1.2rem, 3vw, 2rem);
  font-size: 1.0625rem;
  letter-spacing: 0.01em;
  color: #ffffff;
  text-decoration: none;
}
.join-mark img { width: 38px; height: 38px; }
.join-mark strong { color: #7fd0e8; font-weight: 700; }

.join-hero h1 {
  margin: 0;
  padding: 0;
  border: 0;
  max-width: 18ch;
  font-size: clamp(2.1rem, 4.6vw, 3.1rem);
  line-height: 1.08;
  letter-spacing: -0.015em;
  color: #ffffff;
}

.join-lede {
  margin: 1rem 0 0;
  max-width: 26ch;
  font-size: clamp(1.0625rem, 1.7vw, 1.25rem);
  line-height: 1.5;
  color: #cfdde9;
}

.join-rule {
  width: 3.25rem;
  height: 3px;
  margin: 1.35rem 0 1.2rem;
  border-radius: 2px;
  background: #2e8fb0;
}

.join-assure {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin: 0;
  max-width: 30ch;
  font-size: 0.9375rem;
  line-height: 1.45;
  color: #bfe0ee;
}
.join-assure svg { flex: 0 0 auto; width: 20px; height: 20px; color: #7fd0e8; }

/* The image slot. Gradient underneath, photograph on top when there is one. */
.join-figure {
  flex: 1 1 auto;
  min-height: clamp(9rem, 26vh, 15rem);
  margin: clamp(1.4rem, 3vw, 2.1rem) 0 0;
  background-image:
    linear-gradient(180deg, rgba(14, 58, 94, 0) 0%, rgba(8, 38, 61, 0.55) 100%),
    radial-gradient(120% 80% at 70% 18%, rgba(46, 143, 176, 0.34), transparent 62%);
  background-size: cover, cover;
  background-position: center, center;
  background-repeat: no-repeat;
}

.join-benefits {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.15rem 0;
  padding: clamp(1.1rem, 2.4vw, 1.5rem) clamp(1.1rem, 3vw, 2.4rem)
           clamp(1.3rem, 2.6vw, 1.7rem);
  background: rgba(8, 38, 61, 0.55);
  border-top: 1px solid rgba(127, 208, 232, 0.22);
}

@media (min-width: 45rem) {
  .join-benefits { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.join-benefit { padding: 0.35rem 0.7rem 0.35rem 0; }
.join-benefit svg { width: 22px; height: 22px; margin-bottom: 0.45rem; color: #7fd0e8; }
.join-benefit strong {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
  color: #ffffff;
}
.join-benefit span {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.8125rem;
  line-height: 1.35;
  color: #a9c6d8;
}

/* The right half: one white card holding the decision. */
.join-choices {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.join-card {
  padding: clamp(1.5rem, 3vw, 2.4rem);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-solid);
  box-shadow: var(--shadow);
}

.join-card h2 {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: clamp(1.5rem, 2.6vw, 1.875rem);
  text-align: center;
  color: var(--ink);
}
.join-card > .help { margin: 0.5rem 0 1.5rem; text-align: center; }

/* One door. A bordered card that lifts on hover, because the whole card is the
   target and it should say so before you commit a click to it. */
.join-option {
  display: block;
  padding: 1.1rem 1.15rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  text-decoration: none;
  color: inherit;
  transition: transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease;
}
.join-option + .join-option { margin-top: 0.85rem; }
.join-option:hover,
.join-option:focus-visible {
  transform: translateY(-2px);
  border-color: var(--accent);
  box-shadow: var(--shadow);
  background: var(--surface-solid);
}
.join-option strong {
  display: block;
  font-size: 1.0625rem;
  color: var(--ink);
}
.join-option p {
  margin: 0.3rem 0 0.85rem;
  font-size: 0.9375rem;
  line-height: 1.45;
  color: var(--muted);
}
/* The affordance reads as a button and is not one — the whole card is the link,
   so a nested <a> or <button> would be a second target inside the first. */
.join-option .as-button {
  display: inline-block;
  padding: 0.45rem 1.05rem;
  border-radius: var(--radius-pill);
  background: var(--brand);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--brand-ink);
}
.join-option:hover .as-button,
.join-option:focus-visible .as-button { background: var(--accent-ink); }

/* Already a member. Its own band rather than a line of small print, because
   this is the thing the page was missing: the join buttons were prominent and
   the way back in was a link in the corner. */
.join-signin {
  margin: 1.5rem 0 0;
  padding: 1rem 1.15rem;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  background: var(--wash);
  text-align: center;
  font-size: 0.9375rem;
}
.join-signin a { font-weight: 600; color: var(--accent-ink); }

.join-foot {
  margin: 1.5rem 0 0;
  padding-top: 1.1rem;
  border-top: 1px solid var(--line);
  text-align: center;
  font-size: 0.875rem;
  color: var(--muted);
}
.join-foot .lock { display: block; margin-bottom: 0.5rem; color: var(--accent-ink); }
.join-foot strong { display: block; color: var(--ink); }
.join-foot .join-links { margin: 0.65rem 0 0; }
.join-foot .join-links a { color: var(--muted); }
.join-foot .join-links span { padding: 0 0.45rem; color: var(--line-strong); }

/* ---------------------------------------------------------------------------
   The two-step enrolment QR code

   Reported 27 August 2026: it filled the whole content column and was unusable.
   allauth renders it through its `img` element, which ships as a bare
   `<img src="...">` with no dimensions. We override that element — see
   `templates/allauth/elements/img.html` for why that is safe — so this only has
   to size the one image.

   The white plate is not decoration. The data URI is a transparent SVG, so on the
   dark theme the code would be dark-on-dark and a phone camera has nothing to
   lock on to. The padding is the quiet zone the format expects.
   --------------------------------------------------------------------------- */
.totp-qr {
  display: block;
  width: 100%;
  max-width: 14rem;
  height: auto;
  margin: 1.25rem 0;
  padding: 0.75rem;
  border-radius: var(--radius);
  background: #fff;
}

/* The two current commission rates, stated above the progress bars that explain when
   they rise. Larger than body copy because it is the answer to "what do I earn" — the
   question a rep opens this screen with, and which the bars only answered by
   inference. */
.rates-now {
  margin: 0 0 0.35rem;
  font-size: 1.0625rem;
  color: var(--ink);
}
.rates-now strong { color: var(--accent-ink); }

/* One radio and its label on a line, for a small set of mutually exclusive answers.
   Used by the termination period on Price a deal: how long a negotiated price lasts,
   which was never asked before 28 August 2026 and defaulted silently to for ever. */
.choice {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
  font-weight: 400;
}
.choice input[type="radio"] { margin: 0; }

/* ---------------------------------------------------------------------------
   Bulk apply: many per-row inputs, one button. The inputs live inside table
   cells and reference the form by the `form` attribute, so the form itself is
   just this strip — a button and one sentence about what pressing it does.
--------------------------------------------------------------------------- */
.bulk-apply { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin-top: 0.85rem; }
.bulk-apply .fine { margin: 0; max-width: 40ch; }

/* ---------------------------------------------------------------------------
   A settings table that must fit the screen on every device.

   `main table` scrolls sideways when it does not fit, and for a *data* table
   that is right — a wrapped date column is worse than a scrollbar. The team
   table is not data: it is nine columns of controls, and the account holder's
   report on 3 September 2026 was that it "does not fit into that screen...
   make it fit with that boundary of the screen at all times across all
   devices". So under 62rem of container each row becomes a labelled block —
   the column header travels to the cell via `data-th`, nothing scrolls, and
   every control keeps its full width. CSS only; the markup is the same table.
--------------------------------------------------------------------------- */
@container work (max-width: 62rem) {
  main table.stacks { display: block; overflow-x: visible; white-space: normal; }
  main table.stacks thead { display: none; }
  main table.stacks tbody { display: block; }
  main table.stacks tr {
    display: block;
    padding: 0.85rem 0;
    border-bottom: 1px solid var(--line);
  }
  main table.stacks td {
    display: block;
    border: 0;
    padding: 0.2rem 0;
    white-space: normal;
  }
  main table.stacks td[data-th]::before {
    content: attr(data-th);
    display: block;
    font-size: 0.72rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 0.1rem;
  }
}

/* The same stacking, for a guide page, which cannot use the container query above.
   ---------------------------------------------------------------------------------
   A guide renders as `<body class="guide-page"><main class="guide">` with no portal
   shell, so `container-name: work` does not exist on it and `@container work (...)`
   never fires. A media query is the only condition available there.

   **Measured, not guessed.** The public walkthrough's price table wanted 369px inside a
   318px cell at a 390px content width, putting 20 elements 17px past the right edge, on
   the one page a lead is most likely to open on a phone. It was clean at 1280px and at
   500px, which is why nothing caught it: Chromium headless will not render a viewport
   under 500px, so every "420px" figure recorded for this project was really 500px --
   wider than any phone.

   34rem is the threshold because it is this stylesheet's existing narrowest breakpoint
   and covers every phone. It is deliberately not a value between 390 and 500: a
   threshold in that range could not be verified from here, and an unverifiable
   breakpoint is worse than a slightly early one. The cost is that a 500px-wide window
   stacks a table that would have fitted, which is legible rather than broken.

   These two blocks are one idea and must move together. */
@media (max-width: 34rem) {
  main.guide table.stacks { display: block; overflow-x: visible; white-space: normal; }
  main.guide table.stacks thead { display: none; }
  main.guide table.stacks tbody { display: block; }
  main.guide table.stacks tr {
    display: block;
    padding: 0.85rem 0;
    border-bottom: 1px solid var(--line);
  }
  main.guide table.stacks td {
    display: block;
    border: 0;
    padding: 0.2rem 0;
    white-space: normal;
    text-align: left;
  }
  main.guide table.stacks td[data-th]::before {
    content: attr(data-th);
    display: block;
    font-size: 0.72rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 0.1rem;
  }
}

/* A checkbox in front of a name, for the bulk strip on Control. */
.tick-row { display: inline-flex; align-items: center; gap: 0.45rem; cursor: pointer; }
.tick-row input[type="checkbox"] { width: auto; margin: 0; }

/* ---------------------------------------------------------------------------
   Handbook illustrations
   ---------------------------------------------------------------------------
   A miniature of a real screen, drawn inline with the product's *own* classes
   rather than photographed. The account holder asked for the in-portal guide to
   carry pictures like the training PDFs do, and a PNG was the obvious answer and
   the wrong one here, for three reasons:

     * `docs/` is in `.dockerignore`, so the manuals' `shoot.py` output is not in
       the image at all. A screenshot for this page would have to be committed as
       a binary under `static/`, which nothing can check for staleness — and a
       picture of a screen the product no longer has is worse than no picture.
     * Rendered from `.pill`, `.vital`, `.lead-card` and the rail's own rules, an
       illustration restyles when the product restyles. The type scale moved twice
       in this project; a raster would have needed re-shooting both times.
     * It carries nobody's information by construction. There is no live screen to
       photograph that does not have a member's insurance on it.

   `.mock` sets a smaller root size and everything inside is in `em`, so one
   number scales a whole illustration to fit the 46rem prose column.

   The rail is the one thing that needs undoing rather than reusing: `.side` is
   `position: sticky; height: 100dvh` because in the real shell it is a
   full-height column, and inside a figure that makes a 900px void. Overridden
   here and nowhere else. */
.mock {
  font-size: 0.8125rem;
  border: 1px solid var(--line);
  border-radius: 0.5rem;
  overflow: hidden;
  margin: 1rem 0 0.5rem;
  background: var(--bg);
  box-shadow: 0 1px 3px rgba(8, 42, 71, 0.08);
}
/* 14em against the shell's real 15rem: the rail is narrower here only because the
   whole illustration is set at 0.8125rem, so it stays in proportion. Measured, not
   picked — at 10.5em six of the eleven rows wrapped onto two lines, including
   "Two-step sign-in" hyphenated mid-word, which is not what the product does. */
.mock-split { display: grid; grid-template-columns: 14em 1fr; }
.mock .side {
  /* `grid-area: side` is set on `.side` for the real shell, whose grid names that
     area. This grid does not, so the rail was auto-placed into an implicit second
     row and second column: it rendered on the *right*, under a 200px band of
     nothing. Found by screenshotting the first render — the markup has the rail
     first and reads correctly. */
  grid-area: auto;
  position: static;
  height: auto;
  padding: 0.9em 0.55em 1em;
  font-size: 0.9em;
  z-index: auto;
}
.mock .side .brand { margin-bottom: 0.5em; }
.mock .side a { padding: 0.3em 0.5em; }
.mock-work { padding: 0.9em 1em 1.1em; min-width: 0; }
/* A few grey bars standing in for whichever page opened, for the one illustration
   whose subject is the rail rather than a screen. Without it the work column is a
   400px band of white beside a full-height rail — which is the "too much empty space"
   complaint that got the first training manuals sent back, reproduced inside the
   picture meant to answer it. Not a real screen, and it must not look like one. */
.mock-skeleton { display: flex; flex-direction: column; gap: 0.55em; }
.mock-skeleton span { display: block; height: 0.7em; border-radius: 0.35em; background: var(--surface-2); }
.mock-skeleton span.tall { height: 1.6em; width: 45%; background: var(--line); }
.mock-skeleton span.short { width: 62%; }
.mock-skeleton span.mid { width: 84%; }
.mock-work > :first-child { margin-top: 0; }
.mock-work > :last-child { margin-bottom: 0; }
/* The top bar, so a reader can see which buttons live up there rather than in
   the page — that distinction is the one people ask about most. */
.mock-top {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.4em;
  padding: 0.5em 1em;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}
.mock-top .mock-title { margin-right: auto; font-weight: 600; color: var(--muted); }
.mock h1, .mock h2, .mock h3, .mock h4 { font-size: 1.15em; margin: 0 0 0.35em; }
.mock p { font-size: 1em; margin: 0 0 0.5em; }
.mock .pill, .mock .heat { font-size: 0.85em; }
.mock .button { font-size: 0.9em; padding: 0.35em 0.7em; }
.mock .vitals { border-radius: 0.35em; }
.mock .vital { padding: 0.7em 0.9em; }
.mock .vital-value { font-size: 1.5em; }
.mock .card { padding: 0.8em 0.9em; margin: 0 0 0.6em; }
.mock .lead-card { padding: 0.7em 0.8em; margin: 0 0 0.5em; }
.mock textarea, .mock input, .mock select { font-size: 1em; padding: 0.35em 0.5em; }
.mock label { font-size: 0.95em; }
.mock .fine { font-size: 0.85em; }

/* A drawn form field, and a drawn dropdown.
 *
 * Real `<input>` and `<select>` elements inside an illustration are a trap: a reader
 * types into one, nothing happens, and the guide has taught them the control is broken.
 * `.mock details > summary` above solves the same problem for a fold by killing pointer
 * events; a field needs to not be a field at all. These are `<div>`s that look like one.
 *
 * Added because the account holder asked for more illustrations, 8 September 2026, and
 * every screen worth illustrating in this product is a form. Drawn from the real
 * control's own tokens — `--line`, `--surface`, `--muted` — so a restyle carries.
 */
.mock-input,
.mock-select {
  border: 1px solid var(--line);
  border-radius: 0.3em;
  background: var(--surface);
  padding: 0.35em 0.5em;
  font-size: 1em;
  color: var(--text);
  margin: 0 0 0.5em;
}
/* The caret, so a dropdown reads as a dropdown rather than as a filled-in box. That
   distinction is the whole point of drawing one: a reader has to know whether they are
   choosing from a list or typing. */
.mock-select {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5em;
}
.mock-select::after {
  content: "\25be";
  color: var(--muted);
  font-size: 0.9em;
}
/* An empty field is a placeholder rather than a value, and must not read as typed
   text. */
.mock-input:empty::before,
.mock-select:empty::before {
  content: "\00a0";
}
/* The square code on the two-step setup screen.
 *
 * Drawn rather than shown, and that is not a stylistic preference: a real one encodes a
 * real authenticator secret, so a screenshot of that screen is a working credential
 * printed into a guide, and a stand-in image would be the one artefact here that
 * nothing can check for staleness. A checkerboard reads as "square code" to anybody who
 * has seen one and encodes nothing at all.
 */
.mock-qr {
  width: 7em;
  height: 7em;
  margin: 0 0 0.75em;
  border: 1px solid var(--line);
  border-radius: 0.3em;
  background:
    conic-gradient(var(--text) 25%, transparent 0 50%, var(--text) 0 75%, transparent 0)
    0 0 / 1.16em 1.16em;
  opacity: 0.75;
}

/* A `<details>` inside an illustration must not be openable: it is a drawing of a
   control, not the control, and a reader who opens it gets an empty box. */
.mock details > summary { pointer-events: none; }

/* The numbered marker. Sits inline against the thing it labels, and the list
   below repeats the same numbers — prose pointers rather than arrows drawn into
   the picture, which is `shotref.py`'s reasoning: an arrow baked into an image
   goes stale the moment a field moves, a numbered sentence beside it can be
   fixed in one line. */
.mock-tag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.35em;
  height: 1.35em;
  border-radius: 50%;
  background: var(--navy);
  color: #fff;
  font-size: 0.78em;
  font-weight: 700;
  font-style: normal;
  line-height: 1;
  flex: 0 0 auto;
  vertical-align: 0.1em;
}
.mock .side .mock-tag { background: #7ecfe6; color: #082a47; }
.mock-points { list-style: none; margin: 0 0 1.5rem; padding: 0; counter-reset: mockpt; }
.mock-points > li {
  counter-increment: mockpt;
  position: relative;
  padding-left: 2.1rem;
  margin: 0 0 0.5rem;
}
.mock-points > li::before {
  content: counter(mockpt);
  position: absolute;
  left: 0;
  top: 0.05rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--navy);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 700;
}
.mock-caption { font-size: 0.8125rem; color: var(--muted); margin: 0 0 0.9rem; }

/* Under 34rem the two columns are wider than the phone. The rail stacks above the
   work area rather than being dropped, because "where is that in the menu" is the
   question the illustration exists to answer. */
@media (max-width: 34rem) {
  .mock { font-size: 0.75rem; }
  .mock-split { grid-template-columns: 1fr; }
  .mock .side { flex-direction: row; flex-wrap: wrap; gap: 0.4em 0.8em; height: auto; }
}
