/*
 * Scoped styles for the Wellhub "State of Work-Life Wellness" experience
 * (src/pages/wellhub, mounted at /wellhub in src/App.tsx).
 *
 * Adapted from the standalone app's src/styles.css. The host loads Tailwind once
 * globally, so every rule here is scoped under .wellhub-root (the wrapper in
 * src/pages/Wellhub.tsx) so the app's design-system tokens and base resets
 * (:root vars like --accent/--ring, body/anchor/heading rules) cannot leak into
 * the other sites or clobber the host's own Tailwind tokens. Same approach as
 * northrock.css. The standalone app loaded its fonts from index.html; pull them
 * in here instead.
 */
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,400..800;1,400..800&family=Sacramento&display=swap");

/* NaN Holo Condensed — the brand's PRIMARY typeface, for titles (guideline deck slide 43;
   Inter is the secondary face, for H2s and body). Self-hosted from the woff2 the brand pack
   ships web-ready. Only the two weights this stylesheet actually asks for are shipped —
   the pack also licenses Medium, but an unused 63KB face is 63KB of nothing.
   `swap` so a slow font never blanks the headline. */
@font-face {
  font-family: "NaN Holo Condensed";
  src: url("/fonts/NaNHoloCondensed-Bold.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "NaN Holo Condensed";
  src: url("/fonts/NaNHoloCondensed-ExtraBold.woff2") format("woff2");
  font-weight: 800; font-style: normal; font-display: swap;
}

/* The analytics consent banner, themed.
 *
 * The ONLY rule in this file deliberately outside .wellhub-root, and it has to be: the
 * SDK appends its banner to document.body, so a variable scoped to the wrapper never
 * reaches it and the banner would render in its built-in default blue — on a magenta
 * report. These five custom properties are the SDK's entire theming surface
 * (vendor/analytics/), so nothing else here can leak: no element in this repo other than
 * that banner reads a --jxp-* name.
 *
 * The accent is --magenta-dark, NOT the brand magenta. The banner's primary button puts
 * off-white text on the accent, and #F2496B gives 3.3:1 there — below the 4.5:1 AA needs
 * for body-sized text. #590931 is 13.1:1 and is the same dark tier the headings use, so
 * the banner stays on-brand and readable. This is the accessible-by-default choice the
 * rest of this stylesheet makes everywhere else.
 */
:root {
  --jxp-bg: #FBF8EC;        /* --offwhite */
  --jxp-fg: #1D1D1F;        /* --black    */
  --jxp-accent: #590931;    /* --magenta-dark, for contrast on the button */
  --jxp-accent-fg: #FBF8EC;
  --jxp-radius: 12px;
}

/* ============================================================================
   The State of Work-Life Wellness — design system
   Inter throughout — display, reading and UI (Wellhub brand type system)
   ========================================================================== */
.wellhub-root {
  /* Wellhub's brand type system is exactly two families, and both are now real:
     NaN Holo Condensed for display (@font-face above) and Inter for reading and UI.
     Inter stays at the end of the display stack as the fallback the page renders in
     while the woff2 loads, or if it fails. */
  --font-display: "NaN Holo Condensed", "Inter", system-ui, -apple-system, sans-serif;
  --font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  /* A signature is the one place the brand's two families cannot serve: NaN Holo and Inter
     have no script face. Used ONLY for an expert's signed name, never for reading copy,
     and always with the same name repeated beneath it in ordinary type. Cursive is the
     fallback so a failed webfont still reads as a signature rather than as body text. */
  --font-signature: "Sacramento", "Snell Roundhand", "Apple Chancery", cursive;

  /* ── The Wellhub palette, verbatim. Four families, and every value below this block
     is one of them or a documented exception. Do not "improve" these. ────────────── */
  --magenta-dark:    #590931;
  --magenta:         #F2496B;   /* Main Magenta */
  --magenta-pink:    #FF809F;
  --magenta-light:   #FFB2C6;
  --magenta-lighter: #FFEBF1;

  --purple-dark:     #1B1340;
  --purple-medium:   #5B4191;
  --purple-main:     #A880FF;   /* Main Purple */
  --purple-light:    #DDCCFF;
  --purple-lighter:  #F0E0FF;

  --green-dark:      #034036;
  --green-medium:    #0C8046;
  --green-main:      #DCFF79;   /* Main Green — a highlight, never a text colour */
  --green-light:     #F2FFCC;

  --black:           #1D1D1F;
  --offwhite-s2:     #ECE0CD;
  --offwhite-s1:     #F6EDDF;
  --offwhite:        #FBF8EC;

  /* Roles. Each family has exactly one member dark enough for small text on the
     off-white — magenta 13.1:1, purple 7.6:1, green 4.7:1 — which is what makes a
     per-theme accent possible at all rather than only a per-theme fill. */
  --bg: var(--offwhite);
  --ink: var(--black);
  --accent: var(--magenta);
  --purple: var(--purple-main);
  --green: var(--green-main);

  --bg-2: var(--offwhite-s1);
  --surface: #ffffff;
  --surface-2: #FDFBF4;   /* between white and S1; the palette has no such step */
  --ink-2: #5C5C60;       /* text greys are not in the palette */
  /* Darkened from #86868B, which measured 3.41:1 on the off-white and 3.12:1 on --bg-2 —
     under the 4.5:1 AA bar for the small text this token exists to colour. 214 elements
     were failing on it: every eyebrow, source line, filter label and stat base. #68686D
     clears 5.21 / 4.78 / 5.54 across --bg, --bg-2 and white, and stays a clear step lighter
     than --ink-2 (#5C5C60) so the three-tier grey scale still reads as three tiers. */
  --ink-3: #68686D;

  /* Brand magenta is 3.3:1 on the off-white, so every role that paints it has to clear a
     3:1 bar rather than 4.5:1 — which is why reading copy is 19px (see .reader p.doc).
     A darkened 6:1 stand-in (#B81C46) was tried for bold and rejected: beside the logo it
     reads as red, which is exactly what the client reported. Brand main everywhere now;
     type size carries the contrast instead of a second, off-brand pink. */
  --bar-track: var(--ink);           /* the unfilled remainder of a bar */
  --accent-figure: var(--magenta);   /* display figures: >=3:1 on the off-white */
  --accent-bold: var(--magenta);     /* bold body: 3.3:1, cleared by 19px bold */
  --accent-deep: var(--magenta-dark);
  --accent-soft: var(--magenta-lighter);
  --accent-pink: var(--magenta-pink);
  --purple-soft: var(--purple-light);
  --purple-deep: var(--purple-medium);

/* Sequential ramp for ordered single-series rows (likert scales, segment splits).
     Positional: the payload carries no colour at all and `encoding_notes` is free prose,
     so the ramp is the viewer's to own. Every step is paired in prepare.mjs with the ink
     measured legible on top of it.

     This replaced the pack's categorical --chart-1..6 order, which had no consumer once
     the payload gained `legend[].role`: roles are a real semantic signal and outrank a
     positional guess, so multi-series colour comes from ROLE_FILL instead. */
  --ramp-1: #FFB2C6;  --on-1: var(--ink);
  --ramp-2: #FC9DB4;  --on-2: var(--ink);
  --ramp-3: #FA88A2;  --on-3: var(--ink);
  --ramp-4: #F7738F;  --on-4: var(--ink);
  --ramp-5: #F55E7D;  --on-5: var(--ink);
  --ramp-6: #F2496B;  --on-6: var(--ink);
  --bar-track: var(--magenta-dark);
  --on-primary: var(--ink);

  --line: var(--offwhite-s2);
  --line-2: #E1D3B8;   /* one step past S2; the palette stops at S2 */
  --ring: rgba(242, 73, 107, 0.18);

  --shadow-sm: 0 1px 2px rgba(29, 29, 31, 0.04), 0 1px 3px rgba(29, 29, 31, 0.05);
  --shadow-md: 0 2px 10px rgba(29, 29, 31, 0.05), 0 16px 40px rgba(29, 29, 31, 0.07);

  --radius: 16px;   /* the pack's card radius */
  --radius-lg: 22px;
  --header-h: 60px;
}

/* ── Chapter themes ───────────────────────────────────────────────────────────
 * A chapter carries one of three themes, and everything inside it follows: prose accents,
 * bold, and every chart, because the charts already resolve their colours through these
 * same tokens. Nothing in prepare.mjs or the chart templates knows a theme exists.
 *
 * Each family contributes four roles:
 *   --accent         brand fill and rules. Magenta is the brand main (#F2496B), not a
 *                    darkened 6:1 stand-in — that looked red against the logo colour.
 *   --accent-figure  display figures (drop cap, chart figures). Same as --accent.
 *   --accent-bold    bold body. Every family passes its own --accent through unchanged:
 *                    reading copy is 19px, so bold runs are WCAG large text and the bar is
 *                    3:1, which brand magenta clears at 3.3:1 with no darkened stand-in.
 *   --accent-deep    headings and sidebar numbers. Each family's dark tier, unchanged.
 *
 * The row ramp is a double gradient, as the source figures are: the chapter's own family
 * running dark to light, then a second family running light to dark beneath it. That second
 * family is purple — except in a purple chapter, where purple cannot follow itself and the
 * tail goes to the neutrals instead.
 * ─────────────────────────────────────────────────────────────────────────── */
.wellhub-root .theme-magenta {
  --accent: var(--magenta);
  --accent-figure: var(--magenta);
  --accent-bold: var(--magenta);
  --accent-deep: var(--magenta-dark);
  --accent-soft: var(--magenta-lighter);
  --accent-pink: var(--magenta-pink);
  --on-primary: var(--ink);
  --ramp-1: #FFB2C6;  --on-1: var(--ink);
  --ramp-2: #FC9DB4;  --on-2: var(--ink);
  --ramp-3: #FA88A2;  --on-3: var(--ink);
  --ramp-4: #F7738F;  --on-4: var(--ink);
  --ramp-5: #F55E7D;  --on-5: var(--ink);
  --ramp-6: #F2496B;  --on-6: var(--ink);
  --bar-track: var(--magenta-dark);
}
.wellhub-root .theme-purple {
  --accent: #6A50A2;
  --accent-figure: #6A50A2;
  --accent-bold: #6A50A2;
  --accent-deep: var(--purple-medium);
  --accent-soft: var(--purple-lighter);
  --accent-pink: var(--purple-light);
  /* Purple cannot sit under purple, so the tail is the neutrals — the "blackish" end. */
  --on-primary: #ffffff;
  --ramp-1: #DDCCFF;  --on-1: var(--ink);
  --ramp-2: #D2BDFF;  --on-2: var(--ink);
  --ramp-3: #C8AEFF;  --on-3: var(--ink);
  --ramp-4: #BD9EFF;  --on-4: var(--ink);
  --ramp-5: #B38FFF;  --on-5: var(--ink);
  --ramp-6: #A880FF;  --on-6: var(--ink);
  --bar-track: var(--purple-dark);
}
.wellhub-root .theme-green {
  --accent: #166D3D;
  --accent-figure: #166D3D;
  --accent-bold: #166D3D;
  --accent-deep: var(--green-dark);
  --accent-soft: var(--green-light);
  --accent-pink: var(--green-main);
  --on-primary: #ffffff;
  --ramp-1: #F2FFCC;  --on-1: var(--ink);
  --ramp-2: #C4E6B1;  --on-2: var(--ink);
  --ramp-3: #96CC96;  --on-3: var(--ink);
  --ramp-4: #68B37C;  --on-4: var(--ink);
  --ramp-5: #3A9961;  --on-5: var(--ink);
  --ramp-6: #0C8046;  --on-6: #ffffff;
  --bar-track: var(--green-dark);
}
/* Bold prose takes --accent-bold, which is now every theme's --accent unchanged. The token
   stays because it is the seam where one family could diverge again; today none does. */
.wellhub-root .reader strong { color: var(--accent-bold); }


/* `hidden` is how the islands drop cards, columns and the show-more row out of the
   page, and the UA stylesheet implements it as `display: none` — which ANY author rule
   setting `display` outranks. `.more-row { display: flex }` did exactly that, so a row
   the script had marked hidden stayed on screen. Order-independent by `!important` so
   a later `display` rule cannot quietly re-break it. */
.wellhub-root [hidden] { display: none !important; }

.wellhub-root, .wellhub-root * { box-sizing: border-box; }
.wellhub-root { margin: 0; }
.wellhub-root {
  font-family: var(--font-sans);
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
.wellhub-root ::selection { background: var(--accent-soft); }
.wellhub-root a { color: var(--accent-deep); text-decoration: none; }
.wellhub-root a:hover { text-decoration: underline; }
.wellhub-root button { font-family: inherit; cursor: pointer; }
.wellhub-root h1, .wellhub-root h2, .wellhub-root h3, .wellhub-root h4 { font-weight: 600; }

/* ── Reading progress bar (Deep Dive) ─────────────────────────────────────── */
.wellhub-root .progress {
  position: fixed; top: 0; left: 0; height: 3px; z-index: 60;
  background: linear-gradient(90deg, var(--accent-pink), var(--accent));
  transition: width 0.08s linear;
}

/* The page shell is a bare <body> with this as its only stylesheet (template mode ships
   no reset), so the UA's 8px body margin was framing every page in a strip of canvas and
   keeping the sticky header off all three screen edges — most obvious on a phone, where
   16px is 4% of the width. Scoped through :has() so the rule still cannot reach a page
   that does not mount the viewer. */
body:has(> .wellhub-root) { margin: 0; }

/* ── Top bar ──────────────────────────────────────────────────────────────── */
.wellhub-root .topbar {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: 18px;
  height: var(--header-h); padding: 0 26px;
  background: rgba(251, 249, 244, 0.82);
  backdrop-filter: saturate(1.4) blur(12px);
  border-bottom: 1px solid var(--line);
}
/* `align-items: center`, not `baseline`: the wordmark is now artwork, and an <svg> has no
   baseline to align to — under `baseline` the browser aligns its bottom edge to the text
   baseline, which drops the lockup below the descriptor it sits next to.
   The gap is the brand clear-space rule, not a taste call: the pack requires at least the
   flywheel's width free on every side, and the flywheel is as wide as the lockup is tall. */
.wellhub-root .brand { display: flex; align-items: center; gap: 24px; min-width: 0; }
/* The wordmark links home. Only the logo, not the report title beside it: the title is
   the name of what you are reading, not a control. */
/* `min-height`, not a taller logo: 24×24 is the WCAG 2.2 AA target minimum (2.5.8) and the
   lockup is 21px tall at phone width. The header row is 34px regardless, so this costs no
   layout — it only makes the hit area match the rule. */
.wellhub-root .brand__home {
  display: flex; align-items: center; min-height: 24px;
  flex: none; border-radius: 6px;
  text-decoration: none; -webkit-tap-highlight-color: transparent;
  transition: opacity 140ms ease;
}
.wellhub-root .brand__home:hover { opacity: 0.72; }
/* Keyboard focus must be visible on a link whose content is artwork — there is no text
   here to underline, so the ring is the only affordance. */
.wellhub-root .brand__home:focus-visible {
  outline: 2px solid var(--accent, #e11d63); outline-offset: 4px; opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .wellhub-root .brand__home { transition: none; }
}
.wellhub-root .brand__logo {
  height: 24px; width: auto; flex: none; display: block;
}
.wellhub-root .brand small {
  font-size: 12.5px; font-weight: 500; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wellhub-root .topbar .spacer { flex: 1; }

/* Print / save as PDF. Sits beside the mode toggle — before it, so the toggle keeps the end
   of the strip — and borrows its shape so the header reads as one control strip rather than
   a toolbar with a stray button in it. The order is the markup's, not this file's. */
/* TWO CLASSES, ONE APPEARANCE, and the split is not cosmetic — it is what makes a stale
   islands.js harmless. `/assets/` is served `immutable` for a year against an UNVERSIONED
   filename, so a reader who has been here before keeps whatever islands.js they first
   downloaded. An older one binds the print job to `.printbtn` by class; had the download
   link kept that class, their cached script would have matched it and every click would
   have downloaded the PDF *and* opened the print dialogue. It did, which is how this was
   found.
   Under its own class the link is invisible to any islands.js ever shipped, because none of
   them has heard of it. The page decides, not the cache — and the filled HTML is not cached
   hard the way the assets are, so a template change reaches everyone at once. */
.wellhub-root .printbtn,
.wellhub-root .pdfbtn {
  display: inline-flex; align-items: center; gap: 7px; flex: none;
  padding: 8px 14px; border-radius: 999px;
  border: 1px solid var(--line-2); background: var(--surface); color: var(--ink);
  font-family: var(--font-sans); font-size: 13px; font-weight: 600; cursor: pointer;
  transition: border-color 0.12s, color 0.12s, background 0.12s;
}
.wellhub-root .printbtn svg,
.wellhub-root .pdfbtn svg { width: 16px; height: 16px; flex: none; display: block; }
.wellhub-root .printbtn:hover,
.wellhub-root .pdfbtn:hover { border-color: var(--accent); color: var(--accent-deep); }
/* The link is an <a>, so it also has to refuse the global anchor underline on hover. */
.wellhub-root .pdfbtn, .wellhub-root .pdfbtn:hover { text-decoration: none; }
.wellhub-root .printbtn:focus-visible,
.wellhub-root .pdfbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.wellhub-root .printbtn[disabled] { opacity: 0.6; cursor: progress; }

/* The "preparing for print" dialog. Appended to <body> by islands.js, so it is deliberately
   NOT scoped under .wellhub-root like everything else in this file. It covers the report
   while ~80 signed asset URLs are warmed; without it the reader gets a frozen button for
   half a minute and no reason why. Removed before window.print() fires, and hidden in
   print anyway so it can never reach paper if a browser prints while it is still up. */
.printprep {
  position: fixed; inset: 0; z-index: 9999;
  display: flex; align-items: center; justify-content: center;
  background: rgba(29, 29, 31, 0.55);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
.printprep__box {
  width: min(380px, calc(100vw - 32px));
  padding: 24px;
  border-radius: 14px;
  background: #fff;
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.28);
  text-align: center;
  font-family: inherit;
}
.printprep__title { margin: 0 0 6px; font-size: 16px; font-weight: 650; color: #1d1d1f; }
.printprep__note { margin: 0 0 16px; font-size: 13px; line-height: 1.45; color: #6b6b70; }
.printprep__track { height: 6px; border-radius: 999px; background: #ececef; overflow: hidden; }
/* Starts at 0 and is driven from JS; the transition keeps 80 discrete steps from strobing. */
.printprep__bar { width: 0; height: 100%; border-radius: 999px; background: var(--accent, #e11d63); transition: width 160ms linear; }
.printprep__count { margin: 10px 0 0; font-size: 12px; color: #6b6b70; font-variant-numeric: tabular-nums; }
.printprep__cancel {
  margin-top: 16px; padding: 7px 16px;
  border: 1px solid #d7d7db; border-radius: 999px;
  background: #fff; color: #1d1d1f;
  font: inherit; font-size: 13px; cursor: pointer;
}
.printprep__cancel:hover { border-color: var(--accent, #e11d63); color: var(--accent-deep, #a3154a); }
.printprep__cancel:focus-visible { outline: 2px solid var(--accent, #e11d63); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) { .printprep__bar { transition: none; } }
@media (max-width: 640px) {
  .wellhub-root .printbtn span,
  .wellhub-root .pdfbtn span { display: none; }
}

/* Segmented mode toggle */
.wellhub-root .toggle {
  display: inline-flex; gap: 2px; padding: 3px;
  background: var(--bg-2); border: 1px solid var(--line-2); border-radius: 999px;
}
.wellhub-root .toggle button {
  border: 0; background: transparent; color: var(--ink-2);
  font-weight: 600; font-size: 13.5px; padding: 7px 18px; border-radius: 999px;
  white-space: nowrap;
  transition: color 0.15s, background 0.15s, box-shadow 0.15s;
}
.wellhub-root .toggle button:hover { color: var(--ink); }
.wellhub-root .toggle button.active {
  background: var(--surface); color: var(--ink);
  box-shadow: var(--shadow-sm); font-weight: 700;
}

/* ── Layout shell ─────────────────────────────────────────────────────────── */
.wellhub-root .app { display: flex; flex-direction: column; min-height: 100vh; }
.wellhub-root .body { display: flex; flex: 1; min-height: 0; }

.wellhub-root .sidebar {
  width: 270px; flex: none; padding: 26px 16px 60px;
  border-right: 1px solid var(--line);
  position: sticky; top: var(--header-h); align-self: flex-start;
  height: calc(100vh - var(--header-h)); overflow: auto;
}
.wellhub-root .sidebar .eyebrow {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--ink-3); margin: 0 10px 12px;
}
/* The `hidden` attribute must actually hide. Its only force is a UA rule, and ANY author
   `display` beats that — `.navlink` below sets `display: block`, so a hidden nav button
   stayed visible while the hidden <section> beside it disappeared, which reads as `hidden`
   working. Asserted here once, for every element in this viewer. */
.wellhub-root [hidden] { display: none !important; }

.wellhub-root .navlink {
  position: relative; display: block; width: 100%; text-align: left;
  border: 0; background: transparent; color: var(--ink-2);
  padding: 8px 12px; border-radius: 10px; font-size: 14px; font-weight: 500;
  line-height: 1.35;
}
.wellhub-root .navlink:hover { background: var(--bg-2); color: var(--ink); }
.wellhub-root .navlink.active { background: var(--accent-soft); color: var(--accent-deep); font-weight: 700; }
.wellhub-root .navlink.active::before {
  content: ""; position: absolute; left: 2px; top: 8px; bottom: 8px; width: 3px;
  border-radius: 3px; background: var(--accent);
}
.wellhub-root .navlink.sub { padding-left: 26px; font-size: 13px; }
.wellhub-root .navlink .num { color: var(--accent-deep); font-weight: 700; margin-right: 4px; }

.wellhub-root .main { flex: 1; min-width: 0; padding: 36px 48px 0; display: flex; flex-direction: column; }

/* Password gate (protected experiences) */
.wellhub-root .pwgate {
  max-width: 420px; margin: 96px auto; padding: 36px 32px 32px; text-align: center;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
  display: flex; flex-direction: column; align-items: center; gap: 10px;
}
.wellhub-root .pwgate__lock { font-size: 30px; line-height: 1; margin-bottom: 4px; }
.wellhub-root .pwgate h2 { margin: 0; font-family: var(--font-display); font-size: 22px; font-weight: 700; letter-spacing: -0.006em; }
.wellhub-root .pwgate p { margin: 0 0 8px; color: var(--ink-2); font-size: 14px; }
.wellhub-root .pwgate input {
  width: 100%; padding: 11px 14px; font-size: 15px; font-family: inherit;
  border: 1px solid var(--line-2); border-radius: 12px; background: var(--bg);
  color: var(--ink); transition: border-color 0.12s, box-shadow 0.12s;
}
.wellhub-root .pwgate input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--ring); }
.wellhub-root .pwgate input[aria-invalid="true"] { border-color: var(--accent-deep); }
.wellhub-root .pwgate__err { width: 100%; color: var(--accent-deep); font-size: 13px; text-align: left; }
.wellhub-root .pwgate button {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  width: 100%; margin-top: 4px; padding: 11px 14px; font-size: 15px; font-weight: 600;
  color: var(--on-primary); background: var(--accent); border: 0; border-radius: 12px;
  transition: background 0.12s, opacity 0.12s;
}
.wellhub-root .pwgate button:hover:not(:disabled) { background: var(--accent-deep); }
.wellhub-root .pwgate button:disabled { opacity: 0.5; cursor: not-allowed; }
.wellhub-root .pwgate__spin {
  width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid color-mix(in srgb, var(--on-primary) 45%, transparent);
  border-top-color: var(--on-primary);
  animation: wellhub-spin 0.7s linear infinite;
}

/* Chapter-menu toggle (in the top bar) + foldable sidebar */
.wellhub-root .navtoggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; margin-right: 6px; flex: none;
  border: 1px solid var(--line-2); border-radius: 10px;
  background: var(--surface); color: var(--ink-2); font-size: 16px; line-height: 1;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.wellhub-root .navtoggle:hover { background: var(--bg-2); color: var(--ink); border-color: var(--ink-3); }
.wellhub-root .navtoggle[aria-pressed="true"] { color: var(--accent-deep); border-color: var(--accent-soft); background: var(--accent-soft); }

/* Folded: hide the sidebar at any width; the main column reflows to fill. */
.wellhub-root .body.nav-closed .sidebar { display: none; }

/* Backdrop is only used by the narrow-screen overlay drawer (see media query). */
.wellhub-root .nav-backdrop { display: none; }

/* ── Overview: hero ───────────────────────────────────────────────────────── */
.wellhub-root .wrap { max-width: 1080px; margin: 0 auto; }

.wellhub-root .hero {
  position: relative; isolation: isolate; overflow: hidden;
  border: 1px solid var(--line); border-radius: 28px;
  background:
    radial-gradient(130% 130% at 100% -10%, rgba(255, 122, 166, 0.20), transparent 46%),
    radial-gradient(120% 130% at -10% 115%, rgba(106, 77, 143, 0.15), transparent 50%),
    linear-gradient(180deg, var(--surface-2), var(--surface));
  --hero-pad-x: clamp(28px, 5vw, 64px);
  padding: clamp(40px, 5vw, 72px) var(--hero-pad-x);
  margin-bottom: 44px;
  box-shadow: 0 1px 2px rgba(28, 22, 32, 0.04), 0 34px 64px -34px rgba(106, 77, 143, 0.28);
}
/* Gradient hairline hugging the top edge. */
.wellhub-root .hero::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px; z-index: 2;
  background: linear-gradient(90deg, var(--accent), var(--accent-pink) 55%, var(--purple));
}
/* Soft brand glow for depth (clipped by the card's rounded corners). */
.wellhub-root .hero::after {
  content: ""; position: absolute; right: -140px; top: -150px; z-index: 0;
  width: 380px; height: 380px; border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 122, 166, 0.18), transparent 70%);
  pointer-events: none;
}
.wellhub-root .hero > * { position: relative; z-index: 1; }
/* The flywheel, sitting in the space the copy deliberately leaves at the right (h1 is
   capped at 19ch, the lede at 52ch). Declared AFTER `.hero > *` on purpose: that rule is
   `position: relative` at equal specificity, so only source order lets this be absolute.
   No opacity, no filter — the pack forbids effects on the mark, so it earns its place by
   size and position instead. */
.wellhub-root .hero__mark {
  position: absolute; z-index: 1; pointer-events: none;
  top: clamp(32px, 4vw, 52px); right: var(--hero-pad-x);
  width: 120px; height: auto;
  /* Off by default. An absolutely positioned mark does not push copy out of its way, and
     the h1 is width-capped in `ch` — so as the column narrows the headline grows INTO the
     mark and overlaps it. Measured: clean at 1400px, overlapping by 65px at 1200px. It is
     therefore shown only where the hero can afford to reserve room for it, below. */
  display: none;
}
/* Wide enough to give the mark its own column: the hero's right padding grows by the mark
   plus a clear space of its own width again (the pack's rule), so the copy stops short of
   it instead of running under it. Reserving the space is what makes the guarantee hold at
   every width above the breakpoint, rather than only at the one width it was eyeballed at. */
@media (min-width: 1100px) {
  .wellhub-root .hero { padding-right: calc(var(--hero-pad-x) + 120px + 120px); }
  .wellhub-root .hero__mark { display: block; }
}

.wellhub-root .hero .eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--accent-deep); margin-bottom: 22px;
}
.wellhub-root .hero .eyebrow::before { content: "✽"; font-size: 14px; line-height: 1; color: var(--accent-pink); }
.wellhub-root .hero h1 {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(38px, 5.4vw, 62px); line-height: 1.0; letter-spacing: -0.0105em;
  margin: 0 0 16px; max-width: 19ch; color: var(--ink);
}
.wellhub-root .hero .lede {
  font-family: var(--font-sans); font-size: clamp(16px, 1.5vw, 18.5px); line-height: 1.55;
  color: var(--ink-2); max-width: 52ch; margin: 0;
}

/* ── The Data page opener ─────────────────────────────────────────────────────
 * The same card as the report hero, dialled down. This page is one part of the report
 * rather than its front door, so the type steps back and the space it saves goes to the
 * contents list — the opener's actual job is to say what is on the page.
 * ─────────────────────────────────────────────────────────────────────────── */
.wellhub-root .hero--page {
  padding: clamp(30px, 3.4vw, 46px) var(--hero-pad-x);
  margin-bottom: 40px;
}
.wellhub-root .hero--page h1 {
  font-size: clamp(30px, 3.4vw, 42px); line-height: 1.06; max-width: 22ch;
  margin-bottom: 12px;
}
.wellhub-root .hero--page .eyebrow { margin-bottom: 16px; }
.wellhub-root .hero--page .lede { max-width: 60ch; }

/* What is on this page, in the order you meet it. A numbered list because the order is
   real — headlines, then everything behind them, then the charts, then the markets, then
   how it was gathered — and `list-style: none` with the counter drawn by hand so the
   number can be set in the display face like every other figure on the site. */
.wellhub-root .pagemap {
  list-style: none; counter-reset: pagemap; margin: clamp(24px, 3vw, 34px) 0 0; padding: 0;
  display: grid; gap: 2px;
}
.wellhub-root .pagemap__item {
  counter-increment: pagemap;
  display: grid; grid-template-columns: 28px minmax(0, 22ch) minmax(0, 1fr);
  align-items: baseline; gap: 4px 14px;
  padding: 11px 0; border-top: 1px solid var(--line);
}
.wellhub-root .pagemap__item:last-child { border-bottom: 1px solid var(--line); }
.wellhub-root .pagemap__item::before {
  content: counter(pagemap); font-family: var(--font-display); font-weight: 800;
  font-size: 13px; color: var(--accent); font-variant-numeric: tabular-nums;
}
/* Padding out to the 24px minimum, with the same amount taken back as negative margin so
   the baseline grid of the row is untouched: the hit area grows, the layout does not. */
.wellhub-root .pagemap__link {
  font-family: var(--font-sans); font-weight: 700; font-size: 15px;
  color: var(--ink); text-decoration: none;
  display: inline-block; padding-block: 3px; margin-block: -3px;
}
.wellhub-root .pagemap__link:hover { color: var(--accent-deep); text-decoration: underline; }
.wellhub-root .pagemap__link:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px;
}
.wellhub-root .pagemap__blurb { font-size: 13.5px; line-height: 1.5; color: var(--ink-2); }

/* One column below the width where the title column and the blurb would each be a few
   words wide. The number keeps its own column so the list still reads as a sequence. */
@media (max-width: 720px) {
  .wellhub-root .pagemap__item { grid-template-columns: 24px minmax(0, 1fr); }
  .wellhub-root .pagemap__blurb { grid-column: 2; }
}

/* "By the numbers" strip: one wide descriptive stat + three headline figures,
   all on one row on desktop (a 12-col grid: 6 + 2 + 2 + 2). */
.wellhub-root .hero .meta {
  margin-top: clamp(28px, 4vw, 40px);
  /* Proportional, not a 12-track grid. The three figure cards were `span 2` of twelve,
     which at this hero's width is about 96px — narrower than the words in them, so
     "SURVEY QUESTIONS" and "FINDINGS TRACKED" spilled across their own card borders and
     into the next. The wide descriptive card takes twice a figure card and no more. */
  display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 14px;
}
.wellhub-root .hero .meta .stat {
  display: flex; flex-direction: column; justify-content: center; gap: 7px;
  padding: 18px 20px; border-radius: 16px;
  background: rgba(255, 255, 255, 0.58); border: 1px solid var(--line);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  transition: transform 0.16s ease, box-shadow 0.16s ease, border-color 0.16s ease;
}
.wellhub-root .hero .meta .stat:hover {
  transform: translateY(-2px); border-color: var(--accent-pink);
  box-shadow: 0 14px 30px -16px rgba(106, 77, 143, 0.4);
}

.wellhub-root .hero .meta .stat b {
  font-family: var(--font-display); font-weight: 800; font-size: 34px;
  letter-spacing: -0.009em; color: var(--ink); line-height: 1.02;
}
.wellhub-root .hero .meta .stat:first-child b { font-size: clamp(21px, 2.5vw, 28px); }
.wellhub-root .hero .meta .stat span {
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ink-3);
}
@media (max-width: 760px) {
  .wellhub-root .hero .meta { grid-template-columns: repeat(3, 1fr); }
  .wellhub-root .hero .meta .stat:first-child { grid-column: 1 / -1; }
}

/* ── Sections ─────────────────────────────────────────────────────────────── */
.wellhub-root .section { margin: 56px 0; scroll-margin-top: calc(var(--header-h) + 24px); }
.wellhub-root .section-head { margin-bottom: 22px; }
.wellhub-root .section-head h2 {
  font-family: var(--font-display); font-weight: 800;
  font-size: 30px; letter-spacing: -0.009em; margin: 0;
}
.wellhub-root .section-head .sub { color: var(--ink-2); font-size: 14.5px; margin: 6px 0 0; }
.wellhub-root .eyebrow-line {
  display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--accent-deep); margin-bottom: 8px;
}

/* ── Filter controls ──────────────────────────────────────────────────────── */
.wellhub-root .filters { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.wellhub-root .search {
  flex: 1; max-width: 320px; display: flex; align-items: center; gap: 8px;
  background: var(--surface); border: 1px solid var(--line-2); border-radius: 999px;
  padding: 9px 16px;
}
/* 16px is not a taste call: Safari on iOS zooms the whole page in when a focused field is
   under 16px, and with no `maximum-scale` to stop it (there should not be one) the reader
   is left zoomed after typing. `min-height` takes the field itself — the target, not the
   pill around it — from 18px to the 24px minimum. */
.wellhub-root .search input {
  border: 0; background: transparent; outline: none;
  font-size: 16px; min-height: 24px; width: 100%; color: var(--ink);
}
.wellhub-root .search input::placeholder { color: var(--ink-3); }
.wellhub-root .count { margin-left: auto; color: var(--ink-2); font-size: 13px; font-weight: 600; white-space: nowrap; }

.wellhub-root .tagfilters { display: flex; flex-direction: column; gap: 10px; margin-bottom: 26px; }
.wellhub-root .tagrow { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; }
.wellhub-root .tagrow .lab {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--ink-3); width: 88px; flex: none; white-space: nowrap;
}
.wellhub-root .pill {
  border: 1px solid var(--line-2); background: var(--surface); color: var(--ink-2);
  border-radius: 999px; padding: 6px 13px; font-size: 12.5px; font-weight: 600;
  transition: all 0.12s;
}
.wellhub-root .pill:hover { border-color: var(--accent-pink); color: var(--accent-deep); }
.wellhub-root .pill.on { background: var(--ink); color: #fff; border-color: var(--ink); }

/* One hue per tag cluster — a hard "don't" in the brand pack, and the stat cards were
   breaking it: theme in grey, segment in pink, source in blue, all on the same card.
   Nothing is lost by unifying them, because the colour was never carrying the meaning:
   each chip already SAYS what it is ("burnout", "All employees", "external"), so the
   `.pink` and `.ext` class names went with the rules rather than lingering as no-ops.
   Nothing in the islands or the view model referenced them. */
.wellhub-root .chip {
  display: inline-block; font-size: 11px; font-weight: 700; padding: 3px 9px;
  border-radius: 999px; background: var(--bg-2); color: var(--ink-2);
}

/* ── Grids & cards ────────────────────────────────────────────────────────── */
.wellhub-root .grid { display: grid; gap: 18px; align-items: start; }
.wellhub-root .grid.cols3 { grid-template-columns: repeat(3, 1fr); }
.wellhub-root .grid.cols2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 1000px) { .wellhub-root .grid.cols3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 760px) { .wellhub-root .grid.cols3, .wellhub-root .grid.cols2 { grid-template-columns: 1fr; } }

/* Masonry (CSS columns) for cards with very uneven heights, e.g. charts with
   2 vs 12 bars — packs them tightly instead of stretching to the row height. */
/* Charts are the exception to the two-up masonry: see the chart-card block below. */
.wellhub-root .masonry { column-count: 2; column-gap: 18px; }
.wellhub-root .masonry > * { break-inside: avoid; margin: 0 0 18px; display: block; }
@media (max-width: 760px) { .wellhub-root .masonry { column-count: 1; } }

.wellhub-root .card-base, .wellhub-root .statcard, .wellhub-root .chartcard, .wellhub-root .voice, .wellhub-root .play {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
/* Charts are not cards. Every source figure sits directly on the off-white, and a white
   panel under a chart reads as a second surface competing with the page — it also fought
   the brand background the rest of the site now uses. The hairline between consecutive
   charts does the separating instead. */
.wellhub-root .chartcard {
  background: transparent; border: 0; box-shadow: none; border-radius: 0;
}
.wellhub-root .masonry .chartcard + .chartcard,
.wellhub-root .masonry > .chartcard ~ .chartcard { border-top: 1px solid var(--line); }

.wellhub-root .statcard { padding: 22px; transition: transform 0.14s, box-shadow 0.14s, border-color 0.14s; }
.wellhub-root .statcard:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--line-2); }
.wellhub-root .statcard .val {
  font-family: var(--font-display); font-weight: 800; font-size: 42px;
  letter-spacing: -0.0105em; color: var(--accent); line-height: 0.95;
}
.wellhub-root .statcard .val.muted { color: var(--ink); font-size: 26px; }
.wellhub-root .statcard .stmt { margin: 12px 0 14px; font-size: 14.5px; line-height: 1.45; color: var(--ink); }
.wellhub-root .statcard .base { font-size: 12px; color: var(--ink-2); font-style: italic; margin-bottom: 12px; }
.wellhub-root .statcard .tags { display: flex; gap: 6px; flex-wrap: wrap; }

/* Cards of one height per row. `.grid` is `align-items: start`, so each card takes only the
   height of its own text and a row ends up with ragged bottoms — which reads as a layout
   fault rather than as density. Opt-in class, now on the headline rows AND the explorer:
   the worry that stretching 87 cards would leave tall gaps did not survive looking at it,
   because a row is only ever as tall as its own tallest card, not as the page's.

   Stretching alone is not enough: it makes the BOXES equal and leaves the chips floating
   wherever each card's text happens to end. The card becomes a column and the chips are
   pushed to the bottom, so the rows of a card line up with its neighbours' — figure,
   statement, then chips on a shared baseline. */
.wellhub-root .grid--stretch { align-items: stretch; }
.wellhub-root .grid--stretch .statcard { display: flex; flex-direction: column; }
.wellhub-root .grid--stretch .statcard .tags { margin-top: auto; }

.wellhub-root .more-row { display: flex; justify-content: center; margin-top: 26px; }
.wellhub-root .btn-ghost {
  border: 1px solid var(--line-2); background: var(--surface); color: var(--ink);
  font-weight: 600; font-size: 13.5px; padding: 10px 22px; border-radius: 999px;
  transition: border-color 0.12s, color 0.12s;
}
.wellhub-root .btn-ghost:hover { border-color: var(--accent); color: var(--accent-deep); }

/* ── Chart card ───────────────────────────────────────────────────────────────
 * Seven forms share one shell. Fill colours and the ink on top of them arrive as inline
 * styles from prepare.mjs -- the payload carries no colour, so the viewer assigns it, and
 * it has to be per-element because a positional ramp holds both #B81E45 and #CBB2FF.
 * ─────────────────────────────────────────────────────────────────────────── */
.wellhub-root .chartcard { padding: 22px 24px; }
.wellhub-root .chartcard__head {
  display: flex; align-items: flex-start; gap: 16px; margin: 0 0 16px;
}
.wellhub-root .chartcard__heading { flex: 1; min-width: 0; }
.wellhub-root .chartcard h3 {
  font-family: var(--font-display); font-weight: 800; font-size: 19px;
  letter-spacing: -0.006em; line-height: 1.12; margin: 0; color: var(--ink);
  text-transform: uppercase;
}
.wellhub-root .chartcard__sub {
  margin: 8px 0 0; font-size: 12.5px; line-height: 1.45;
  color: var(--ink-2); font-style: italic;
}
/* The callout badge: one figure, one label, on magenta. White on magenta is the pack's
   own pairing. Never wraps under the title -- it is the headline number. */
.wellhub-root .chartcard__callout {
  flex: none; max-width: 140px; text-align: center;
  background: var(--accent); color: var(--on-primary);
  border-radius: 14px; padding: 10px 14px;
}
.wellhub-root .chartcard__callout b {
  display: block; font-family: var(--font-display); font-weight: 800;
  font-size: 26px; line-height: 1; letter-spacing: -0.006em;
}
.wellhub-root .chartcard__callout span {
  display: block; margin-top: 4px; font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; line-height: 1.25;
}
.wellhub-root .chartcard__legend {
  display: flex; flex-wrap: wrap; gap: 8px 18px; margin: 0 0 16px;
}
.wellhub-root .clegend {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12px; font-weight: 600; color: var(--ink-2);
}
.wellhub-root .clegend i { width: 11px; height: 11px; border-radius: 50%; flex: none; }
.wellhub-root .chartcard .insight {
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line);
  font-size: 13px; line-height: 1.5; color: var(--ink-2);
}
.wellhub-root .chartcard__source {
  margin-top: 10px; font-size: 11.5px; color: var(--ink-3); line-height: 1.4;
}

/* Charts render one per row rather than two-up. Partly to match the source figures, which
   are all full-width, and partly because curve quality is a function of size: at 450px wide
   a 30px bar's rounded cap is described by ~15 pixels and steps visibly; at full width with
   a 40px bar the same cap gets roughly twice as many, and the worst step falls from 13.3%
   of the bar's height to 10.0%. Revert by deleting this rule if density matters more. */
.wellhub-root .masonry[data-list="charts"] { column-count: 1; }

/* Air between one chart and the next. At the masonry's shared 18px the hairline sat almost
   against the chart below it, so a long scroll of full-width charts read as one continuous
   band and it took effort to tell where a chart's own labels stopped and the next chart's
   title began.
   Split evenly ACROSS the rule rather than piled below it: the gap belongs to both charts,
   and a line 44px under one chart but 18px over the next belongs to the second and reads as
   its overline. Applies only to this list — the two-up masonry elsewhere is unchanged. */
.wellhub-root .masonry[data-list="charts"] { --chart-gap: clamp(30px, 3.4vw, 48px); }
.wellhub-root .masonry[data-list="charts"] > * { margin-bottom: var(--chart-gap); }
.wellhub-root .masonry[data-list="charts"] > *:last-child { margin-bottom: 0; }
.wellhub-root .masonry[data-list="charts"] > .chartcard ~ .chartcard { padding-top: var(--chart-gap); }

/* Form 1 — single-series rows on a full-width dark track. The row is one line: the track
   holds the fill, then the label, then any tag. Nothing sits above the bar, which is what
   makes a six-row chart compact rather than twelve lines tall. */
.wellhub-root .cbar { margin: 0 0 8px; }
.wellhub-root .cbar__track {
  /* min-height, not height: a row whose label needs two lines grows instead of cutting it.
     The pill radius is 999px, so a taller track is still a pill. */
  background: var(--bar-track); border-radius: 999px; min-height: 40px;
  position: relative; display: flex; align-items: center; gap: 0;
}
.wellhub-root .cbar__fill {
  /* `align-self: stretch`, NOT `height: 100%`. The track is min-height rather than height
     so a wrapped label can grow it — and a percentage height resolves against the parent's
     HEIGHT, which is now auto, so `height: 100%` silently became content height and the
     fill shrank to a thin bar floating inside the track. Stretch does not care whether the
     parent's height is definite. */
  align-self: stretch; border-radius: 999px; min-width: 44px; flex: none;
  /* One pixel proud of the track, so the fill's cap is the only curve drawn at that edge —
     two coincident anti-aliased caps left the track's darker one showing through. */
  margin-left: -1px;
  display: flex; align-items: center; justify-content: flex-start; gap: 10px;
  padding: 2px 12px 2px 2px; position: relative; z-index: 2;
  font-size: 12.5px; font-weight: 700;
  transition: width 0.5s cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* The label on the remainder. Light ink, because the remainder is the theme's darkest.
   WRAPS RATHER THAN TRUNCATES. Several of these labels are whole survey statements — "I use
   AI tools regularly and actively help colleagues…" needed 514px of a 413px row and was
   being ellipsised, losing the half of the question that says what was asked. Three lines is
   a ceiling for pathological input, not a target: the longest label here takes two. */
.wellhub-root .cbar__label {
  flex: 1 1 auto; min-width: 0; padding: 9px 14px; position: relative; z-index: 2;
  font-size: 13px; font-weight: 700; color: var(--offwhite); line-height: 1.32;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden; overflow-wrap: anywhere;
}
/* The label lives on the track's REMAINDER, so its column is whatever the fill leaves —
   which on a phone is nothing. Measured with the bars at their real widths: 10 of 47
   statements lost their ending at 320px, 4 at 390px, 2 at 480px, clean from 560px. Simply
   lifting the clamp is not the fix; it makes the label wrap inside a 28px column and turns
   one row 190px tall. So below 560px the label takes a line of its own inside the pill,
   full width, and the clamp goes back to being what it was written as — a ceiling for
   pathological input, never reached. Rows cost ~26px each for it (40px → 66px median),
   which is the price of the sentence being readable at all.
   `.cbar__track` is already `min-height` and light ink on the dark pill, so neither the
   growth nor the contrast is new. */
@media (max-width: 560px) {
  .wellhub-root .cbar__track { flex-wrap: wrap; }
  /* `order` keeps the tag on the bar's line rather than letting it wrap to a third one,
     where it read as a stray word under the sentence instead of as the row's note. Flex
     fills lines in order, so the tag has to come BEFORE the full-width label to share
     line one with the fill. */
  .wellhub-root .cbar__tag { order: 1; margin-left: auto; }
  .wellhub-root .cbar__label { order: 2; flex: 1 0 100%; padding: 2px 14px 9px; }
}
.wellhub-root .cbar__tag {
  flex: none; padding-right: 16px; position: relative; z-index: 2;
  font-size: 10px; font-weight: 800; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--offwhite); opacity: 0.75;
}
/* Where the label is inside the fill, the tag has no dark remainder to sit on at the left,
   so it keeps the far right of the track. */
.wellhub-root .cbars--inside .cbar__tag { margin-left: auto; }

/* The 0-100 scale above the bars, and the dotted quarter lines over them. Drawn only when
   the bars are actually scaled against 100 — see `hasAxis`. */
.wellhub-root .caxis {
  display: flex; justify-content: space-between; margin: 0 0 10px;
  font-size: 11px; font-weight: 700; color: var(--ink-3); letter-spacing: 0.04em;
}
.wellhub-root .cbar__grid {
  position: absolute; inset: 0; display: flex; pointer-events: none; z-index: 3;
}
.wellhub-root .cbar__grid i {
  flex: 1; border-right: 1px dashed rgba(255, 255, 255, 0.45);
}
.wellhub-root .cbar__inlabel {
  font-size: 13px; font-weight: 700; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; min-width: 0;
}
/* Value in a circle at the left of the fill — readable on any ramp step because the
   disc is the off-white and the figure is ink, not the fill's own `on` colour. */
.wellhub-root .cbar__val {
  flex: none; width: 34px; height: 34px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--offwhite); color: var(--ink);
  font-size: 11px; font-weight: 800; letter-spacing: -0.02em;
}

/* Form 9 — vertical columns. */
.wellhub-root .ccols {
  display: flex; align-items: flex-end; justify-content: center;
  gap: clamp(16px, 5%, 44px); height: 240px; padding: 8px 0 0;
}
.wellhub-root .ccol { flex: 1; max-width: 110px; display: flex; flex-direction: column; height: 100%; }
/* Sits just above its own bar's top edge, wherever that is. `bottom: 100%` measures from
   the bar, so the distance is the same on a 38% column and a 95% one. */
.wellhub-root .ccol__val {
  position: absolute; bottom: 100%; left: 0; right: 0; margin-bottom: 6px;
  font-family: var(--font-display); font-weight: 800; font-size: 22px;
  text-align: center; color: var(--accent-figure); line-height: 1.1;
}
/* Padding, not margin: a percentage height resolves against the CONTENT box, so reserving
   the label's room here keeps a full-height column inside the chart instead of pushing its
   number out of the top. */
.wellhub-root .ccol__plot {
  flex: 1; display: flex; align-items: flex-end;
  box-sizing: border-box; padding-top: 32px;
}
.wellhub-root .ccol__bar { position: relative; width: 100%; border-radius: 14px 14px 6px 6px; }
.wellhub-root .ccol__label {
  margin-top: 10px; text-align: center; font-size: 13px; font-weight: 700; color: var(--ink);
}

/* Forms 4/5 — stat cards, and the card half of the ribbon form. */
.wellhub-root .cstats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; align-items: stretch; }
.wellhub-root .cstats--ribbon { margin-top: 16px; }
.wellhub-root .cstat {
  background: var(--bg-2); border-radius: var(--radius); padding: 18px 16px; text-align: center;
  /* A column with the bar pushed to the foot: captions run to different lengths, and with
     the bar in normal flow each one sat at a different height across the row. */
  display: flex; flex-direction: column;
}
.wellhub-root .cstats--ribbon .cstat { text-align: left; }
/* Fixed soft tint, not the card's ramp colour: the icon art is magenta and would vanish
   on the ramp's own deep magenta. */
.wellhub-root .cstat__icon {
  width: 54px; height: 54px; border-radius: 50%; margin: 0 auto 12px;
  background-color: var(--accent-soft);
  background-repeat: no-repeat; background-position: center; background-size: 28px 28px;
}
.wellhub-root .cstat__icon--on { background-image: var(--ico-magenta); }
.wellhub-root .theme-magenta .cstat__icon--on { background-image: var(--ico-magenta); }
.wellhub-root .theme-purple .cstat__icon--on { background-image: var(--ico-purple); }
.wellhub-root .theme-green .cstat__icon--on { background-image: var(--ico-green); }
.wellhub-root .cstat__label {
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink-2); margin: 0 0 8px;
}
.wellhub-root .cstat__pill {
  display: inline-block; border-radius: 999px; padding: 4px 12px; margin: 0 0 10px;
  font-size: 11.5px; font-weight: 800;
}
.wellhub-root .cstat__row { display: flex; align-items: baseline; gap: 8px; }
/* Deliberately NOT the card's fill: a big figure in --purple-soft on cream is ~1.5:1.
   The colour coding lives in the icon and the bar, where it is safe. */
.wellhub-root .cstat__val {
  font-family: var(--font-display); font-weight: 800; font-size: 34px;
  line-height: 1; letter-spacing: -0.006em; color: var(--accent-figure);
}
.wellhub-root .cstat__n { font-size: 12px; color: var(--ink-3); font-weight: 600; }
.wellhub-root .cstat__note {
  margin: 6px 0 8px; font-size: 12.5px; line-height: 1.45; color: var(--ink-2);
}
.wellhub-root .cstat__track {
  margin-top: auto; height: 7px; border-radius: 999px; background: var(--surface); overflow: hidden;
}
.wellhub-root .cstat__fill { height: 100%; border-radius: 0 999px 999px 0; }

/* A one-point stat_group is a single coloured box — icon, figure, copy — not a lone
   progress card sitting on the beige field the multi-card grid uses. */
.wellhub-root .cstats--solo { grid-template-columns: 1fr; max-width: 420px; }
.wellhub-root .cstats--solo .cstat {
  background: var(--accent); color: var(--on-primary); text-align: left; padding: 22px 24px;
}
.wellhub-root .cstats--solo .cstat__icon {
  margin: 0 0 14px;
  background-color: color-mix(in srgb, var(--on-primary) 22%, transparent);
}
.wellhub-root .cstats--solo .cstat__label {
  /* Full strength, not 80%. The softened mix resolved to #48262E on brand magenta — 3.73:1
     for 10.5px bold, under the bar. The whole ink measures 4.76:1 and the label is small
     enough that the softening was never doing much. */
  color: var(--on-primary);
}
.wellhub-root .cstats--solo .cstat__val { color: var(--on-primary); }
.wellhub-root .cstats--solo .cstat__note {
  color: color-mix(in srgb, var(--on-primary) 90%, transparent); margin: 8px 0 0;
}

/* Form 3 — the 100% ribbon above its cards. */
.wellhub-root .cribbon {
  display: flex; height: 46px; border-radius: 999px; overflow: hidden;
}
.wellhub-root .cribbon__seg {
  display: flex; align-items: center; justify-content: center;
  font-size: 13.5px; font-weight: 800; min-width: 0;
}

/* Form 7 — a 100% stack per category. */
.wellhub-root .cstack { margin: 0 0 14px; }
.wellhub-root .cstack__label {
  font-size: 13px; font-weight: 700; color: var(--ink); margin: 0 0 6px;
}
.wellhub-root .cstack__bar { display: flex; height: 34px; border-radius: 999px; overflow: hidden; }
.wellhub-root .cstack__seg {
  display: flex; align-items: center; justify-content: center;
  font-size: 12.5px; font-weight: 700; min-width: 0; overflow: hidden;
}

/* Form 12 — `butterfly_bar`: two groups, one measure, growing out from a centre column.
   The centre is a fixed track rather than a third flexible column: the label decides how
   wide it is, and a label-sized centre would drift from row to row, taking the axis with
   it. Fixed, the two axes are the same two vertical lines down the whole chart, which is
   the only thing that lets a reader compare rows at a glance. */
.wellhub-root .cbfly__row {
  display: flex; align-items: center; gap: 10px; margin: 0 0 10px;
}
.wellhub-root .cbfly__row:last-child { margin-bottom: 0; }
.wellhub-root .cbfly__label {
  flex: none; width: 190px; text-align: center;
  font-size: 12.5px; font-weight: 700; color: var(--ink); line-height: 1.3;
}
.wellhub-root .cbfly__side { display: flex; align-items: center; min-width: 0; }
/* Each side grows towards the centre, so the bars meet the label rather than the margins. */
.wellhub-root .cbfly__side--l { justify-content: flex-end; }
.wellhub-root .cbfly__side--r { justify-content: flex-start; }
.wellhub-root .cbfly__bar {
  height: 30px; border-radius: 999px; flex: none; box-sizing: border-box;
  display: flex; align-items: center; gap: 8px;
  font-size: 12.5px; font-weight: 800; letter-spacing: -0.02em;
}
/* The wheel takes the far end and the figure the centre end, so the two never compete for
   the middle of the bar — mirrored, because "far" is the left on one side and the right on
   the other. */
.wellhub-root .cbfly__side--l .cbfly__bar { padding: 0 12px 0 10px; justify-content: space-between; }
.wellhub-root .cbfly__side--r .cbfly__bar { padding: 0 10px 0 12px; justify-content: space-between; }
.wellhub-root .cbfly__side--l .cbfly__bar .cbfly__val { margin-left: auto; }
.wellhub-root .cbfly__side--r .cbfly__bar .cbfly__val { margin-right: auto; }
.wellhub-root .cbfly__val { white-space: nowrap; }
/* The fallback for a bar too short to hold its figure: just beyond the bar's end, in the
   page's ink rather than the fill's, and never inside the centre column. */
.wellhub-root .cbfly__val--out {
  flex: none; color: var(--ink); font-size: 12.5px; font-weight: 800; letter-spacing: -0.02em;
}
.wellhub-root .cbfly__side--l .cbfly__val--out { margin-right: 8px; }
.wellhub-root .cbfly__side--r .cbfly__val--out { margin-left: 8px; }
/* The centre column is what gives on a narrow screen — the bars are the chart. */
@media (max-width: 760px) {
  .wellhub-root .cbfly__label { width: 120px; font-size: 11.5px; }
  .wellhub-root .cbfly__row { gap: 6px; }
}

/* Off the screen, not out of the page: the `stat_rows` heading is the chart's only name,
   and this site is built to be read by crawlers and screen readers as well as by eye. The
   1px-clip pattern rather than `display: none` or `visibility: hidden`, which take an
   element out of the accessibility tree along with the view. */
/* Off the screen, still in the accessibility tree. The 1px-clip pattern, NOT `display: none`
   or `visibility: hidden` — those take the element out of the tree along with the view, which
   for the charts' data tables would delete the very thing they exist to provide. */
/* Off-screen until focused, then a real, visible control in the top-left. Not
   `display: none`, which would take it out of the tab order and defeat the point.
   Above the sticky topbar's z-index so it cannot appear behind it. */
.wellhub-root .skiplink {
  position: absolute; left: 8px; top: -60px; z-index: 100;
  padding: 10px 18px; border-radius: 999px;
  background: var(--surface); color: var(--ink); border: 1px solid var(--accent);
  font-family: var(--font-sans); font-size: 13.5px; font-weight: 600; text-decoration: none;
  transition: top 0.12s;
}
.wellhub-root .skiplink:focus { top: 8px; }
/* The skip target must not draw a focus ring — it takes focus only to move the caret, and
   a box around the whole page reads as a fault. Focus still lands there for the next Tab. */
.wellhub-root .main:focus { outline: none; }

.wellhub-root .visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

.wellhub-root .chartcard__head--offscreen {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* Form 11 — `stat_rows`: a ranked stack. One band per row, no gaps, so the stack reads as
   a single object whose weight drains away down the list; the corners are rounded on the
   stack, not on each band, for the same reason. The band colour and its ink both come from
   prepare.mjs, which walks the theme's own scale from darkest to palest — so this form is
   magenta in a magenta chapter and green in a green one without knowing a theme exists. */
.wellhub-root .crows { border-radius: var(--radius); overflow: hidden; }
.wellhub-root .crow {
  display: grid; grid-template-columns: 46px auto minmax(0, 1fr);
  align-items: center; gap: 14px; padding: 15px 18px;
}
/* The circle is the off-white throughout, not a tint of the band: the icon art is drawn in
   the brand colours and needs a light ground to read on, and a tint dark enough to sit on
   the top band would swallow it. `--offwhite` is that ground on every band. */
.wellhub-root .crow__icon {
  width: 46px; height: 46px; border-radius: 50%; background-color: var(--offwhite);
  background-repeat: no-repeat; background-position: center; background-size: 26px 26px;
  background-image: var(--ico-magenta);
}
.wellhub-root .theme-purple .crow__icon { background-image: var(--ico-purple); }
.wellhub-root .theme-green .crow__icon { background-image: var(--ico-green); }
/* A row the payload sent no icon for keeps the circle's space rather than shifting its
   figure left out of line with the rows above and below it. */
.wellhub-root .crow__icon--bare { background-image: none; opacity: 0.35; }
.wellhub-root .crow__val {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(26px, 3.4vw, 34px); line-height: 1; letter-spacing: -0.01em;
}
.wellhub-root .crow__note { font-size: 13px; line-height: 1.4; }
/* Weight, never a second colour — see the template. */
.wellhub-root .crow__note b { font-weight: 800; }
/* Beside the prose the stack has 46% of a 70ch column — about 325px — and three columns to
   fit into it. The circle and the figure give up what they can afford so the sentence, the
   only part that cannot be read at a glance, keeps the width it needs. */
.wellhub-root .docchart--aside .crow {
  grid-template-columns: 38px auto minmax(0, 1fr); gap: 11px; padding: 13px 14px;
}
.wellhub-root .docchart--aside .crow__icon {
  width: 38px; height: 38px; background-size: 22px 22px;
}
.wellhub-root .docchart--aside .crow__val { font-size: 26px; }
.wellhub-root .docchart--aside .crow__note { font-size: 12.5px; line-height: 1.35; }

/* The Wellhub-effect grouped chart keeps the light track it always had. Every other
   grouped chart became a bar row — same dark track as the rest of the report — but these
   are the brand's own comparison: the wheel is stamped on the fill, and on a dark track
   the mark and the "with" bar stop being the thing the eye lands on. Scoped to the charts
   that carry the wheel and nothing else, which is `breakdown_dimension: with_wellhub`.
   The rules below are the pre-bar-row ones, restored unchanged. */
.wellhub-root .cgroup__row { margin: 0 0 14px; }
.wellhub-root .cgroup__row:last-child { margin-bottom: 0; }
.wellhub-root .cgroup__track {
  display: flex; align-items: center; background: var(--bg-2);
  border-radius: 999px; height: 26px; overflow: hidden;
}
.wellhub-root .cgroup__fill {
  flex: none; height: 100%; border-radius: 0 999px 999px 0;
  display: flex; align-items: center; padding-left: 8px; box-sizing: border-box;
  /* The wheel stays put at the left and the value is pushed to the right edge by its own
     `margin-left: auto`, so the two never fight over the middle. */
  min-width: 0;
}
.wellhub-root .cgroup__fill--wheel {
  display: flex; align-items: center; box-sizing: border-box;
}
/* Inside the fill, at its far end. The colour is inherited from the fill's own `color`,
   which prepare.mjs pairs with the fill as the measured-legible ink for it — so the value
   is readable on brand magenta and on the palest tint alike, without a second choice here. */
.wellhub-root .cgroup__inval {
  margin-left: auto; padding-right: 10px;
  font-size: 12.5px; font-weight: 800; letter-spacing: -0.02em; line-height: 1;
  white-space: nowrap;
}
/* The fallback, for a bar too short to hold its own number: on the track just past the
   fill, in the page's ink rather than the fill's. */
.wellhub-root .cgroup__val {
  padding-left: 10px; flex: none;
  font-size: 12.5px; font-weight: 800; letter-spacing: -0.02em;
  line-height: 1; color: var(--ink);
}

/* Forms 8/10 — grouped comparison. The ROWS are bar rows: `chart-grouped.html` renders
   them through `.cbar`'s own classes, so the two forms share one set of rules and cannot
   drift apart. What is left here is the only thing a group adds — the category heading
   above its rows, and the space between one group and the next.
   The track, fill, in-value and fallback-value rules that used to live here went with the
   light-track layout they described. */
.wellhub-root .cgroup { margin: 0 0 22px; }
.wellhub-root .cgroup:last-child { margin-bottom: 0; }
.wellhub-root .cgroup__label {
  font-size: 13px; font-weight: 700; color: var(--ink); margin: 0 0 10px; line-height: 1.35;
}
.wellhub-root .cdivrow__bar--wheel {
  display: flex; align-items: center; box-sizing: border-box;
}
/* The wheel has to clear the pill's cap. Flush against it, the 999px radius cut the mark:
   an 18px wheel centred in a 26px bar reaches 9px from the middle, and at that height the
   curve is still 3.62px inside the bar's edge — so the wheel's outer corner sat under it.
   10px is that clearance with room to spare, and reads as deliberate spacing rather than a
   near miss. `box-sizing: border-box` above means the padding costs the bar no length, so
   the value it draws is unchanged. */
.wellhub-root .cdivrow__side--l .cdivrow__bar--wheel { padding-left: 10px; }
.wellhub-root .cdivrow__side--r .cdivrow__bar--wheel { padding-right: 10px; justify-content: flex-end; }
.wellhub-root .cwheel {
  width: 18px; height: 18px; flex: none; display: block; pointer-events: none;
}
/* Chart entrance.
 *
 * The final geometry is the DEFAULT — width: var(--w) and so on. Without JavaScript, or
 * with reduced motion, the charts are simply drawn complete. That ordering matters: if the
 * collapsed state were the default, a failed island would leave every bar at zero and the
 * page would render blank while returning 200, which is the failure this repo keeps
 * relearning.
 *
 * islands.js adds `chart-anim` to the root only when it is actually going to drive the
 * reveal. Only then is anything held back, and only until the card is marked `is-in`.
 * `is-in` is never removed, so a chart animates once and then stays put on later scrolls.
 */
.wellhub-root .cbar__fill,
.wellhub-root .cstat__fill,
.wellhub-root .cgroup__fill,
.wellhub-root .cbfly__bar,
.wellhub-root .cdivrow__bar,
.wellhub-root .cribbon__seg,
.wellhub-root .cstack__seg { width: var(--w); }
.wellhub-root .ccol__bar { height: var(--h); }
.wellhub-root .cpie__svg circle,
.wellhub-root .cdonut__svg circle { stroke-dasharray: var(--dash) var(--gap); }

.wellhub-root.chart-anim .chartcard :is(.cbar__fill, .cstat__fill,
  .cdivrow__bar, .cribbon__seg, .cstack__seg, .ccol__bar, .cpie__svg circle,
  .cdonut__svg circle) {
  /* Staggered off the element's own index so a chart resolves in reading order rather
     than every bar moving at once. Capped so a twelve-row chart does not crawl. */
  transition: width 0.75s cubic-bezier(0.22, 0.7, 0.2, 1),
              height 0.75s cubic-bezier(0.22, 0.7, 0.2, 1),
              stroke-dasharray 0.9s cubic-bezier(0.22, 0.7, 0.2, 1);
  transition-delay: calc(min(var(--i, 0) * 70ms, 560ms));
}
.wellhub-root.chart-anim .chartcard:not(.is-in) :is(.cbar__fill, .cstat__fill,
  .cgroup__fill, .cbfly__bar, .cdivrow__bar, .cribbon__seg, .cstack__seg) { width: 0; min-width: 0; }
.wellhub-root.chart-anim .chartcard:not(.is-in) .ccol__bar { height: 0; }
.wellhub-root.chart-anim .chartcard:not(.is-in) :is(.cpie__svg, .cdonut__svg) circle {
  stroke-dasharray: 0 100;
}
/* The value sits inside the bar, so it is faded rather than squashed by the collapse. */
.wellhub-root.chart-anim .chartcard .cbar__fill > span,
.wellhub-root.chart-anim .chartcard .cdonut__centre { transition: opacity 0.4s ease 0.35s; }
.wellhub-root.chart-anim .chartcard:not(.is-in) .cbar__fill > span,
.wellhub-root.chart-anim .chartcard:not(.is-in) .cdonut__centre { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  /* Belt and braces: the island already declines to add `chart-anim`, but if the class
     ever arrives another way, nothing here moves and nothing is held back. */
  .wellhub-root.chart-anim .chartcard :is(.cbar__fill, .cstat__fill,
    .cdivrow__bar, .cribbon__seg, .cstack__seg, .ccol__bar, .cpie__svg circle,
    .cdonut__svg circle) { transition: none; }
  .wellhub-root.chart-anim .chartcard:not(.is-in) :is(.cbar__fill, .cstat__fill,
    .cgroup__fill, .cbfly__bar, .cdivrow__bar, .cribbon__seg, .cstack__seg) { width: var(--w); min-width: 44px; }
  .wellhub-root.chart-anim .chartcard:not(.is-in) .ccol__bar { height: var(--h); }
  .wellhub-root.chart-anim .chartcard:not(.is-in) :is(.cpie__svg, .cdonut__svg) circle {
    stroke-dasharray: var(--dash) var(--gap);
  }
  .wellhub-root.chart-anim .chartcard:not(.is-in) .cbar__fill > span,
  .wellhub-root.chart-anim .chartcard:not(.is-in) .cdonut__centre { opacity: 1; }
}

/* Pie — the circle beside its key. The key is not decoration: each slice carries an `n`
   and a sentence of real copy, which is why they are listed rather than crammed onto arcs
   at angles nobody can read. */
.wellhub-root .cpie {
  display: grid; grid-template-columns: minmax(200px, 300px) 1fr;
  gap: clamp(20px, 4%, 40px); align-items: center;
}
.wellhub-root .cpie__svg { width: 100%; height: auto; display: block; }
.wellhub-root .cpie__key { list-style: none; margin: 0; padding: 0; }
.wellhub-root .cpiekey {
  display: grid; grid-template-columns: auto 1fr auto; gap: 4px 10px;
  align-items: baseline; padding: 10px 0; border-top: 1px solid var(--line);
}
.wellhub-root .cpiekey:first-child { border-top: 0; padding-top: 0; }
.wellhub-root .cpiekey__dot {
  width: 12px; height: 12px; border-radius: 50%; align-self: center;
}
.wellhub-root .cpiekey__name { font-size: 13.5px; font-weight: 700; color: var(--ink); }
.wellhub-root .cpiekey__val {
  font-family: var(--font-display); font-weight: 800; font-size: 19px;
  letter-spacing: -0.006em; color: var(--accent-figure);
}
.wellhub-root .cpiekey__n {
  grid-column: 2 / -1; font-size: 11.5px; color: var(--ink-3); font-weight: 600;
}
.wellhub-root .cpiekey__note {
  grid-column: 2 / -1; margin: 2px 0 0; font-size: 12.5px; line-height: 1.45; color: var(--ink-2);
}

/* Grouped donut — one ring per category, sharing the legend above them.
 *
 * This form is laid out as the source figures lay it out, and it is the only one that is:
 * title in a tinted pill, key centred beneath it, then the dimension the rings vary along,
 * then the rings. The other nine forms read as a left-aligned title over a plot, and a pill
 * on all of them would restyle twenty-seven charts to match one — so every rule here is
 * scoped to `.chartcard--donuts` and nothing else moves.
 *
 * Colour is entirely the theme's: the pill takes --accent-soft, the slices their series'
 * role fill. A magenta chapter reproduces the customer's figure exactly; purple and green
 * chapters get the same layout in their own family.
 */
.wellhub-root .chartcard--donuts .chartcard__head { display: block; margin-bottom: 14px; }
.wellhub-root .chartcard--donuts h3 {
  /* max-width in ch so the pill hugs a short title instead of ruling the full column, and
     the reading measure holds on a long one. */
  max-width: 54ch; margin: 0 auto; text-align: center;
  background: var(--accent-soft); border-radius: 999px; padding: 15px 30px;
  font-size: 17.5px; line-height: 1.3;
}
/* A callout badge is rare on this form, but if one arrives it centres under the pill rather
   than sitting beside a title that is no longer left-aligned. */
.wellhub-root .chartcard--donuts .chartcard__callout { margin: 14px auto 0; }
.wellhub-root .chartcard--donuts .chartcard__legend {
  justify-content: center; gap: 10px 30px; margin-bottom: 18px;
}
.wellhub-root .chartcard--donuts .clegend { gap: 10px; font-size: 13px; color: var(--ink); }
/* Rounded squares, not dots: at 22px the swatch is a sample of the fill rather than a
   marker, which is what a two-series key of long labels needs. */
.wellhub-root .chartcard--donuts .clegend i { width: 22px; height: 22px; border-radius: 7px; }
/* What the rings are a share OF, named once above them.
   It is the SUBTITLE, moved — so it keeps the subtitle's own type, italic and quiet, and is
   held to a reading measure. It was set at 600 weight for one round, on the assumption that
   this field carries a short axis label like "Update frequency". In the live payload it
   carries a full sentence, and at 600 weight two centred lines of it outweighed the rings
   they were introducing. */
.wellhub-root .cdonuts__caption {
  max-width: 62ch; margin: 0 auto 16px; text-align: center;
  font-size: 12.5px; line-height: 1.45; font-style: italic; color: var(--ink-2);
}
/* The rings want width more than the gutters do: the type inside the hole is a fraction of
   the ring, so a narrow ring is unreadable type, while the rings are told apart by their own
   names and need very little air between them. 200px is the floor at which the qualifier
   line is still legible — below it the grid drops to one column rather than shrinking. */
.wellhub-root .cdonuts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: clamp(10px, 2%, 22px); align-items: start;
  /* Out into the card's side padding. That padding is a text gutter, and none of this is
     text — it is three circles. Reclaiming it is 5% more width for every ring, and because
     everything inside a ring is sized against the ring, 5% more width is 5% larger type. */
  margin-left: -16px; margin-right: -16px;
}
.wellhub-root .cdonut { margin: 0; text-align: center; }
/* `overflow: visible` is load-bearing. An <svg> in HTML clips to its viewBox by default, and
   the slice figures are drawn just outside the ring, near the edge of that box — so a figure
   wider than prepare.mjs budgeted for does not wrap, shrink or warn: it loses its last
   character, on one ring out of three, and reads as a different number. `value_text` is free
   text from the payload, so no budget can be a guarantee. Visible overflow turns the failure
   from a wrong figure into a few pixels of spill into a gutter that has room for it. */
.wellhub-root .cdonut__svg {
  /* 240px, and the cap is what keeps the type legible rather than what keeps the ring
     small. Everything inside the ring is sized in viewBox units, so it scales with the
     rendered width: at 330px a phone ring drew a 17px figure while the desktop column drew
     the same figure at 12px. Capping the box holds the whole form inside one narrow band of
     type sizes instead, which is the point of setting them against the ring at all. */
  width: 100%; max-width: 230px; height: auto; display: block; margin: 0 auto;
  overflow: visible;
}
.wellhub-root .chartcard__legend + .cdonuts { margin-top: 4px; }
/* EVERY SIZE AND POSITION IN THE RING COMES FROM prepare.mjs, as an inline font-size — the
   type sizes and the viewBox are derived from each other there (see LABEL_SIZE), and a
   font-size set here would win over the attribute and quietly break the fit. The stylesheet
   owns colour and weight; that is the whole contract. */
.wellhub-root .cdonut__centre { font-family: var(--font-sans); fill: var(--ink); letter-spacing: 0; }
.wellhub-root .cdonut__name { font-weight: 700; }
/* The qualifier is subordinate to the name it sits under, and says so in WEIGHT alone. It
   was grey for one round and that was wrong twice over: it is set small already, and it
   carries the only definition of what "Frequently" means. */
.wellhub-root .cdonut__note { font-weight: 400; }
/* Slice figures sit outside their own arc, in ink rather than in the accent: on a two-tone
   ring an accent-coloured figure claims the accent-coloured slice, and half of them belong
   to the other one. */
.wellhub-root .cdonut__slicelabel {
  font-family: var(--font-sans); font-weight: 700; fill: var(--ink); letter-spacing: 0;
}
.wellhub-root .cdonut__edge { stroke: var(--line-2); stroke-width: 0.3; }
/* The ring's edges are not slices and must not be swept up by the reveal above, which sets
   `stroke-dasharray: 0 100` on every circle in the SVG until the card scrolls in — on a
   hairline that means it is missing and then pops in, which reads as a rendering fault. */
.wellhub-root .cdonut__svg circle.cdonut__edge,
.wellhub-root.chart-anim .chartcard .cdonut__svg circle.cdonut__edge,
.wellhub-root.chart-anim .chartcard:not(.is-in) .cdonut__svg circle.cdonut__edge {
  stroke-dasharray: none; transition: none;
}

@media (max-width: 640px) {
  .wellhub-root .cpie { grid-template-columns: 1fr; }
  .wellhub-root .cpie__svg { max-width: 240px; margin: 0 auto; }
}

/* Form 6 — diverging. Each half owns 50% of the row so both sides share one scale. */
.wellhub-root .cdivrow { margin: 0 0 16px; }
.wellhub-root .cdivrow__label {
  text-align: center; font-size: 13px; font-weight: 700; color: var(--ink); margin: 0 0 8px;
}
.wellhub-root .cdivrow__plot { display: flex; align-items: center; }
/* The two halves share the space left by the gutters, in proportion to each side's own max
   — set from the template as a flex-grow per chart. Growing rather than a percentage width
   is what keeps the labels out of the calculation: percentages would resolve against the
   whole plot and overflow it once the gutters are added. */
.wellhub-root .cdivrow__side {
  flex: 1 1 0; display: flex; align-items: center; min-width: 0;
}
.wellhub-root .cdivrow__side--l { justify-content: flex-end; }
.wellhub-root .cdivrow__side--r { justify-content: flex-start; }
.wellhub-root .cdivrow__bar { height: 26px; border-radius: 999px; flex: none; }
.wellhub-root .cdivrow__side--l .cdivrow__bar { border-radius: 999px 4px 4px 999px; }
.wellhub-root .cdivrow__side--r .cdivrow__bar { border-radius: 4px 999px 999px 4px; }
/* Fixed gutters. Sized to their text, each row would keep a different amount of space for
   its halves and the axis would wander down the chart. */
.wellhub-root .cdivrow__val {
  flex: none; width: 44px; font-size: 13px; font-weight: 700; color: var(--ink-2);
}
.wellhub-root .cdivrow__val--l { text-align: right; padding-right: 8px; }
.wellhub-root .cdivrow__val--r { text-align: left; padding-left: 8px; }

@media (max-width: 700px) {
  .wellhub-root .cstats { grid-template-columns: 1fr; }
  .wellhub-root .chartcard__head { flex-direction: column; }
  .wellhub-root .chartcard__callout { max-width: none; align-self: flex-start; }
}

/* Expert embedded in the prose, with an optional signature. Not a card: like the charts,
   it sits on the page with a rule above it rather than in a white panel, which is how the
   signed block is meant to read. */
/* A perspective is a PANEL, not a rule across the column. It is one person's argument set
   inside someone else's chapter, and a tinted card is what says so — a border-top said
   "new section" instead, which is the one thing this block is not.
   Two columns: the portrait, and everything the person says. The essay then starts where
   the name starts, rather than below the whole lockup and back at the margin, which read
   as ordinary prose that happened to follow a photograph. */
.wellhub-root .voice--mention {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 20px;
  align-items: start;
  background: var(--bg-2); border: 0; border-radius: var(--radius);
  box-shadow: none; padding: 26px 28px; margin: 32px 0;
}
.wellhub-root .voice__ident { min-width: 0; }
.wellhub-root .voice--mention .voice-avatar,
.wellhub-root .voice--mention .voice-avatar--fallback {
  width: 88px; height: 88px; flex: none; font-size: 26px;
}
/* A signed expert has no essay to align to, so the signature and name take the full width
   beside the portrait rather than a column of their own. */
.wellhub-root .voice--signed { align-items: center; }
@media (max-width: 620px) {
  /* The portrait stops being a column of its own before the words are squeezed to nothing. */
  .wellhub-root .voice--mention { grid-template-columns: minmax(0, 1fr); gap: 14px; padding: 20px; }
}
/* Decorative: the same name follows in ordinary type, and the element is aria-hidden, so
   a screen reader hears the name once rather than twice. Overflow is visible because
   script descenders and the initial swash reach past the text box. */
.wellhub-root .voice__signature {
  font-family: var(--font-signature);
  font-size: clamp(30px, 4vw, 40px); line-height: 1.05;
  color: var(--ink); margin: 0 0 2px; overflow: visible;
}
/* The name leads, in ink, at reading size — it is what the eye is looking for, and at 13px
   in the accent it was the quieter half of its own byline. */
.wellhub-root .voice.voice--mention .name {
  font-family: var(--font-sans); font-weight: 700; font-size: 18px;
  letter-spacing: -0.006em; color: var(--ink);
}
/* The sibling rule sets small-caps for the card layout; here the title reads as a line of
   prose, so the transform and tracking come off — and it takes the chapter's accent, which
   ties the panel to the chapter around it without competing with the name above it. */
.wellhub-root .voice.voice--mention .role {
  font-size: 13px; color: var(--accent-deep); margin: 3px 0 0;
  text-transform: none; letter-spacing: normal; font-weight: 600; line-height: 1.4;
}
.wellhub-root .voice.voice--mention .quote { margin-top: 16px; }

/* A signed card carries no essay, so it is the whole block rather than a heading for one —
   scaled up 40% across the board (portrait, signature, name, role and the spacing between
   them) so it reads as a sign-off rather than as a small caption stranded on the page. */
.wellhub-root .voice--signed { gap: 24px; }
.wellhub-root .voice--signed .voice-avatar,
.wellhub-root .voice--signed .voice-avatar--fallback {
  width: 90px; height: 90px; font-size: 28px;
}
.wellhub-root .voice--signed .voice__signature { font-size: clamp(31px, 4.2vw, 42px); }
.wellhub-root .voice.voice--signed .name { font-size: 18px; }
.wellhub-root .voice.voice--signed .role { font-size: 18px; margin-top: 3px; }

/* ── Regional comparator ──────────────────────────────────────────────────────
 * A wide table read by scanning, so it is built for scanning: no card, strong horizontal
 * rules, and the measure bands tinted with the chapter's own accent so the eye can find
 * where one measure ends and the next begins.
 * ─────────────────────────────────────────────────────────────────────────── */

/* Market picker. Compact — eleven of these sit above the table, and at the old size they
   were a wall. Selected takes the theme's accent with the ink measured legible on it. */
.wellhub-root .region-pick { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px; }
.wellhub-root .region-pick button {
  border: 1px solid var(--line-2); background: transparent; border-radius: 999px;
  padding: 4px 11px; font-size: 12px; font-weight: 600; color: var(--ink-2);
  line-height: 1.5; transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.wellhub-root .region-pick button:hover { border-color: var(--accent); color: var(--accent-deep); }
/* White on the selected pill, not the palette's `--on-primary`.
   That token is black in the magenta theme and white in the other two, so this control read
   one way here and another way in a purple or green chapter; white is now the pairing in all
   three. Measured on #F2496B: white is 3.53:1 and the black it replaces was 4.76:1 — so at
   12px this sits under the 4.5:1 AA bar for body text and over the 3:1 bar for user-interface
   text. A darker pink would buy the contrast back, but this repo already tried a darkened
   magenta (#B81C46) and the client read it as red beside the logo, so the brand colour stays
   and the state is carried by the fill, which is what the reader is actually scanning for. */
.wellhub-root .region-pick button.on {
  background: var(--accent); color: #fff; border-color: var(--accent);
}

.wellhub-root .table-scroll {
  overflow-x: auto; border-radius: var(--radius);
  border: 1px solid var(--line); background: transparent; box-shadow: none;
}
.wellhub-root .regiontable {
  /* Columns sized to their content, not eleven equal shares of the reading measure. Fixed
     layout forced every market into the same narrow column and the long names broke apart;
     `max-content` lets each column ask for what it needs, and `min-width: 100%` keeps the
     table filling its container when the names are short. It scrolls in `.table-scroll` if
     the total still exceeds the width, which is the honest outcome for eleven markets on a
     phone. */
  width: max-content; min-width: 100%; border-collapse: collapse; font-size: 12px;
  background: transparent; table-layout: auto;
  /* Digits line up column to column, which is the whole point of a comparison table. */
  font-variant-numeric: tabular-nums;
}
.wellhub-root .regiontable th, .wellhub-root .regiontable td {
  /* 4px, not 5: twelve columns pay for each side twice, and at 5px the table measured
     736px against a 705px reading column — 31px over, so every laptop from 900px to
     1360px had to scroll a table whose whole point is that it fits. */
  padding: 8px 4px; border-bottom: 1px solid var(--line); text-align: center;
}
.wellhub-root .regiontable tr:last-child td { border-bottom: 0; }
.wellhub-root .regiontable th {
  background: var(--bg); font-size: 10.5px; font-weight: 800; color: var(--ink-2);
  /* The tracking is what the widest columns are made of: these headings are the longest
     strings in the table, and at 0.04em the ninety-odd characters across the row cost
     roughly 34px of width on their own. 0.02em still opens up small uppercase. */
  letter-spacing: 0.02em; text-transform: uppercase; line-height: 1.2;
  /* Two words, two lines — never two pieces of one word.
     `overflow-wrap: anywhere` was tried first and broke names mid-word ("UNITED KINGDO / M",
     "ROMANI / A"), which reads as a rendering fault; the answer to that was `nowrap`, and
     that made "UNITED KINGDOM" and "UNITED STATES" set their columns from a fourteen-
     character line. Ordinary wrapping is what was wanted all along: it breaks at the space
     and nowhere else, so the two-word markets take two lines and the one-word ones cannot
     break at all.
     The `max-width` is what makes it happen. On its own, `white-space: normal` changes
     nothing here — the table asks for `max-content`, which IS the width at which nothing
     wraps, so the column stays as wide as the longest line and the wrap never fires
     (measured: identical to nowrap at every breakpoint). 9ch is the longest single word in
     the market list, ARGENTINA — a cap no name can be broken below, and one that lets
     UNITED KINGDOM fold. Measured at 1440: that column falls from 149px to 102px and the
     narrowest market column rises from 55px to 62px, which is the point — the eleven
     columns even out. At 1024 the table stops overflowing its container entirely.
     `max-width` on a table cell is a suggestion to the column algorithm rather than a
     guarantee, so an engine that declines it renders exactly what this file did before. */
  white-space: normal; overflow-wrap: normal; word-break: normal; hyphens: none;
  max-width: 9ch;
  border-bottom: 1.5px solid var(--line-2); position: sticky; top: 0; z-index: 2;
}
/* The measure heading its own band, tinted with the chapter's accent. */
.wellhub-root .regiontable .group-band td {
  background: var(--accent-soft); text-align: left;
  font-weight: 800; font-size: 13px; color: var(--ink);
  border-bottom: 1px solid var(--line-2);
  box-shadow: inset 3px 0 0 var(--accent);
}
.wellhub-root .regiontable .group-band .note {
  font-weight: 500; font-size: 11.5px; color: var(--ink-2); margin-left: 6px;
}
/* Quieter, and legible. These were 13px of brand magenta on the off-white, which measures
   3.30:1 — small text wants 4.5:1, so a table of a hundred numbers was the least readable
   text on the page while also being the loudest. `--accent-deep` measures 12.98:1 and, at a
   step down in size and weight, lets the band headings lead the table again. The comment
   this replaces claimed these were 16px; they were not. */
.wellhub-root .regiontable td .v {
  font-family: var(--font-display); font-weight: 600; font-size: 13.5px;
  letter-spacing: -0.003em; color: var(--accent-deep);
}
/* The segment column stays put while the markets scroll past it — with eleven columns the
   row labels were the first thing to disappear. */
.wellhub-root .regiontable td.seg, .wellhub-root .regiontable th.seg {
  position: sticky; left: 0; z-index: 1; background: var(--bg);
}
.wellhub-root .regiontable th.seg { z-index: 3; }

/* Segment column: a label, not a number — it should not compete with the values. It does
   need room to be read as a label rather than a squeezed caption, though: at its content
   width it took 91px of a 705px table, so "All employees" and "Pioneers" sat in a column
   narrower than the numbers they name. The floor is what makes it a column. */
.wellhub-root .regiontable td.seg, .wellhub-root .regiontable th.seg {
  text-align: left; color: var(--ink-2); font-size: 13px; white-space: normal;
  min-width: 150px;
}

.wellhub-root .reader .region-breakout,
/* `.summary` as well as `.reader`: the summary page shares markdownBlocks with the Deep
   Dive, so a Key Findings group embedded in the summary prose lands in a `.summary` column
   instead. Scoping this to `.reader` alone would have given that block no spacing at all —
   the failure would have been a grid flush against the paragraph above it. */
.wellhub-root .reader .kf-embed,
.wellhub-root .summary .kf-embed { margin: 8px 0 18px; }
/* Wider than the reading measure, EITHER SIDE of it. It used to reach only right, into the
   column the margin stats occupied; with the reader centred there is no reason to favour
   one side, and a symmetric block stays centred on the prose above it.
   Negative margins rather than a grid span, because the table is nested inside its chapter
   <section> and cannot be a grid item from where it sits — a `.reader > .region-breakout`
   rule silently matched nothing for exactly that reason.

   THE TABLE ONLY. Key Findings used to break out too, and that put two blocks — of the
   dozens the reader scrolls past — on a width nothing else shared: prose, all 34 charts,
   the quotes and the figures sit on the 70ch measure, so the wide block read as a mistake
   rather than as emphasis. The table earns the exception because its content demands it:
   it carries a column per market, and narrowing it is what wrapped the country names onto
   two lines that the client asked us to fix. Key Findings has no such constraint — its
   cards simply reflow — so it goes back on the measure with everything else. */
/* 1261px, not 1361: the table asks for the wider box from the moment there is room for it,
   and measured, a 134px reach each side still clears the 270px rail by 8px at 1261. The
   extra hundred pixels of threshold cost the commonest laptop width — 1280 — a table it
   had the room to show whole. */
@media (min-width: 1261px) {
  .wellhub-root .reader .region-breakout {
    margin-left: calc(-1 * var(--breakout, 134px));
    margin-right: calc(-1 * var(--breakout, 134px));
  }
}
/* Between the width where the sidebar stops being a drawer (901px) and the width where the
   reading column reaches its full 70ch (1100px), the column is squeezed between a fixed
   270px rail and `.main`'s 48px padding — 533px of it at 901px. The table needs 696px, so
   this is the one band where it cannot fit whatever its own padding does, and it fell back
   to scrolling: 163px of it at 901px, 40px at 1024px, which is an iPad in landscape.
   Reaching into `.main`'s own padding is the only room there is; 44px of the 48 keeps the
   table off the rail's border. The band runs up to where the full breakout takes over at
   1261px, so the two together leave no width above 901px where the table has room it is
   not using. Below that the sidebar is a drawer, the page padding is 20px rather than 48,
   and `.table-scroll` does its job instead. */
@media (min-width: 901px) and (max-width: 1260px) {
  .wellhub-root .reader .region-breakout { margin-left: -44px; margin-right: -44px; }
}
/* Below the grid, the table simply fills the reading column and scrolls inside
   `.table-scroll` if eleven markets need more.
   What was here centred it on `min(1040px, 100vw - 32px)` with a 50% offset — which is
   centred on the CONTAINING BLOCK, not the viewport. At 1100px the sidebar is still on
   screen, so a 1040px table ran underneath it and off the right edge of the page. Measured:
   overlapsSidebar true, overflowsViewport true. A table that scrolls is a smaller cost than
   one you cannot fully see. */
/* Each measure heads its segment rows as a full-width band: written once, as a heading,
   rather than as a first-row cell with the rest of the column left blank — which read as
   missing data. Its appearance is set in the comparator block above. */
.wellhub-root .regiontable tr.group-band td { font-family: var(--font-sans); }
.wellhub-root .regiontable tr.group-band:first-child td { border-top: 0; }

/* ── Voices / playbook ────────────────────────────────────────────────────── */
.wellhub-root .voice { padding: 22px; }
.wellhub-root .voice .name { font-family: var(--font-display); font-weight: 700; font-size: 17px; letter-spacing: -0.0045em; line-height: 1.15; }
.wellhub-root .voice .role { color: var(--accent-deep); font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; margin: 3px 0 12px; }
.wellhub-root .voice .quote { font-size: 15px; line-height: 1.6; color: var(--ink-2); }

/* Voice card header: portrait + identity */
.wellhub-root .voice-head { display: flex; align-items: center; gap: 13px; margin-bottom: 14px; }
.wellhub-root .voice-head .voice-id { min-width: 0; }
.wellhub-root .voice-head .role { margin: 2px 0 0; }
/* A white ring and a soft shadow, so the portrait reads as a print lifted off the page
   rather than as an image with a coloured outline. The magenta ring this replaces competed
   with the accent used for the figures beside it.
   The hairline in the shadow is load-bearing: the expert card's own background IS white, so
   a white ring alone has no edge there and the portrait bleeds into the card. On the tinted
   person card the same hairline is all but invisible. One rule, legible on both. */
.wellhub-root .voice-avatar,
.wellhub-root .voice-avatar--fallback {
  width: 52px; height: 52px; flex: none; border-radius: 50%; object-fit: cover;
  object-position: center 30%;
  border: 4px solid #fff; background: var(--bg-2); box-sizing: border-box;
  box-shadow: 0 0 0 1px var(--line), 0 3px 10px rgba(42, 24, 34, 0.16);
}
.wellhub-root .voice-avatar--fallback {
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: 700; font-size: 18px;
  color: var(--accent-deep); background: var(--accent-soft);
}
.wellhub-root .voice blockquote {
  font-family: var(--font-sans); font-weight: 600; font-style: italic;
  font-size: 17px; line-height: 1.4; letter-spacing: -0.015em;
  margin: 0 0 12px; padding: 0; border: 0; color: var(--ink);
}
.wellhub-root .linkbtn {
  margin-top: 10px; border: 0; background: transparent; color: var(--accent-deep);
  font-weight: 700; font-size: 12.5px; padding: 0;
}
.wellhub-root .linkbtn:hover { text-decoration: underline; }
.wellhub-root .play { padding: 22px; }
.wellhub-root .play h3 { font-family: var(--font-display); font-weight: 700; margin: 0 0 8px; font-size: 19px; letter-spacing: -0.0045em; }
.wellhub-root .play p { margin: 0; font-size: 14px; line-height: 1.55; color: var(--ink-2); }

/* Persona card (inline in Deep Dive) — portrait + profile */
/* ============================================================================
   Deep Dive — long-form reading
   ========================================================================== */
.wellhub-root .reader { max-width: 70ch; margin: 0 auto; }
/* A plain centred measure. This was a grid reserving a second 240px column for the margin
   stats; with those gone the column would have been permanent empty space on the right and
   the prose would have sat visibly left of centre. `--breakout` is what the wide blocks
   still reach into — the same distance the reserved column used to take, now split evenly
   either side of the measure. */
.wellhub-root .main > .reader { --breakout: 134px; max-width: 70ch; margin: 0 auto; }

/* Report masthead — the research title at the very top of the Deep Dive, taken
   from report-meta, so the reader opens with the report's identity before §1. */
/* The rule needs more air beneath it than above: weighted the other way it reads as an
   underline on the subtitle instead of the end of the masthead, and the first chapter head
   is deliberately undrawn (nothing above it to separate from), so this line is the only
   thing marking where the report's identity stops and its content starts. */
.wellhub-root .reader .masthead {
  margin: 8px 0 40px; padding-bottom: 30px;
  border-bottom: 1px solid var(--line, rgba(40, 30, 50, 0.12));
}
.wellhub-root .reader .masthead__hero {
  margin: 0 0 22px; border-radius: var(--radius-lg, 22px); overflow: hidden;
  box-shadow: var(--shadow-md);
  /* Reserve the height before the image loads so it doesn't shift the whole
     document down (which would throw off click-to-scroll on later chapters). */
  aspect-ratio: 16 / 9; max-height: 460px; background: var(--bg-2);
}
.wellhub-root .reader .masthead__hero img {
  display: block; width: 100%; height: 100%; object-fit: cover;
}
.wellhub-root .reader .masthead__eyebrow {
  /* --accent-deep, not --accent: brand magenta is 3.32:1 on the off-white and this is 12px,
     so it needed the palette's dark tier — the same reasoning already written against
     h1.doc below. Same family, four points more contrast. */
  font-family: var(--font-sans); color: var(--accent-deep); font-weight: 700;
  font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase;
}
.wellhub-root .reader .masthead__title {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(38px, 5.2vw, 56px); line-height: 1.04; letter-spacing: -0.0105em;
  margin: 12px 0 0; color: var(--ink);
}
.wellhub-root .reader .masthead__subtitle {
  font-family: var(--font-sans); font-size: clamp(17px, 2vw, 20px);
  line-height: 1.5; color: var(--ink-2); margin: 14px 0 0; font-weight: 400;
}

.wellhub-root .reader .chapter-head {
  margin: 72px 0 10px; padding-bottom: 4px;
  scroll-margin-top: calc(var(--header-h) + 24px);
}
/* A CHAPTER OPENING, not just a bigger heading. On a document this long, space alone stops
   registering — the reader has already scrolled past a dozen paragraph gaps and a larger one
   reads as a pause, not as a new chapter. So the break is drawn: a hairline across the
   measure with a short, thick accent tick straddling it at the left.
   The tick carries the CHAPTER'S OWN THEME, so the colour changes as the reader moves from
   one chapter to the next and the boundary is legible before the title is read. */
.wellhub-root .reader .chapter-head {
  position: relative;
  margin-top: 104px; padding-top: 32px;
  border-top: 1px solid var(--line);
}
.wellhub-root .reader .chapter-head::before {
  content: ""; position: absolute; top: -2px; left: 0;
  width: 72px; height: 3px; border-radius: 2px; background: var(--accent);
}
/* Every chapter head is drawn, not only the top-level ones. In this report the numbering
   runs 1.4, 3.4, 3.5 — nearly every chapter is a SUBSECTION by `isSubChapter`, so a rule
   scoped to top-level heads would have appeared almost nowhere. A subsection gets the same
   break at a lower weight: less space above, a shorter tick, so the hierarchy still reads. */
.wellhub-root .reader .chapter-head--sub { margin-top: 68px; padding-top: 26px; }
.wellhub-root .reader .chapter-head--sub::before { width: 40px; height: 2px; }
/* The first chapter opens the document — there is nothing above it to be separated from,
   and a rule there would read as the end of the masthead. `.chapter` is the per-chapter
   wrapper, so this has to reach for the first SECTION, not the first child: the head is the
   first child of every one of them. */
.wellhub-root .reader .chapter:first-of-type .chapter-head {
  margin-top: 8px; padding-top: 0; border-top: 0;
}
.wellhub-root .reader .chapter:first-of-type .chapter-head::before { content: none; }
.wellhub-root .reader .chapter-head .num { margin-right: 0.55em; }
/* Selected by the WRAPPER, not the tag. The chapter head is an <h2> and a subsection head
   an <h3> — the report's own 1 / 1.1 numbering told as heading levels — and both share the
   prose `.doc` class, so a tag selector here would either miss them or collide with the
   `h2.doc` / `h3.doc` prose rules below. Four classes beats those three-classes-and-a-tag,
   so the chapter styling wins wherever the two overlap. */
.wellhub-root .reader .chapter-head > .doc {
  /* `text-transform: none` is not redundant. A subsection head is an <h3 class="doc">, which
     also matches the prose `h3.doc` rule below — and that rule sets uppercase, which nothing
     here was overriding. Every "1.1" title came out shouting, and the deep dive grew 123px.
     Anything the prose rules set and these do not will leak the same way. */
  text-transform: none;
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(30px, 4vw, 40px); line-height: 1.08; letter-spacing: -0.009em;
  margin: 0;
  /* The chapter title in the chapter's own colour. `--accent-deep` rather than `--accent`:
     it is the palette's tier for text that must clear 4.5:1, so the heading stays readable
     in all three themes rather than relying on its size for contrast. */
  color: var(--accent-deep);
}
/* Subsection chapter heads (e.g. "1.1 Foreword") sit a tier below top-level chapters:
   smaller type. Their spacing and rule weight are set with the chapter break above. */
.wellhub-root .reader .chapter-head--sub > .doc {
  font-size: clamp(21px, 2.5vw, 27px); line-height: 1.14; letter-spacing: -0.025em;
}

.wellhub-root .reader h2.doc {
  font-family: var(--font-display); font-weight: 700;
  font-size: 25px; line-height: 1.2; letter-spacing: -0.006em; margin: 40px 0 12px;
}
.wellhub-root .reader h3.doc {
  font-family: var(--font-sans); font-weight: 700;
  font-size: 13px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--accent-deep); margin: 32px 0 8px;
}

/* 19px, and the size is load-bearing. Bold runs in here are painted brand magenta at
   3.3:1, which satisfies AA only under the large-text provision — >=18.66px at bold. Drop
   this back to 18px and every bold run in the report silently fails contrast, with nothing
   in the build to catch it. Any override of this size must clear 18.66px too. */
.wellhub-root .reader p.doc {
  font-family: var(--font-sans); font-size: 19px; line-height: 1.7;
  margin: 0 0 22px; color: var(--ink); font-weight: 400;
}
.wellhub-root .reader ol.doc, .wellhub-root .reader ul.doc {
  font-family: var(--font-sans); font-size: 19px; line-height: 1.65;
  color: var(--ink); font-weight: 400; margin: 0 0 22px; padding-left: 1.6em;
}
.wellhub-root .reader ol.doc { list-style: decimal; }
.wellhub-root .reader ul.doc { list-style: disc; }
.wellhub-root .reader ol.doc li, .wellhub-root .reader ul.doc li { margin: 0 0 8px; padding-left: 6px; }
.wellhub-root .reader ol.doc li::marker, .wellhub-root .reader ul.doc li::marker { color: var(--accent); font-weight: 600; }
/* Editorial drop cap on the first paragraph of each chapter — except where the paragraph
   opens on an initialism, which a drop cap would split ("A" beside "I fluency"). */
.wellhub-root .reader .chapter-head + .unit > p.doc.doc--nocap:first-child::first-letter {
  font: inherit; float: none; padding: 0; color: inherit; line-height: inherit;
  height: auto;
}
.wellhub-root .reader .chapter-head + .unit > p.doc:first-child::first-letter {
  font-family: var(--font-display); font-weight: 800; float: left;
  /* Body line-height is 1.7, so three lines = 5.1em. Stay under that or the
     fourth line wraps too. 5.35 × 0.9 = 4.82em. */
  font-size: 5.35em; line-height: 0.9; padding: 0 10px 0 0;
  /* --accent-figure: the drop cap and the chart figures share the chapter's ~6:1 colour. */
  color: var(--accent-figure);
}

.wellhub-root .reader blockquote.pull {
  margin: 40px 0; padding: 0; border: 0; background: transparent;
}
.wellhub-root .reader blockquote.pull::before {
  content: ""; display: block; width: 34px; height: 3px; border-radius: 3px;
  background: var(--accent); margin: 0 0 18px;
}
.wellhub-root .reader blockquote.pull p {
  font-family: var(--font-sans); font-weight: 600; font-style: italic;
  font-size: 25px; line-height: 1.4; letter-spacing: -0.02em; color: var(--ink); margin: 0;
}
.wellhub-root .reader blockquote.pull cite {
  display: block; margin-top: 16px; font-family: var(--font-sans); font-style: normal;
  font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-2);
}
.wellhub-root .reader blockquote.pull cite::before { content: "— "; color: var(--accent-deep); }

/* ── Photographs in the prose ─────────────────────────────────────────────────
 * An inline [[image: …]] marker, which is how every narrative photograph arrives — there
 * is no image field on a narrative section, and the marker's position in the markdown IS
 * the intended placement, so these render in document order where they fall.
 *
 * Set BESIDE the prose rather than spanning it, which is the source report's own
 * convention and the reason this is a float. Side-by-side in a grid was the alternative
 * and is wrong here: splitting a 70ch measure in two leaves ~40 characters a line, below
 * what reads comfortably. A float narrows the measure only for the few lines it takes to
 * pass the photo, then gives it back.
 *
 * Left, deliberately. The margin stats occupy the right, and a section can carry both —
 * 3.4 has two stats and a photo — so putting the photo right would crowd one edge and
 * leave the other empty.
 * ─────────────────────────────────────────────────────────────────────────── */
.wellhub-root .reader .figure {
  float: left; width: 46%; margin: 6px 28px 18px 0;
  /* Payload has no width/height. A 4:3 slot is the photograph's shape, reserved
     before the file arrives so wrapping prose does not jump when it does. */
  aspect-ratio: 4 / 3; overflow: hidden; background: var(--bg-2);
  border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.wellhub-root .reader .figure img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* A figure with no prose to wrap it — the last block of a short section, or one hemmed in
   by headings and charts. prepare.mjs marks it rather than guessing here, because whether
   text follows is a fact about the document, not about the viewport. Full measure and a
   wider frame: it then reads as a plate the section ends on, instead of a float that found
   nowhere to sit. */
.wellhub-root .reader .figure--wide,
.wellhub-root .summary .figure--wide {
  float: none; width: 100%; margin: 26px 0; aspect-ratio: 16 / 9;
}

/* What may sit beside a photo, and what may not. Prose and lists wrap around it — that is
   the point. Everything with its own frame or rule clears instead: a chart, a pull quote or
   a heading squeezed into the remaining 60% reads as broken layout, not as a wrap. */
.wellhub-root .reader h2.doc,
.wellhub-root .reader h3.doc,
.wellhub-root .reader blockquote.pull,
.wellhub-root .reader .figure,
.wellhub-root .reader .imgph,
.wellhub-root .reader .docchart,
.wellhub-root .reader .statcard,
.wellhub-root .reader .voice,
.wellhub-root .reader .personcard,
.wellhub-root .reader table { clear: both; }
.wellhub-root .reader .docchart { margin: 32px 0; }
/* …except a `stat_rows` stack, which is the one chart shaped like a picture: tall, narrow,
   and mostly empty across a full column. It floats and the paragraph wraps around it, the
   way a photograph does. `clear: right` rather than the `both` above, so it can sit beside
   prose that already has a figure floated left.
   Only where there is a column to share: below the width where `.figure` gives up floating,
   this does too — 46% of a phone is not a chart, it is a sliver. */
@media (min-width: 761px) {
  .wellhub-root .reader .docchart--aside,
  .wellhub-root .summary .docchart--aside {
    float: right; clear: right; width: 46%; margin: 6px 0 18px 28px;
  }
}
/* Charts sit on the prose column's left edge — no centred max-width inside a chapter. */
.wellhub-root .chapter .chartcard {
  margin-inline: 0; max-width: none;
}

/* A float that outlives its unit would spill into the next chapter's prose. Cleared with a
   pseudo-element rather than `overflow: auto`, which would have clipped the margin stats —
   they are positioned outside the unit's box by design. */
.wellhub-root .unit::after { content: ""; display: block; clear: both; }

/* Narrow enough that 46% of the measure is a thumbnail and what wraps beside it is a
   column of two-word lines: the photo spans instead. Declared here, beside the rules it
   undoes, rather than in the mobile block far below — at equal specificity, source order
   decides, and that has already cost this file twice. */
@media (max-width: 760px) {
  .wellhub-root .reader .figure { float: none; width: 100%; margin: 26px 0; }
}
.wellhub-root .reader .imgph {
  display: flex; gap: 10px; align-items: center; background: var(--bg-2);
  border: 1px dashed var(--line-2); border-radius: var(--radius);
  padding: 16px 18px; margin: 28px 0; font-size: 13px; color: var(--ink-2);
}
.wellhub-root .reader .imgph .tag {
  font-family: var(--font-sans); font-weight: 800; font-size: 10px; letter-spacing: 0.08em;
  color: var(--purple); flex: none; white-space: nowrap;
  background: #fff; border-radius: 6px; padding: 4px 7px;
}

/* ── Shared misc ──────────────────────────────────────────────────────────── */
/* The source name is the only thing in its row, so it is a standalone target rather than a
   link inside a sentence — WCAG 2.2's inline exemption does not cover it, and it measured
   20px. Padded to the 24px minimum with the same amount taken back as margin, so the list
   keeps its spacing. */
/* A 24px tall target (WCAG 2.5.8) on a 16px line, without moving anything: the padding
   grows the hit area and the line box is left alone, so the sources list sets exactly as it
   did.
   `inline`, NOT `inline-block`, and the difference only shows once something follows the
   link. An inline-block is one box however many lines it wraps onto, so text after it
   starts below the whole thing: a wrapping title put the journal on a line of its own with
   the full stop orphaned at the start of it — ". International Archives of Occupational
   and Environmental Health." Inline, the link breaks into line fragments and the container
   carries on from the end of the last one. Vertical padding still grows the hit area of
   each fragment; vertical margin would not apply to an inline box at all, which is why the
   -4px that used to cancel it is gone rather than kept as decoration. */
.wellhub-root .sources__label {
  display: inline; padding-block: 4px;
}
/* The publisher and year take a line of their own above the work, so the two stop running
   into each other. They used to be one inline flow — "The Inverse Care Law Hart, J. T. ·
   1971" — which set as a single wrapped sentence with no visible boundary between the title
   and its citation, and on the longer entries the wrap landed mid-phrase.
   A block, not a flex column: the label's 24px touch target is an inline-block with a
   negative margin cancelling its own padding, and making the row a flex container would
   have stretched it to the full width and put the hit area across the whole line. */
.wellhub-root .sources__detail { display: block; color: var(--ink-2); font-size: 13px; }
/* An entry is two lines now, so the entries have to be told apart from each other. Measured
   without this: items sat 39px apart and each one is two ~20px lines, so consecutive entries
   butted together and the only thing pairing a title with its publisher was the type. The
   gap makes the pair the closest thing to itself, which is what stops a reader attaching a
   title to the organisation on the line below it.
   On the sibling rather than on every item, so the list does not end in trailing space. */
.wellhub-root .sources__item + .sources__item { margin-top: 12px; }

.wellhub-root .empty {
  color: var(--ink-2); padding: 40px; text-align: center; font-size: 14px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
}
.wellhub-root .loading {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  min-height: 60vh; color: var(--ink-2); font-size: 15px;
}
.wellhub-root .spinner {
  width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid var(--line-2); border-top-color: var(--accent);
  animation: wellhub-spin 0.7s linear infinite;
}
@keyframes wellhub-spin { to { transform: rotate(360deg); } }

/* ── Responsive ───────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  /* On narrow screens the menu is an overlay drawer over the content. It is
     hidden by default (body.nav-closed) and slides in when toggled open. */
  .wellhub-root .sidebar {
    position: fixed; top: var(--header-h); left: 0; bottom: 0; height: auto;
    width: min(84vw, 320px); z-index: 60; background: var(--bg);
    box-shadow: var(--shadow-md);
    /* The desktop rail is a flex item and sets `align-self: flex-start`; the drawer is
       out of flow and must drop it. Chrome self-aligns a fixed flex child that still
       carries an align-self, which made it ignore `top`/`bottom` — the drawer rendered
       at y=0 over the header and grew to its content height (1857px measured), so most
       of a 43-chapter list sat below the fold with nothing able to scroll it. */
    align-self: auto;
  }
  .wellhub-root .body:not(.nav-closed) .nav-backdrop {
    display: block; position: fixed; inset: var(--header-h) 0 0 0; z-index: 55;
    background: rgba(20, 15, 25, 0.38);
  }
  .wellhub-root .main { padding: 24px 20px 0; }
  .wellhub-root .hero { padding: 36px 26px; }
  .wellhub-root .brand small { display: none; }
}

/* The header cannot hold the lockup, the controls and three tab labels on one row at
   phone width — measured at 390px, the tab strip alone wants 247px of a 374px bar, so
   the labels wrapped to two lines each and the wordmark ended up underneath them.
   Nothing here is shrinkable enough to close that gap: the three labels are ~145px of
   bare text before any padding. So the tabs drop to a row of their own and share its
   full width, which is the shape a segmented control takes on a phone anyway.
   `--header-h` is the single source for the sticky offsets (sidebar top and height, the
   nav backdrop, every `scroll-margin-top`), so raising it here is all the two-row header
   needs — do not hard-code 60px anywhere. */
@media (max-width: 720px) {
  .wellhub-root .topbar { gap: 9px 10px; padding: 0 14px; }
  .wellhub-root .navtoggle { margin-right: 0; }
  .wellhub-root .brand { gap: 12px; }
  .wellhub-root .brand__logo { height: 21px; }
  .wellhub-root .toggle button { padding: 7px 8px; }
}
/* The second row starts only where one row genuinely stops fitting. Measured with the
   compact sizes above: the header needs 532px and first has slack at 540px, so the wrap
   threshold is 539px. It was 500px when the first tab read "Overview" — the longer label
   costs the strip 60px and moved the boundary with it, which is the kind of thing that
   only shows up by measuring the header again after renaming a tab.
   The band above it is not a rare case — it is every phone held sideways (667, 736, 844
   wide), where a 98px header would eat a quarter of a 375px-tall screen to solve a problem
   that width does not have. `--header-h` carries the taller header to the sticky offsets. */
@media (max-width: 539px) {
  .wellhub-root { --header-h: 98px; }
  .wellhub-root .topbar { flex-wrap: wrap; align-content: center; }
  /* `order` moves the strip past the print button without touching the markup, so the
     first row keeps its reading order: menu, wordmark, print. */
  .wellhub-root .toggle { order: 1; flex: 1 0 100%; }
  /* `auto` basis, not equal thirds: "Executive Summary" is three times the width of
     "Data", and splitting the row equally gave it a pill too narrow to hold it — the text
     then ran out of its own background, because a tab label is `nowrap` by design. Sized
     from content, each tab takes what it needs and the spare width is shared. */
  .wellhub-root .toggle button { flex: 1 1 auto; min-width: 0; }
}

/* ────────────────────────────────────────────────────────────────────────────
 * Defensive overrides — neutralize global CSS bleed from sibling experiences.
 *
 * Kehe (src/pages/kehe) is statically imported in src/App.tsx and ships UNSCOPED
 * global class rules (.section-head, .pill, .brand, .chip, .filters, .wrap, …)
 * that collide with this app's generic class names and are therefore present in
 * the document even on /wellhub. Our .wellhub-root-scoped rules already out-rank
 * Kehe (0,2,0 vs 0,1,0) on every property they DECLARE, but Kehe still bleeds
 * through for properties the standalone app left at their browser defaults
 * (e.g. Kehe's `.section-head { display:grid }` and `.pill { text-transform:
 * uppercase }`). Re-assert those defaults here. Derived from a kehe↔wellhub
 * property diff — revisit if either app's class names change.
 * ──────────────────────────────────────────────────────────────────────────── */
.wellhub-root .section-head { display: block; border-top: 0; padding-top: 0; }
.wellhub-root .brand { font-family: var(--font-sans); font-weight: 500; font-size: 14px; letter-spacing: normal; }
.wellhub-root .pill { display: inline-block; font-family: var(--font-sans); letter-spacing: normal; text-transform: none; }
.wellhub-root .chip { border: 0; }
.wellhub-root .filters { padding: 0; border: 0; border-radius: 0; background: transparent; }
.wellhub-root .empty { margin-top: 0; }
.wellhub-root .wrap { padding: 0; }
/* Kehe's `.quote` is a huge display-serif pull-quote (font: display, size:
   clamp(28–42px), max-width: 22ch). The standalone app has no bare `.quote`
   rule — its `.quote` (Playbook bodies, Voice essays/personas via <Expandable>)
   is plain reading text. Re-establish that; `.voice .quote` (above) still wins
   on size/line-height/colour for the voice cards. */
.wellhub-root .quote {
  font-family: var(--font-sans); font-weight: 400; font-size: 15px; line-height: 1.65;
  color: var(--ink-2); letter-spacing: normal; max-width: none;
}
/* An essay is now one paragraph per break in the payload rather than one collapsed block.
   The gap is set here rather than left to the browser's 1em on <p>, and the outer margins
   are zeroed: the wrapper already owns the spacing between the essay and the name above it
   (`.voice.voice--mention .quote`), so a UA margin on the first and last paragraph would
   have added to it and moved every voice card. A single-paragraph essay is therefore
   byte-for-byte the same box it was before. */
.wellhub-root .quote > p { margin: 0; }
.wellhub-root .quote > p + p { margin-top: 0.9em; }
/* Kehe's `.eyebrow` forces a monospace font; the hero/sidebar eyebrows
   (`.hero .eyebrow`, `.sidebar .eyebrow`) don't set font-family, so it bleeds. */
.wellhub-root .eyebrow { font-family: var(--font-sans); }

/* ── Site footer ──────────────────────────────────────────────────────────────
 * The copyright closes the page, not the Methodology section. It used to live
 * inside that section, above `.main`'s 140px bottom padding, so it rendered a
 * screenful short of the end of the document — "the footer scrolls up". It is
 * now the last child of `.main`, which is a column with the reading content
 * growing to fill it: long pages get the footer straight after the content,
 * short ones get it pinned to the bottom of the viewport. Same on both reading
 * modes; the modifier only matches the narrower Deep Dive measure.
 * ──────────────────────────────────────────────────────────────────────────── */
.wellhub-root .main > .wrap,
.wellhub-root .main > .reader { flex: 1 0 auto; width: 100%; padding-bottom: 96px; }

.wellhub-root .sitefoot {
  width: 100%; max-width: 1080px; margin: 0 auto;
  padding: 20px 0 36px; border-top: 1px solid var(--line);
  color: var(--ink-3); font-size: 12.5px;
}
.wellhub-root .sitefoot--reader { max-width: 70ch; }

/* ────────────────────────────────────────────────────────────────────────────
 * Print — the on-screen app is an interactive shell (sticky header, a fixed
 * sidebar TOC that runs the full page height, a scroll progress bar, a mode
 * toggle, a mobile drawer). Printed as-is, that chrome squeezes the report into
 * a narrow column, the header/progress bar repeat, and screen backgrounds drop
 * out. Here we strip the chrome and let the report flow as a document. Works for
 * both reading modes: Deep Dive (`.reader`) and Overview (`.wrap`). What is on
 * screen when the user hits Print is what prints.
 * ──────────────────────────────────────────────────────────────────────────── */
@media print {
  /* Belt and braces: the dialog is removed before print() is called, but a browser
     print started any other way must never put the overlay on paper. */
  .printprep { display: none !important; }
  /* Comfortable paper margins; the flowing content owns everything inside. */
  @page { margin: 18mm 16mm; }

  /* Print the real ink of charts, chips, accent rules, cover art and card
     fills — otherwise browsers strip backgrounds/colours to save toner and the
     bar charts and colour-coded elements come out blank. */
  .wellhub-root, .wellhub-root * {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }
  .wellhub-root { background: #fff !important; }

  /* Drop every screen-only control so only the report remains. */
  .wellhub-root .topbar,
  .wellhub-root .progress,
  .wellhub-root .sidebar,
  .wellhub-root .nav-backdrop,
  .wellhub-root .navtoggle,
  .wellhub-root .toggle,
  .wellhub-root .more-row,
  .wellhub-root .filters,
  .wellhub-root .tagfilters { display: none !important; }

  /* Collapse the flex app shell into one flowing, full-width column. */
  .wellhub-root .app,
  .wellhub-root .body { display: block !important; min-height: 0 !important; }
  .wellhub-root .main { display: block !important; padding: 0 !important; }
  .wellhub-root .main > .wrap,
  .wellhub-root .main > .reader { padding-bottom: 0 !important; }
  .wellhub-root .reader,
  .wellhub-root .wrap { max-width: 100% !important; margin: 0 !important; }

  /* Screen shadows/transitions print as muddy grey haloes — flatten them. */
  .wellhub-root .statcard,
  .wellhub-root .chartcard,
  .wellhub-root .voice,
  .wellhub-root .play,
  .wellhub-root .card-base,
  .wellhub-root .personcard,
  .wellhub-root .table-scroll,
  .wellhub-root .masthead__hero,
  .wellhub-root .figure img { box-shadow: none !important; transition: none !important; }
  /* Unfloat for print: a float that crosses a page break is rendered inconsistently by
     print engines, and paper has no margin stats competing for the width. */
  .wellhub-root .reader .figure { float: none !important; width: 100% !important; margin: 18pt 0 !important; }

  /* Print-scale typography: the on-screen sizes use viewport clamps that resolve
     against the *page* width when printing (over-large and unpredictable). Pin
     them to point sizes so the report reads like print, not a screenshot. */
  .wellhub-root .reader .masthead__title { font-size: 26pt !important; }
  .wellhub-root .reader .masthead__subtitle { font-size: 13pt !important; }
  .wellhub-root .reader .chapter-head > .doc { font-size: 20pt !important; }
  .wellhub-root .reader .chapter-head--sub > .doc { font-size: 15pt !important; }
  .wellhub-root .reader h2.doc { font-size: 15pt !important; margin-top: 20pt !important; }
  .wellhub-root .reader h3.doc { font-size: 10pt !important; }
  .wellhub-root .reader p.doc,
  .wellhub-root .reader ol.doc,
  .wellhub-root .reader ul.doc { font-size: 11pt !important; line-height: 1.5 !important; margin-bottom: 12pt !important; }
  .wellhub-root .reader blockquote.pull p { font-size: 15pt !important; }

  /* Keep a heading with the content it introduces. */
  .wellhub-root .chapter-head,
  .wellhub-root .chapter-head > .doc,
  .wellhub-root h2.doc,
  .wellhub-root h3.doc,
  .wellhub-root .section-head,
  .wellhub-root .masthead__eyebrow,
  .wellhub-root .chapter-head .num { break-after: avoid; page-break-after: avoid; }

  /* Never split an atomic block across pages. */
  .wellhub-root .figure,
  .wellhub-root .chartcard,
  .wellhub-root .statcard,
  .wellhub-root .voice,
  .wellhub-root .personcard,
  .wellhub-root blockquote.pull,
  .wellhub-root .imgph,
  .wellhub-root .cbar,
  .wellhub-root .cgroup,
  .wellhub-root .cstat,
  .wellhub-root li,
  .wellhub-root tr,
  .wellhub-root img { break-inside: avoid; page-break-inside: avoid; }

  /* Cap image height so one tall figure can't monopolise a page. */
  .wellhub-root .reader .figure img,
  .wellhub-root .reader .masthead__hero { max-height: 80vh !important; }

  /* Start each top-level chapter (e.g. "2 What's Fueling…") on a fresh page so
     the report prints as chapters, not one run-on scroll. Sub-sections (2.1,
     2.2 …) stay inline within their chapter. */
  .wellhub-root .reader .chapter-head:not(.chapter-head--sub):not(:first-child) {
    break-before: page; page-break-before: always;
  }

  /* Avoid orphan/widow single lines dangling across page breaks. */
  .wellhub-root .reader p.doc { orphans: 3; widows: 3; }

  /* THE WORLDWIDE WELLNESS TABLE WAS BEING CROPPED, not scaled, and it lost data silently.
     `.table-scroll` scrolls sideways on screen — the honest answer to eleven markets on a
     phone — and a scroll container prints only the part that fits. Measured on A4 with the
     margins above: 671px of page against a 782px table, so the printed report ended at
     GERMANY. Mexico and Romania were absent from the PDF entirely and Argentina's heading
     was cut to "ARGENTIN", with nothing on the page to suggest two markets were missing.

     `overflow: visible` is what stops the clipping. On its own it would spill 111px past
     the page edge instead, so the table also has to be told to fit.

     WHAT ACTUALLY MAKES IT FIT IS THE TYPE SIZE, not the fixed layout — measured, because
     the opposite is the natural assumption. At these print sizes the column algorithm asks
     for 671px of a 673px page even left on `auto`, so an auto table squeezes in. With TWO
     PIXELS to spare: one market renamed, one value at "100.0%", one font substituted on a
     machine without Inter, and it is over the edge and clipping again. `table-layout: fixed`
     with `width: 100%` is what makes that impossible rather than lucky — the algorithm can
     no longer ask for more than the page. Removing it does not turn the print test red
     today, and that is precisely the reason it is here: the test pins the outcome, and this
     line is what keeps the outcome true for content nobody has sent yet.

     Fixed layout also makes the market headings wrap at their space, which is what
     `white-space: normal` and `max-width: 9ch` on that rule always intended — on screen the
     `max-content` width means the wrap never fires, as the note there explains. `max-width`
     comes off here because 9ch is narrower than the column a twelfth of the page gives, and
     it would wrap earlier than it needs to.

     The segment column takes a share rather than its 150px floor: that floor exists to stop
     "All employees" wrapping inside a reading column, and paper has no such column.

     `position: static` on the header: sticky is meaningless on paper, and <thead> already
     repeats the row on every page it breaks onto, which is the behaviour actually wanted. */
  .wellhub-root .table-scroll { overflow: visible !important; }
  .wellhub-root .regiontable {
    width: 100% !important; min-width: 0 !important; table-layout: fixed !important;
    font-size: 7.5pt !important;
  }
  .wellhub-root .regiontable th,
  .wellhub-root .regiontable td { padding: 5px 2px !important; }
  /* The headings need their OWN size, and the reason is a specificity trap worth naming:
     `.regiontable th` sets `font-size: 10.5px`, which is more specific than the
     `.regiontable` rule above, so shrinking the table left the headings at their screen
     size. Measured at that size in a column a twelfth of the page wide, four of them —
     Argentina by 16px, Germany 7px, United Kingdom and Romania 4px each — were wider than
     their column and, with `word-break: normal` forbidding a mid-word break, simply
     overflowed into the neighbour: the PDF read "ARGENTINACHILE" and "GERMANYMEXICO".

     Smaller type rather than a mid-word break. `overflow-wrap: anywhere` was tried on
     screen and produced "ROMANI / A", which reads as a rendering fault; hyphenating country
     names in a table heading is no better. A heading set smaller than its data is ordinary
     in a dense print table, and it keeps every name whole. */
  .wellhub-root .regiontable th {
    font-size: 6pt !important; letter-spacing: 0 !important;
    max-width: none !important; position: static !important;
  }
  .wellhub-root .regiontable th.seg,
  .wellhub-root .regiontable td.seg { width: 14% !important; min-width: 0 !important; }
  .wellhub-root .regiontable .group-band td { font-size: 8.5pt !important; }

  /* The market picker is a row of eleven buttons. The rule above says every screen-only
     control goes, and this one was simply missed — on paper it is a legend for a selection
     nobody can change, above a table whose headings already name the markets it shows. */
  .wellhub-root .region-pick { display: none !important; }
}



/* ── Statistic icons ──────────────────────────────────────────────────────────
 * The payload gives every statistic the same icon in four colours. prepare.mjs puts all
 * four on the element as --ico-* and the theme picks one HERE, because the theme is a class
 * on an ancestor and only CSS can see it: the same statistic renders inside a magenta
 * chapter, again inside a green one, and again on the untinted Data page.
 *
 * A background, not an <img> — decorative, and a background that fails to load paints
 * nothing where a failed <img> paints a broken-image glyph. Only the variant selected below
 * is ever fetched.
 * ─────────────────────────────────────────────────────────────────────────── */
/* Icon beside the figure, not above it. The figure is 42px tall and the icon 34px, so the
   pair costs one line instead of two and the card loses a whole band of height — which
   compounds down a grid of them. `align-items: center` rather than baseline: the icon is a
   picture with no baseline of its own, and aligning its box edge to the figure's baseline
   hangs it low. */
.wellhub-root .statcard__top { display: flex; align-items: center; gap: 12px; }
.wellhub-root .statcard__icon {
  display: block; width: 34px; height: 34px; flex: none;
  background-repeat: no-repeat; background-position: left center; background-size: contain;
  /* Magenta by default. The Overview and Data pages carry no chapter theme and their accent
     is magenta, so the icon matches the page it is on rather than introducing a fourth
     colour nothing else uses. Swap to var(--ico-black) here if those pages should read
     neutral — one line, and the black variant is already on the element. */
  background-image: var(--ico-magenta);
}
.wellhub-root .theme-magenta .statcard__icon { background-image: var(--ico-magenta); }
.wellhub-root .theme-purple  .statcard__icon { background-image: var(--ico-purple); }
.wellhub-root .theme-green   .statcard__icon { background-image: var(--ico-green); }

/* In the margin the card is 240px of quiet note beside the prose, so the icon sits at the
   scale of the rule beside it rather than at the card's. */

/* ── Overview #1: the executive summary as a page ─────────────────────────────
 * A reading column, not a card grid: this page is one continuous piece of author's prose.
 * Narrower than the page's full width for the usual reason — a 1000px line is hard to
 * track back from — but wider than the deep dive's 70ch, because the summary is short and
 * carries full-width charts between its paragraphs.
 * ─────────────────────────────────────────────────────────────────────────── */
.wellhub-root .summary { max-width: 82ch; }
.wellhub-root .summary h2.doc {
  font-family: var(--font-display); font-weight: 800; font-size: 27px;
  letter-spacing: -0.008em; line-height: 1.15; color: var(--ink);
  margin: 44px 0 14px;
  /* Cleared by the sticky header when the sidebar jumps to it. Without this the heading
     lands underneath the header and the section looks like it starts mid-paragraph. */
  scroll-margin-top: calc(var(--header-h) + 24px);
}
.wellhub-root .summary h2.doc:first-child { margin-top: 0; }
.wellhub-root .summary h3.doc {
  font-family: var(--font-sans); font-weight: 700; font-size: 15px;
  letter-spacing: 0.02em; text-transform: uppercase; color: var(--accent-deep);
  margin: 30px 0 10px; scroll-margin-top: calc(var(--header-h) + 24px);
}
.wellhub-root .summary p.doc {
  font-family: var(--font-sans); font-size: 16.5px; line-height: 1.62;
  color: var(--ink-2); margin: 0 0 16px;
}
.wellhub-root .summary ul.doc, .wellhub-root .summary ol.doc {
  font-size: 16.5px; line-height: 1.62; color: var(--ink-2); margin: 0 0 16px; padding-left: 22px;
}
.wellhub-root .summary li { margin-bottom: 7px; }
.wellhub-root .summary .docchart { margin: 30px 0; width: 100%; }
/* Same stacked chartcard the Deep Dive uses, so a summary figure and its chapter twin
   cannot diverge in layout. */
.wellhub-root .summary blockquote.pull { margin: 26px 0; }

/* Same wrap-beside as Deep Dive. The customer asked for Executive Summary photos
   next to the prose, not stacked under it — `.reader .figure` never reached this page. */
.wellhub-root .summary .figure {
  float: left; width: 46%; margin: 6px 28px 18px 0;
  aspect-ratio: 4 / 3; overflow: hidden; background: var(--bg-2);
  border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.wellhub-root .summary .figure img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.wellhub-root .summary h2.doc,
.wellhub-root .summary h3.doc,
.wellhub-root .summary blockquote.pull,
.wellhub-root .summary .figure,
.wellhub-root .summary .imgph,
.wellhub-root .summary .docchart,
.wellhub-root .summary .statcard { clear: both; }
.wellhub-root .summary::after { content: ""; display: block; clear: both; }
@media (max-width: 760px) {
  .wellhub-root .summary .figure { float: none; width: 100%; margin: 26px 0; }
}

/* A chart with no data to draw: one column, so the text is not set beside an empty half.
   The record still has a title and an insight worth reading — dropping the card entirely
   would lose the author's point along with the missing chart. */

/* ── A typographic page title ─────────────────────────────────────────────────
 * For pages that are writing rather than dashboards. No panel, no gradient, no border —
 * the type sets the hierarchy and a rule closes it off, so the reader arrives at the first
 * paragraph rather than at a card.
 * ─────────────────────────────────────────────────────────────────────────── */
.wellhub-root .pagetitle {
  max-width: 82ch; margin: 0 0 clamp(28px, 3.4vw, 44px);
  padding-bottom: clamp(20px, 2.4vw, 28px); border-bottom: 1px solid var(--line);
}
.wellhub-root .pagetitle .eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--accent-deep); margin-bottom: 14px;
}
.wellhub-root .pagetitle .eyebrow::before {
  content: "✽"; font-size: 14px; line-height: 1; color: var(--accent-pink);
}
.wellhub-root .pagetitle h1 {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(32px, 4vw, 50px); line-height: 1.03; letter-spacing: -0.0105em;
  margin: 0; max-width: 20ch; color: var(--ink);
}
.wellhub-root .pagetitle__sub {
  font-family: var(--font-sans); font-size: clamp(16px, 1.5vw, 18.5px); line-height: 1.55;
  color: var(--ink-2); max-width: 56ch; margin: 14px 0 0;
}

.wellhub-root .kfgrid {
  display: grid; grid-template-columns: repeat(var(--kf-cols, 3), minmax(0, 1fr));
  gap: 18px; align-items: start;
}
/* The group is a heading and a stack of tiles, not a panel. It used to be one bordered
   card with the tiles divided by hairlines; separating them lets the ground show through
   between, which is what makes the block read as light. */
.wellhub-root .kfgroup {
  background: transparent; border: 0; box-shadow: none; border-radius: 0;
  overflow: visible; display: flex; flex-direction: column; gap: 10px;
}
/* The Deep Dive embeds this in a 70ch reading column; a phone has less again. Both cap the
   count rather than setting it, so a two-group report does not stretch to three. */
@media (max-width: 1180px) { .wellhub-root .kfgrid { grid-template-columns: repeat(min(var(--kf-cols, 3), 2), minmax(0, 1fr)); } }
@media (max-width: 700px)  { .wellhub-root .kfgrid { grid-template-columns: minmax(0, 1fr); } }
.wellhub-root .kfgroup__head {
  display: flex; align-items: center; gap: 10px;
  background: var(--accent-pink); border-radius: 14px; padding: 11px 15px;
  color: var(--accent-deep);
}
/* Brand pink with the deep magenta ink, measured at 5.86:1. The reference sets this title
   in white, which on any rose in this palette reaches 3.5:1 at best — and a 15px bold
   title is not WCAG "large text", so it needs 4.5:1. The fill matches; the ink cannot. */
.wellhub-root .kfgroup__icon,
.wellhub-root .kfgroup__glyph {
  width: 32px; height: 32px; flex: none; border-radius: 50%;
  /* Nearly white on the rose, so the mark inside reads as drawn on a disc rather than as a
     tint of the header behind it. */
  background-color: color-mix(in srgb, #fff 82%, transparent);
  display: grid; place-items: center;
  font-size: 14px; font-weight: 800; color: var(--accent-deep); line-height: 1;
}
.wellhub-root .kfgroup__icon {
  background-repeat: no-repeat; background-position: center; background-size: 19px 19px;
}
/* Default glyphs when the payload icon is null — a mark in the circle so the
   groups stay distinguishable without authored artwork. */
.wellhub-root .kfgroup__glyph--burnout::before { content: "✦"; }
.wellhub-root .kfgroup__glyph--security::before { content: "▣"; }
.wellhub-root .kfgroup__glyph--coping::before { content: "♡"; }
.wellhub-root .kfgroup__glyph--support::before { content: "●"; }
.wellhub-root .kfgroup__title {
  margin: 0; font-family: var(--font-display); font-weight: 800;
  font-size: 14.5px; letter-spacing: -0.003em; line-height: 1.2; color: var(--accent-deep);
}
.wellhub-root .kfgroup__cards { display: flex; flex-direction: column; gap: 10px; }
/* FIGURE LEFT, SENTENCE RIGHT. Stacked, each card cost the height of a 36px number plus
   its text and the groups ran long; side by side the figure and the words share one band,
   and the fixed first column lines every sentence in the group up on the same edge. */
.wellhub-root .kfcard {
  /* Fixed first column rather than auto, so every sentence in a group starts on the same
     edge; with `auto` the column would size to the widest figure in each card and the text
     would step in and out down the group. 78px carries "24%" at 30px. */
  display: grid; grid-template-columns: 78px minmax(0, 1fr); gap: 4px 14px;
  align-items: start;
  background: var(--bg-2); border: 0; border-top: 0; border-radius: 12px;
  padding: 13px 15px;
}
.wellhub-root .kfcard .val {
  grid-row: span 2;
  font-family: var(--font-display); font-weight: 800; font-size: 30px;
  letter-spacing: -0.008em; color: var(--accent-deep); line-height: 1.06;
  /* Centred in its column. Left-aligned, a two-character figure left a gap on its right
     that a three-character one did not, so the space between figure and sentence changed
     from card to card and the column read as ragged. */
  text-align: center;
}
/* A worded headline ("Nearly half") is not a figure and must not be set like one — it
   grows with the figure but stays clearly subordinate to it. */
.wellhub-root .kfcard .val.muted { font-size: 16px; line-height: 1.25; }
.wellhub-root .kfcard__stmt {
  margin: 0; font-size: 12.5px; line-height: 1.45; color: var(--ink);
}
/* The baseline continues the statement rather than annotating it, so it is set as the same
   sentence at the same size — quieter in colour only. */
.wellhub-root .kfcard__base {
  margin: 0; font-size: 12.5px; line-height: 1.45; color: var(--ink-2); font-style: normal;
}

/* ── Missing-support list ───────────────────────────────────────────────────── */
.wellhub-root .clist { display: flex; flex-direction: column; gap: 10px; }
.wellhub-root .clist__row {
  display: grid; grid-template-columns: 36px auto 1fr; gap: 12px;
  align-items: center; padding: 10px 4px;
  border-bottom: 1px solid var(--line);
}
.wellhub-root .clist__row:last-child { border-bottom: 0; }
.wellhub-root .clist__icon {
  width: 36px; height: 36px; border-radius: 50%; flex: none;
  background-color: var(--accent-soft);
  background-repeat: no-repeat; background-position: center; background-size: 20px 20px;
  box-shadow: inset 0 0 0 2px var(--accent);
}
.wellhub-root .clist__icon--on { background-image: var(--ico-magenta); }
.wellhub-root .theme-magenta .clist__icon--on { background-image: var(--ico-magenta); }
.wellhub-root .theme-purple .clist__icon--on { background-image: var(--ico-purple); }
.wellhub-root .theme-green .clist__icon--on { background-image: var(--ico-green); }
.wellhub-root .clist__val {
  font-family: var(--font-display); font-weight: 800; font-size: 22px;
  letter-spacing: -0.006em; color: var(--accent-figure); line-height: 1;
}
.wellhub-root .clist__copy {
  font-size: 14px; line-height: 1.4; color: var(--ink); min-width: 0;
}

/* ── Executive Summary cover ──────────────────────────────────────────────── */
.wellhub-root .summary-cover {
  margin: 0 0 22px; border-radius: var(--radius-lg); overflow: hidden;
  box-shadow: var(--shadow-md);
  aspect-ratio: 16 / 9; max-height: 420px; background: var(--bg-2);
}
.wellhub-root .summary-cover img {
  display: block; width: 100%; height: 100%; object-fit: cover;
}

