/* ===========================================================================
   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; }
.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; }
/* 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); }

/* 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 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; }
/* 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); }

/* 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; }
main table td .fine, main table td.fine, main table td p { 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; }

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

/* 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);
}
.rows li > :last-child { flex: 0 0 auto; text-align: right; }
/* 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 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'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. */
.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; }

/* 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); }
