/* ═══════════════════════════════════════════════════════════════════════════
   PLATINUM-THEME  —  the site-wide unified design system  ·  "H27"
   ---------------------------------------------------------------------------
   WHAT THIS IS
   The homepage's H27 act-based design language, extracted verbatim from
   static/css/home-2027.css and promoted to a shared layer so that ALL pages —
   not just the homepage — can be built from the same vocabulary: acts, ghost
   act numerals, corner-bracket eyebrows, oversized display headlines, the
   sticky chapter rail, grounds + textures, cards, tabs, the journey line,
   voices, accordions, the closing CTA, photo backdrops and plates.

   Everything that was specific to the homepage's four bespoke artefacts — the
   hero and its stage, the OS planes, the Ask console, the product/dashboard
   stage, the module index and the relay — was deliberately left behind in
   home-2027.css. Nothing here references them.

   HOW IT LOADS
   Linked from templates/base_public.html for EVERY page, so brand-2026.css and
   ux-2027.css still load after it. Every rule is therefore scoped under `.h27`
   (two classes: `.h27 .h27-foo`) so it out-specifies those later layers without
   !important — !important appears only where the enforcement layer uses it too.

   The homepage additionally loads home-2027.css AFTER this file, from its own
   {% block extra_css %}, for its bespoke artefacts. The duplicate base rules in
   that file simply re-declare the same values, so the cascade is a no-op.

   MARKUP CONTRACT
   The page content must be wrapped in `<div class="h27">…</div>`. Without that
   wrapper not a single rule in this file matches.

   RULES IT KEEPS (non-negotiable brand):
     · palette locked — navy #0D1B3E · persimmon #E8593A · sky #3B86BC ·
       sage #7A9E8E, plus white and the ice ramp. No new hues, no warm stone.
       Persimmon stays <=10% of surface.
     · type: DM Serif Display owns H1/H2 (enforced by brand-2026.css) and the
       big numerals; Inter owns everything else.
     · eyebrows keep the Round-6 corner-bracket (viewfinder) standard.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ══ §0 · TOKENS ═════════════════════════════════════════════════════════ */

.h27 {
  /* ink ramp — deeper than the brand navy so the navy itself can sit on top
     of it as a raised plane */
  --h27-void:    #060C1E;
  --h27-ink:     #0A1330;
  --h27-navy:    #0D1B3E;
  --h27-navy-up: #14244F;

  /* accents (brand-locked) */
  --h27-coral:    #E8593A;
  --h27-coral-dk: #C94A2D;
  --h27-coral-lt: #FFAB96;
  --h27-sky:      #3B86BC;
  --h27-sky-lt:   #8BBEDD;   /* on-dark tint of sky — the ink ramp swallows #3B86BC */
  --h27-sage:     #7A9E8E;
  --h27-sage-lt:  #A9CFBE;   /* on-dark tint of sage, same reason */

  /* light surfaces — white + ice ramp only */
  --h27-paper: #FFFFFF;
  --h27-ice:   #F7FAFD;
  --h27-ice-2: #EDF4FB;
  --h27-hair:  #E3EAF2;

  /* text */
  --h27-body:  #2D2D3E;
  --h27-mute:  #5F718C;
  --h27-onink:      rgba(255,255,255,.78);
  --h27-onink-mute: rgba(255,255,255,.52);
  --h27-onink-hair: rgba(255,255,255,.13);

  /* display scale — the single biggest change from the old page */
  --h27-d0: clamp(32px, 4.7vw, 59px);   /* hero — client asked for a slightly smaller first-section headline (was 5.2vw/66px) */
  --h27-d1: clamp(30px, 4.3vw, 58px);    /* act headline — trimmed for a calmer, more professional section scale */
  --h27-d2: clamp(25px, 2.9vw, 39px);    /* sub headline */
  --h27-d3: clamp(20px, 1.9vw, 26px);    /* card headline */
  --h27-num: clamp(46px, 6.4vw, 92px);   /* number wall */

  /* rhythm */
  --h27-act:  clamp(76px, 9vw, 148px);   /* vertical act padding */
  --h27-gut:  clamp(20px, 4vw, 64px);    /* horizontal gutter */

  /* the OPENING act is not a mid-page band and must not be padded like one.
     It already sits below the 72px fixed header and carries the largest type
     on the page, so the full act pad reads as dead space above the eyebrow and
     a gap under the CTA row. Roughly half the mid-page rhythm, bottom-weighted
     so the hero still releases into the section under it. */
  --h27-act-1-top: clamp(40px, 4vw, 68px);
  --h27-act-1-bot: clamp(46px, 4.8vw, 84px);

  /* HERO RHYTHM — the vertical ladder inside the opening act's copy column.
     Every element in it (h1, .h27-lede, .h27-cta-row, .h27-chips) is reset to
     `margin: 0` by the site-wide `*` reset and by its own rule, so without
     these the lede sat flush against the headline and the button row flush
     against the lede — a 0px seam on every page of the site, and a measurably
     NEGATIVE one wherever the headline's 1.04 line-height pulls its last line
     box up under the lede's first (-0.7px to -3.2px across the module pages).

     The steps widen going down, matching the client-approved homepage hero
     (kicker 14 · h1 18 · sub 20 · CTA 30): the gaps are tightest where the
     type is largest and open up as it gets smaller, so the block reads as one
     falling column instead of four stacked pieces.

     The eyebrow is deliberately NOT in the ladder — `.h27-eyebrow` is shared
     with every act header on the site and keeps its own 18px margin-bottom.
     The floors below therefore start at 18 so the ladder never steps backwards
     under the eyebrow on a narrow screen: 18 · 22 · 29 · 33 at 1440,
     18 · 18 · 22 · 26 at 390. */
  --h27-hero-r1: clamp(18px, 1.5vw, 22px);   /* headline  → lede    */
  --h27-hero-r2: clamp(22px, 2vw,   29px);   /* lede/list → CTA row */
  --h27-hero-r3: clamp(26px, 2.3vw, 33px);   /* CTA row   → chips   */

  --h27-ease: cubic-bezier(.16, 1, .3, 1);
  --h27-out:  cubic-bezier(.22, .61, .36, 1);
}

/* ══ §1 · LAYOUT PRIMITIVES ══════════════════════════════════════════════ */

.h27 { position: relative; overflow-x: clip; }

/* the page rail — wider than the old 1140 container so the type can breathe */
.h27 .h27-edge {
  width: 100%;
  max-width: 1320px;
  margin-inline: auto;
  padding-inline: var(--h27-gut);
  position: relative;
  z-index: 2;
}
.h27 .h27-edge--tight { max-width: 1080px; }
.h27 .h27-edge--text  { max-width: 860px; }

/* ACT — the band. Dark acts stack against white ones for contrast swing. */
.h27 .h27-act {
  position: relative;
  padding-block: var(--h27-act);
  isolation: isolate;
}
/* FIRST ACT — every page opens with one (the hero bed on /module/*, the
   .h27-head hero on the rest), and it is the only act with the header above it
   instead of another band. It takes the tighter pair. `:first-of-type` is
   matched against <section>, so the preview banner the blog/article detail
   templates emit before the hero does not shift the match — and the homepage,
   whose first section is .h27-hero (its own viewport-height opener), is not
   matched at all. */
.h27 > .h27-act:first-of-type {
  padding-top: var(--h27-act-1-top);
  padding-bottom: var(--h27-act-1-bot);
}

/* ── the opening act's copy ladder ──────────────────────────────────────────
   Scoped to `.h27 > .h27-act:first-of-type` — the same selector the pad above
   uses — so it cannot reach a mid-page band. That matters: .m27-hero appears
   a second time further down billing, security, why-platinum and the three
   /solutions/* pages, and .h27-head is the act header on EVERY section of
   every page. Both keep their existing spacing outside the hero.

   Two hero beds are covered because the site only builds heroes two ways:
     .m27-hero  copy left, product/plate right — 29 pages. The whole ladder
                applies; the copy is one column, so all four seams are real.
     .h27-head  eyebrow + h1 left, lede + CTA right — 7 pages (legal, sitemap,
                blog, articles, testimonials, the two detail templates). Its
                grid `gap` already owns the h1→lede seam, so only the CTA and
                chips steps below can match there, which is what we want.

   The HOMEPAGE is untouched, for the same reason it is exempt from the act-1
   pad above: its opener is <section class="h27-hero">, which takes the
   `:first-of-type` slot without being an .h27-act, so nothing here can match
   anywhere on it. Its hero rhythm stays home-2027.css's. */
.h27 > .h27-act:first-of-type h1 + .h27-lede { margin-top: var(--h27-hero-r1); }

/* `:not(:first-child)` rather than `.h27-lede + …` on purpose — three pages
   put something between the lede and the buttons (pricing's "from $299" line,
   demo's checklist, the detail templates' byline) and each of those carries
   its own top margin already. Keying off position instead of the previous
   element's class gives all of them the same step into the CTA row. */
.h27 > .h27-act:first-of-type .h27-cta-row:not(:first-child) { margin-top: var(--h27-hero-r2); }
.h27 > .h27-act:first-of-type .h27-chips { margin-top: var(--h27-hero-r3); }

/* .h27-head carries a large bottom margin for its real job — separating an act
   header from the act's body. When it IS the hero and nothing follows it
   (legal, articles, testimonials, both detail templates) that margin lands on
   top of the act's own bottom pad and doubles the gap under the hero, which is
   why those pages opened with a visibly deeper bottom than top. */
.h27 > .h27-act:first-of-type .h27-edge > .h27-head:last-child { margin-bottom: 0; }

.h27 .h27-act--paper { background: var(--h27-paper); }
.h27 .h27-act--ice   { background: var(--h27-ice); }
.h27 .h27-act--ink   { background: var(--h27-ink); color: var(--h27-onink); }
.h27 .h27-act--void  { background: var(--h27-void); color: var(--h27-onink); }

.h27 .h27-act--ink h2,
.h27 .h27-act--void h2,
.h27 .h27-act--ink h3,
.h27 .h27-act--void h3 { color: #fff; }
.h27 .h27-act--ink p,
.h27 .h27-act--void p { color: var(--h27-onink); }

/* hairline seam between two same-tone acts */
.h27 .h27-seam {
  border: 0; height: 1px; margin: 0;
  background: var(--h27-hair);
}
.h27 .h27-act--ink + .h27-act--ink::before,
.h27 .h27-act--void + .h27-act--ink::before,
.h27 .h27-act--ink + .h27-act--void::before {
  content: ''; position: absolute; inset-inline: var(--h27-gut); top: 0; height: 1px;
  background: var(--h27-onink-hair);
}

/* ── atmosphere on dark acts: engineered grid + slow brand aurora + grain ── */
.h27 .h27-atm { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.h27 .h27-atm::before {
  content: ''; position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.045) 1px, transparent 1px);
  background-size: 72px 72px;
  mask-image: radial-gradient(80% 70% at 50% 30%, #000 0%, transparent 84%);
  -webkit-mask-image: radial-gradient(80% 70% at 50% 30%, #000 0%, transparent 84%);
}
.h27 .h27-atm::after {
  content: ''; position: absolute; inset: -20% -10%;
  opacity: .62; filter: blur(14px);
  background:
    none;
  animation: h27-drift 34s var(--h27-ease) infinite alternate;
}
@keyframes h27-drift {
  0%   { transform: translate3d(0,0,0) scale(1); }
  50%  { transform: translate3d(2.4%,-2%,0) scale(1.06); }
  100% { transform: translate3d(-2%,2.2%,0) scale(1.03); }
}
/* film grain — kills banding on the big navy planes */
.h27 .h27-grain {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  opacity: .35; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='.34'/%3E%3C/svg%3E");
}

/* ══ §2 · ACT HEADER — ghost numeral + eyebrow + oversized headline ══════ */

.h27 .h27-head {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, .82fr);
  gap: clamp(20px, 4vw, 72px);
  align-items: end;
  margin-bottom: clamp(38px, 5vw, 72px);
}
.h27 .h27-head--solo { grid-template-columns: minmax(0, 1fr); }
.h27 .h27-head--mid  { text-align: center; grid-template-columns: minmax(0,1fr); justify-items: center; }

/* the ghost act numeral — outlined, huge, parked behind the headline */
.h27 .h27-actno {
  position: absolute;
  top: clamp(-40px, -2.6vw, -14px);
  left: -.055em;
  z-index: -1;
  font-family: 'DM Serif Display', Georgia, serif;
  font-size: clamp(78px, 11.5vw, 184px);
  line-height: .8;
  letter-spacing: -.04em;
  color: transparent;
  -webkit-text-stroke: 1px rgba(13,27,62,.10);
  user-select: none;
  pointer-events: none;
}
.h27 .h27-act--ink .h27-actno,
.h27 .h27-act--void .h27-actno { -webkit-text-stroke-color: rgba(255,255,255,.10); }
.h27 .h27-head--mid .h27-actno { left: 50%; transform: translateX(-50%); }

/* eyebrow — Round-6 corner-bracket standard, rebuilt at this layer's scale */
.h27 .h27-eyebrow {
  position: relative;
  display: inline-block;
  /* As a direct grid child the eyebrow is blockified and would stretch, pulling
     its bottom-right corner tick out to the far edge of the column. */
  width: max-content; max-width: 100%;
  padding: 7px 14px;
  margin-bottom: 18px;
  font-family: 'Inter', -apple-system, sans-serif;
  font-size: 11px; font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--h27-navy);
}
.h27 .h27-eyebrow::before,
.h27 .h27-eyebrow::after {
  content: ''; position: absolute; width: 11px; height: 11px;
  border-style: solid; border-color: var(--h27-coral);
}
.h27 .h27-eyebrow::before { top: 0; left: 0;     border-width: 2px 0 0 2px; }
.h27 .h27-eyebrow::after  { bottom: 0; right: 0; border-width: 0 2px 2px 0; }
.h27 .h27-act--ink .h27-eyebrow,
.h27 .h27-act--void .h27-eyebrow { color: var(--h27-coral-lt); }
.h27 .h27-act--ink .h27-eyebrow::before, .h27 .h27-act--ink .h27-eyebrow::after,
.h27 .h27-act--void .h27-eyebrow::before, .h27 .h27-act--void .h27-eyebrow::after { border-color: var(--h27-coral-lt); }

/* the headline itself — the loudest single change on the page */
.h27 .h27-head h2,
.h27 h2.h27-h {
  font-size: var(--h27-d1);
  line-height: 1.02;
  letter-spacing: -.02em;
  color: var(--h27-navy);
  margin: 0;
  text-wrap: balance;
}
.h27 .h27-head p,
.h27 .h27-lede {
  font-size: clamp(16px, 1.15vw, 19px);
  line-height: 1.62;
  color: var(--h27-mute);
  max-width: 46ch;
  margin: 0;
}
/* Dark acts re-assert white on the headline/lede here — §1's `.h27-act--ink h2`
   ties with `.h27-head h2` on specificity and would lose on source order. */
.h27 .h27-act--ink .h27-head h2,
.h27 .h27-act--void .h27-head h2,
.h27 .h27-act--ink h2.h27-h,
.h27 .h27-act--void h2.h27-h { color: #fff; }
.h27 .h27-act--ink .h27-lede,
.h27 .h27-act--void .h27-lede,
.h27 .h27-act--ink .h27-head p,
.h27 .h27-act--void .h27-head p { color: var(--h27-onink); }

/* accent words inside a headline */
.h27 .h27-hl { color: var(--h27-coral); }
.h27 .h27-hl-s { color: var(--h27-sky); }
.h27 .h27-act--ink .h27-hl,
.h27 .h27-act--void .h27-hl { color: var(--h27-coral-lt); }
/* Underscored accent — a coral rule drawn under the phrase on reveal.
   Painted as a background rather than an ::after bar so it survives a line
   break: a display headline wraps, and an absolutely-positioned bar would
   both overflow the column and only underline one line. */
.h27 .h27-mark {
  background-image: linear-gradient(var(--h27-coral), var(--h27-coral));
  background-repeat: no-repeat;
  background-position: 0 calc(100% - .05em);
  background-size: 0% 3px;
  transition: background-size 900ms var(--h27-ease) 220ms;
  -webkit-box-decoration-break: clone;
          box-decoration-break: clone;
}
.h27 .x27-in .h27-mark,
.h27 .h27-mark.x27-in { background-size: 100% 3px; }

/* ══ §3 · BUTTONS — bigger, squarer, with a moving fill ══════════════════ */

.h27 .h27-btn {
  position: relative;
  display: inline-flex; align-items: center; gap: 10px;
  padding: 16px 28px;
  border: 0; border-radius: 4px;
  font-family: 'Inter', sans-serif;
  font-size: 15px; font-weight: 700; letter-spacing: -.005em;
  text-decoration: none; cursor: pointer;
  overflow: hidden; isolation: isolate;
  transition: transform 320ms var(--h27-ease), box-shadow 320ms var(--h27-ease), color 240ms linear;
}
.h27 .h27-btn > * { position: relative; z-index: 2; }
.h27 .h27-btn::before {
  content: ''; position: absolute; inset: 0; z-index: 1;
  transform: translateY(101%);
  transition: transform 460ms var(--h27-ease);
}
.h27 .h27-btn:hover { transform: translateY(-2px); }
.h27 .h27-btn:hover::before { transform: translateY(0); }
.h27 .h27-btn__a {
  display: inline-block;
  transition: transform 380ms var(--h27-ease);
}
.h27 .h27-btn:hover .h27-btn__a { transform: translateX(5px); }

.h27 .h27-btn--fill  { background: var(--h27-coral); color: #fff; box-shadow: 0 10px 30px rgba(232,89,58,.28); }
.h27 .h27-btn--fill::before { background: var(--h27-coral-dk); }
.h27 .h27-btn--fill:hover { box-shadow: 0 16px 40px rgba(232,89,58,.34); }

.h27 .h27-btn--line { background: transparent; color: var(--h27-navy); box-shadow: inset 0 0 0 1.5px rgba(13,27,62,.28); }
.h27 .h27-btn--line::before { background: var(--h27-navy); }
.h27 .h27-btn--line:hover { color: #fff; }

/* Every dark ground the outline button can land on. .h27-close is a band, not
   an act, so it has to be named here explicitly — without it the button keeps
   the light-mode navy-on-navy treatment and disappears. */
.h27 .h27-act--ink .h27-btn--line,
.h27 .h27-act--void .h27-btn--line,
.h27 .h27-close .h27-btn--line { color: #fff; box-shadow: inset 0 0 0 1.5px rgba(255,255,255,.34); }
.h27 .h27-act--ink .h27-btn--line::before,
.h27 .h27-act--void .h27-btn--line::before,
.h27 .h27-close .h27-btn--line::before { background: #fff; }
.h27 .h27-act--ink .h27-btn--line:hover,
.h27 .h27-act--void .h27-btn--line:hover,
.h27 .h27-close .h27-btn--line:hover { color: var(--h27-navy); }

/* quiet text link with a sliding rule */
.h27 .h27-link {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: 'Inter', sans-serif; font-size: 14px; font-weight: 700;
  color: var(--h27-sky); text-decoration: none;
  padding-bottom: 3px;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1.5px; background-position: 0 100%; background-repeat: no-repeat;
  transition: background-size 420ms var(--h27-ease);
}
.h27 .h27-link:hover { background-size: 100% 1.5px; }
.h27 .h27-act--ink .h27-link,
.h27 .h27-act--void .h27-link,
.h27 .h27-close .h27-link { color: var(--h27-coral-lt); }
/* a text link that is really a <button> — e.g. a "watch the tour" trigger */
.h27 button.h27-link { font-family: 'Inter', sans-serif; padding: 11px 0; }

.h27 .h27-cta-row { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 18px; }

/* ══ §5 · TICKER — clinic names, slim, dark ══════════════════════════════ */

.h27 .h27-ticker {
  background: var(--h27-void);
  border-top: 1px solid rgba(255,255,255,.10);
  border-bottom: 1px solid rgba(255,255,255,.10);
  padding: 18px 0;
  overflow: hidden;
  position: relative;
}
.h27 .h27-ticker::before,
.h27 .h27-ticker::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 16vw; z-index: 2; pointer-events: none;
}
.h27 .h27-ticker::before { left: 0;  background: none; }
.h27 .h27-ticker::after  { right: 0; background: none; }
.h27 .h27-ticker__track {
  display: flex; align-items: center; gap: clamp(28px, 4vw, 56px);
  width: max-content;
  animation: h27-scroll 46s linear infinite;
}
.h27 .h27-ticker:hover .h27-ticker__track { animation-play-state: paused; }
.h27 .h27-ticker__item {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: 'Inter', sans-serif;
  font-size: 13px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: rgba(255,255,255,.46);
  white-space: nowrap;
  transition: color 300ms var(--h27-ease);
}
.h27 .h27-ticker__item::before {
  content: ''; width: 5px; height: 5px; border-radius: 50%;
  background: var(--h27-coral); opacity: .7; flex: 0 0 auto;
}
.h27 .h27-ticker__item:hover { color: #fff; }
@keyframes h27-scroll { from { transform: translate3d(0,0,0); } to { transform: translate3d(-50%,0,0); } }

/* ══ §6 · SECTION INDEX — the sticky chapter rail ════════════════════════
   Every converted page carries one of these under the fixed header. It has
   three faces:

     · desktop — a chapter rail with a sliding marker whose coral tick fills
       with progress *through the lit section*, and edge chevrons that appear
       only on the side the rail can still scroll toward.
     · phone — the rail collapses into one compact picker button that opens a
       bottom sheet listing every section. A dozen chips behind a swipe is a
       list nobody reads; one tap to the whole list is.
     · sticking — the bar's height is identical free and stuck, deliberately.
       A condense-on-stick resizes a box that is still in flow, so the page
       below it jumps at the exact pixel it sticks, and on a trackpad that
       jump can bounce the bar in and out of its own stuck state.

   Two rules make the sticky work at all — (1) nothing between it and <body>
   may be a scroll container (see the overflow-x:clip note in styles.css), and
   (2) it is a child of `.h27`, whose box spans the whole page, so the sticky
   range covers every section.

   No page-progress line here on purpose — ux-2027.js §9 already puts a scroll
   beam at the top of the viewport, and a second one 72px below it reads as two
   competing indicators. The marker tick measures the section, not the page.

   theme-2027.js §2 owns .is-stuck / .is-spied / .has-pick, the data-of
   overflow state, the marker offsets, the section fill and the sheet — and on
   the homepage home-2027.js §2 does the same for its own copy of this CSS.  */

.h27 {
  --h27-idx-bg:       rgba(255,255,255,.86);
  --h27-idx-bg-stuck: rgba(255,255,255,.94);
  --h27-idx-hair:     var(--h27-hair);
  /* how far the cut edge of the rail dissolves. Wide enough to cover the edge
     chevron (30px at an 8px inset), or the button sits on top of a label that
     is still at full contrast and the two fight. */
  --h27-idx-fade:     46px;
}

.h27 .h27-index {
  position: sticky; z-index: 40;
  top: var(--header-height, 72px);
  background: var(--h27-idx-bg);
  -webkit-backdrop-filter: blur(20px) saturate(180%); backdrop-filter: blur(20px) saturate(180%);
  border-bottom: 1px solid var(--h27-idx-hair);
  transition: background 340ms var(--h27-ease), box-shadow 420ms var(--h27-ease),
              border-color 340ms var(--h27-ease);
}
/* stuck = the reader is inside the sequence: the bar lifts off the page so it
   reads as chrome over the sections rather than a band between them */
.h27 .h27-index.is-stuck {
  background: var(--h27-idx-bg-stuck);
  border-bottom-color: rgba(13,27,62,.10);
  box-shadow: 0 1px 0 rgba(13,27,62,.05), 0 14px 34px -22px rgba(13,27,62,.55);
}

.h27 .h27-index__wrap {
  position: relative;
  max-width: 1320px; margin-inline: auto;
}

.h27 .h27-index__inner {
  position: relative;
  display: flex; gap: 2px; align-items: stretch;
  padding-inline: var(--h27-gut);
  overflow-x: auto; overscroll-behavior-x: contain;
  scrollbar-width: none;
  scroll-behavior: smooth;
  /* kept on the rail as well as on __wrap: the script moves the rail into a
     wrap, but with JS off there is no wrap and the rail is still its own
     centred box. Inside a wrap of the same width the pair is a no-op. */
  max-width: 1320px; margin-inline: auto;
}
.h27 .h27-index__inner::-webkit-scrollbar { display: none; }

/* ── the sliding marker ────────────────────────────────────────────────────
   One element for every chapter, so the active state travels instead of
   blinking on and off. It rides the scroller's content box, which is exactly
   its containing block, so it stays put while the rail scrolls under it. */
.h27 .h27-index__marker {
  position: absolute; z-index: 0; pointer-events: none;
  top: 6px; bottom: 8px; left: 0; width: var(--h27-mw, 0px);
  border-radius: 12px;
  background: #fff;
  box-shadow: inset 0 0 0 1px rgba(13,27,62,.07),
              0 1px 1px rgba(13,27,62,.04),
              0 6px 16px -10px rgba(13,27,62,.5);
  opacity: 0;
  transform: translate3d(var(--h27-mx, 0px), 0, 0);
  transition: transform 560ms var(--h27-ease), width 560ms var(--h27-ease),
              opacity 260ms linear;
  will-change: transform, width;
}
.h27 .h27-index.is-spied .h27-index__marker { opacity: 1; }
/* The persimmon tick, landing on the bar's own bottom rule. Its coral half is
   how far the reader is through the lit section (--h27-mp, set per frame by
   the spy) — a hard gradient stop rather than a transform, so it can update
   every scroll frame without fighting the marker's own 560ms travel. */
.h27 .h27-index__marker::after {
  content: ''; position: absolute; left: 13px; right: 13px; bottom: -8px; height: 2px;
  border-radius: 2px 2px 0 0;
  background: linear-gradient(90deg,
              var(--h27-coral) var(--h27-mp, 100%),
              rgba(232,89,58,.22) var(--h27-mp, 100%));
}

.h27 .h27-index a {
  position: relative; z-index: 1;
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 15px 14px;
  font-family: 'Inter', sans-serif;
  font-size: 12.5px; font-weight: 600; letter-spacing: -.005em;
  color: var(--h27-mute); text-decoration: none;
  white-space: nowrap;
  border-radius: 12px;
  transition: color 260ms var(--h27-ease), background 220ms var(--h27-ease);
}
.h27 .h27-index a em {
  font-style: normal;
  font-variant-numeric: tabular-nums;
  font-size: 10px; font-weight: 800; letter-spacing: .08em;
  color: var(--h27-mute);          /* §25a: rgba(13,27,62,.34) was 2.13:1 */
  transition: color 260ms var(--h27-ease);
}
.h27 .h27-index a:hover { color: var(--h27-navy); background: rgba(13,27,62,.035); }
.h27 .h27-index a:hover em { color: var(--h27-body); }
.h27 .h27-index a.is-active:hover { background: transparent; }
.h27 .h27-index a:focus-visible {
  outline: 2px solid var(--h27-coral); outline-offset: -3px;
}
.h27 .h27-index a.is-active { color: var(--h27-navy); }
.h27 .h27-index a.is-active em { color: var(--h27-navy); }

/* ── overflow affordances ──────────────────────────────────────────────────
   data-of carries which way the rail can still travel ("l", "r" or "lr"), so
   the fade and the chevron only ever appear on a side that has something
   behind it. A permanent fade on a rail that fits reads as a rendering bug. */
.h27 .h27-index[data-of~="l"] .h27-index__inner {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--h27-idx-fade), #000 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 var(--h27-idx-fade), #000 100%);
}
.h27 .h27-index[data-of~="r"] .h27-index__inner {
  -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - var(--h27-idx-fade)), transparent 100%);
          mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - var(--h27-idx-fade)), transparent 100%);
}
.h27 .h27-index[data-of~="l"][data-of~="r"] .h27-index__inner {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--h27-idx-fade),
                      #000 calc(100% - var(--h27-idx-fade)), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 var(--h27-idx-fade),
                      #000 calc(100% - var(--h27-idx-fade)), transparent 100%);
}

.h27 .h27-index__edge {
  position: absolute; top: 50%; z-index: 3;
  width: 30px; height: 30px; margin-top: -15px; padding: 0;
  display: grid; place-items: center;
  border: 0; border-radius: 50%; cursor: pointer;
  color: var(--h27-navy);
  background: rgba(255,255,255,.94);
  box-shadow: inset 0 0 0 1px rgba(13,27,62,.08), 0 4px 14px -6px rgba(13,27,62,.45);
  opacity: 0; visibility: hidden; transform: scale(.82);
  transition: opacity 220ms var(--h27-ease), transform 280ms var(--h27-ease),
              visibility 0s linear 220ms, background 200ms linear;
}
.h27 .h27-index__edge--l { left: 8px; }
.h27 .h27-index__edge--r { right: 8px; }
.h27 .h27-index[data-of~="l"] .h27-index__edge--l,
.h27 .h27-index[data-of~="r"] .h27-index__edge--r {
  opacity: 1; visibility: visible; transform: scale(1); transition-delay: 0s;
}
.h27 .h27-index__edge:hover { background: #fff; }
.h27 .h27-index__edge:active { transform: scale(.92); }
.h27 .h27-index__edge:focus-visible { outline: 2px solid var(--h27-coral); outline-offset: 2px; }
.h27 .h27-index__edge svg { width: 15px; height: 15px; }

/* ── the phone picker ──────────────────────────────────────────────────────
   .has-pick is set by the script, so with JS off the rail simply stays a rail
   and the page keeps a working table of contents. */
.h27 .h27-index__pick {
  display: none;   /* -> flex inside the phone breakpoint, once .has-pick is on */
  width: 100%; padding: 11px var(--h27-gut); border: 0; background: transparent;
  align-items: center; gap: 11px; cursor: pointer; text-align: left;
  font-family: 'Inter', sans-serif; color: var(--h27-navy);
  -webkit-tap-highlight-color: transparent;
}
.h27 .h27-index__pick:focus-visible { outline: 2px solid var(--h27-coral); outline-offset: -3px; }
.h27 .h27-index__pick:active { background: rgba(13,27,62,.03); }
/* the number sits in a ring that fills with page position — the phone's
   equivalent of the desktop marker tick */
.h27 .h27-index__dial {
  position: relative; flex: 0 0 auto;
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  background: conic-gradient(var(--h27-coral) var(--h27-pp, 0%), rgba(13,27,62,.11) 0);
}
.h27 .h27-index__dial::before {
  content: ''; position: absolute; inset: 2.5px; border-radius: 50%; background: #fff;
}
.h27 .h27-index__dial em {
  position: relative; font-style: normal;
  font-size: 10.5px; font-weight: 800; letter-spacing: .02em;
  font-variant-numeric: tabular-nums; color: var(--h27-navy);
}
.h27 .h27-index__pickmain { min-width: 0; flex: 1 1 auto; }
.h27 .h27-index__picklabel {
  display: block; font-size: 13.5px; font-weight: 650; letter-spacing: -.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.h27 .h27-index__pickmeta {
  display: block; margin-top: 1px;
  font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--h27-mute);
}
.h27 .h27-index__pickchev {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center; color: var(--h27-mute);
  background: rgba(13,27,62,.05);
}
.h27 .h27-index__pickchev svg { width: 14px; height: 14px; }

@media (max-width: 760px) {
  .h27 .h27-index.has-pick .h27-index__inner,
  .h27 .h27-index.has-pick .h27-index__edge { display: none; }
  .h27 .h27-index.has-pick .h27-index__pick { display: flex; }
}
@media (max-width: 640px) {
  .h27 .h27-index a { padding: 13px 11px; font-size: 12px; gap: 6px; }
  .h27 .h27-index__marker { top: 5px; bottom: 7px; }
  .h27 .h27-index__marker::after { left: 10px; right: 10px; bottom: -7px; }
}

/* ── the chapter sheet ─────────────────────────────────────────────────────
   Lives on <body>, not inside the bar: the bar carries a backdrop-filter,
   which makes it a containing block for fixed descendants, so a sheet nested
   inside it would be pinned to the bar instead of the viewport. */
.h27-idxsheet {
  position: fixed; inset: 0;
  /* over the chat widget and the scroll beams, both of which sit at 9999 — it
     is a modal, so nothing may float in front of it or stay tappable behind */
  z-index: 10010;
  display: flex; flex-direction: column; justify-content: flex-end;
}
.h27-idxsheet[hidden] { display: none; }
.h27-idxsheet__scrim {
  position: absolute; inset: 0;
  background: rgba(9,17,38,.42);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  opacity: 0; transition: opacity 280ms cubic-bezier(.16,1,.3,1);
}
.h27-idxsheet__panel {
  position: relative;
  max-height: min(72vh, 620px);
  display: flex; flex-direction: column;
  background: #fff;
  border-radius: 22px 22px 0 0;
  box-shadow: 0 -18px 60px -20px rgba(9,17,38,.55);
  padding: 8px 0 max(10px, env(safe-area-inset-bottom));
  transform: translate3d(0, 100%, 0);
  transition: transform 380ms cubic-bezier(.16,1,.3,1);
}
/* the panel takes focus on open so the dialog is announced and Shift+Tab has
   somewhere to wrap from; it is a container, not a control, so it gets no ring */
.h27-idxsheet__panel:focus,
.h27-idxsheet__panel:focus-visible { outline: none; }
.h27-idxsheet.is-open .h27-idxsheet__scrim { opacity: 1; }
.h27-idxsheet.is-open .h27-idxsheet__panel { transform: translate3d(0,0,0); }

.h27-idxsheet__grip {
  width: 38px; height: 4px; border-radius: 4px; margin: 4px auto 10px;
  background: rgba(13,27,62,.16);
}
.h27-idxsheet__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; padding: 0 20px 10px;
  border-bottom: 1px solid var(--h27-hair, #E3EAF2);
}
.h27-idxsheet__title {
  margin: 0; font-family: 'Inter', sans-serif;
  font-size: 11px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--h27-mute, #5F718C);
}
.h27-idxsheet__count {
  font-family: 'Inter', sans-serif; font-size: 11px; font-weight: 700;
  font-variant-numeric: tabular-nums; color: var(--h27-mute, #5F718C);
}
.h27-idxsheet__list {
  /* min-height:0 or the flex item refuses to shrink and the list runs off the
     bottom of the panel instead of scrolling inside it */
  min-height: 0;
  overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
  padding: 6px 10px 4px;
}
.h27-idxsheet__row {
  display: flex; align-items: center; gap: 13px;
  padding: 12px 12px; border-radius: 13px;
  font-family: 'Inter', sans-serif; font-size: 14.5px; font-weight: 600;
  letter-spacing: -.01em; color: var(--h27-navy, #0D1B3E); text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.h27-idxsheet__row em {
  flex: 0 0 auto; min-width: 27px; height: 27px; padding: 0 5px; border-radius: 9px;
  display: grid; place-items: center;
  font-style: normal; font-size: 10.5px; font-weight: 800; letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
  background: rgba(13,27,62,.055); color: var(--h27-mute, #5F718C);
  transition: background 200ms linear, color 200ms linear;
}
.h27-idxsheet__row span { flex: 1 1 auto; }
.h27-idxsheet__row svg { flex: 0 0 auto; width: 17px; height: 17px; color: var(--h27-coral, #E8593A); opacity: 0; }
.h27-idxsheet__row:active { background: rgba(13,27,62,.04); }
.h27-idxsheet__row.is-active { background: rgba(232,89,58,.07); }
.h27-idxsheet__row.is-active em { background: var(--h27-coral, #E8593A); color: #fff; }
.h27-idxsheet__row.is-active svg { opacity: 1; }
.h27-idxsheet__row:focus-visible { outline: 2px solid var(--h27-coral, #E8593A); outline-offset: -2px; }

/* same lock the mobile menu uses in main.js §6, as a class so the two never
   overwrite each other's inline style */
body.h27-idxsheet-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .h27 .h27-index__marker,
  .h27 .h27-index__edge { transition: opacity 160ms linear, visibility 0s; }
  .h27 .h27-index__inner { scroll-behavior: auto; }
  .h27-idxsheet__panel, .h27-idxsheet__scrim { transition: none; }
}

/* Landing offset for *browser-driven* fragment navigation — opening the page on
   a #hash, or a link to a chapter from elsewhere. Those land via html's
   scroll-padding-top, which ux-2027.css already sets to header + the 16px
   default --x27-anchor-pad = 88px; this margin adds the rest of the bar's 52px
   so the chapter clears it rather than sitting behind it. Clicks on the rail
   itself never take this path — main.js §10 preventDefaults every in-page
   anchor, so home-2027.js §2 scrolls those to a measured position instead. */
.h27 .x27-anchor { scroll-margin-top: 46px; }

/* ══ §7 · ACT 01 · THE PROBLEM — the big five-versus-one split ═══════════ */

.h27 .h27-split {
  display: grid;
  grid-template-columns: minmax(0,1fr) minmax(0,1fr);
  border-top: 1px solid var(--h27-hair);
  border-bottom: 1px solid var(--h27-hair);
}
.h27 .h27-split__side {
  position: relative;
  padding: clamp(30px, 3.4vw, 52px) clamp(22px, 3vw, 48px) clamp(34px, 4vw, 56px);
  border-left: 1px solid var(--h27-hair);
  transition: background 520ms var(--h27-ease);
}
.h27 .h27-split__side:first-child { border-left: 0; }
.h27 .h27-split__side--now:hover  { background: rgba(13,27,62,.025); }
.h27 .h27-split__side--new { background: var(--h27-ink); color: #fff; }
.h27 .h27-split__side--new::before {
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .5;
  background: none;
}
.h27 .h27-split__side--new > * { position: relative; z-index: 1; }

/* the giant counter numeral that carries the argument */
.h27 .h27-bignum {
  display: flex; align-items: baseline; gap: 14px;
  margin-bottom: 20px;
}
.h27 .h27-bignum b {
  font-family: 'DM Serif Display', Georgia, serif; font-weight: 400;
  font-size: clamp(64px, 9vw, 132px);
  line-height: .82; letter-spacing: -.045em;
  color: var(--h27-navy);
}
.h27 .h27-split__side--new .h27-bignum b { color: var(--h27-coral-lt); }
.h27 .h27-bignum span {
  font-family: 'Inter', sans-serif;
  font-size: clamp(13px, 1.1vw, 16px); font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--h27-mute);
  max-width: 17ch; line-height: 1.35;
}
.h27 .h27-split__side--new .h27-bignum span { color: var(--h27-onink-mute); }

.h27 .h27-split__tag {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: 'Inter', sans-serif;
  font-size: 11px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: var(--h27-mute);
  margin-bottom: 18px;
}
.h27 .h27-split__side--new .h27-split__tag { color: var(--h27-coral-lt); }
.h27 .h27-split__side p {
  font-size: clamp(15px, 1.1vw, 17px); line-height: 1.72;
  color: var(--h27-body); margin: 0;
  max-width: 44ch;
}
.h27 .h27-split__side--new p { color: var(--h27-onink); }

/* the stack of broken tools vs the single platform */
.h27 .h27-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 24px; }
.h27 .h27-chip {
  font-family: 'Inter', sans-serif;
  font-size: 12px; font-weight: 600;
  padding: 7px 13px; border-radius: 3px;
  color: var(--h27-mute);
  box-shadow: inset 0 0 0 1px var(--h27-hair);
  background: #fff;
}
.h27 .h27-chip--dead { text-decoration: line-through; opacity: .68; }
.h27 .h27-split__side--new .h27-chip {
  background: rgba(255,255,255,.06); color: #fff;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.18);
}

/* the calculator strip beneath the split */
.h27 .h27-strip {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 18px 28px;
  padding: 26px clamp(22px, 3vw, 48px);
  border: 1px solid var(--h27-hair);
  border-top: 0;
  background: var(--h27-ice);
}
.h27 .h27-strip p {
  margin: 0; font-family: 'Inter', sans-serif;
  font-size: clamp(15px, 1.2vw, 18px); font-weight: 600; color: var(--h27-navy);
}
/* same footing on an ink band — Act 02 closes the way Act 01 does */
.h27 .h27-strip--ink {
  border-color: rgba(255,255,255,.13);
  background: rgba(255,255,255,.035);
  position: relative; z-index: 1;
}
.h27 .h27-strip--ink p { color: #fff; }

/* ══ §12 · NUMBER WALL — the proof act ═══════════════════════════════════ */

.h27 .h27-wall {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-top: 1px solid var(--h27-onink-hair);
  border-left: 1px solid var(--h27-onink-hair);
}
/* four-up variant (the "one journey" proof row) — declared after the base so
   it wins the equal-specificity tie */
.h27 .h27-wall--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.h27 .h27-wall--4 .h27-wall__num { font-size: clamp(38px, 4.6vw, 66px); }
.h27 .h27-act--paper .h27-wall,
.h27 .h27-act--ice .h27-wall { border-top-color: var(--h27-hair); border-left-color: var(--h27-hair); }
.h27 .h27-wall__cell {
  position: relative;
  padding: clamp(20px, 2.1vw, 30px) clamp(18px, 2vw, 32px);
  border-right: 1px solid var(--h27-onink-hair);
  border-bottom: 1px solid var(--h27-onink-hair);
  overflow: hidden;
  transition: background 460ms var(--h27-ease);
}
.h27 .h27-act--paper .h27-wall__cell,
.h27 .h27-act--ice .h27-wall__cell { border-right-color: var(--h27-hair); border-bottom-color: var(--h27-hair); }
.h27 .h27-wall__cell:hover { background: rgba(255,255,255,.04); }
.h27 .h27-act--paper .h27-wall__cell:hover { background: var(--h27-ice); }
.h27 .h27-wall__cell::after {
  content: ''; position: absolute; left: 0; bottom: 0; height: 2px; width: 100%;
  background: var(--h27-coral);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 1100ms var(--h27-ease) 200ms;
}
.h27 .h27-wall__cell.x27-in::after { transform: scaleX(var(--h27-fill, .5)); }
.h27 .h27-wall__num {
  font-family: 'DM Serif Display', Georgia, serif !important; font-weight: 400;
  font-size: var(--h27-num);
  line-height: .88; letter-spacing: -.035em;
  color: #fff; margin-bottom: 10px;
}
.h27 .h27-act--paper .h27-wall__num,
.h27 .h27-act--ice .h27-wall__num { color: var(--h27-navy); }
.h27 .h27-wall__cell--coral .h27-wall__num { color: var(--h27-coral-lt); }
.h27 .h27-act--paper .h27-wall__cell--coral .h27-wall__num { color: var(--h27-coral); }
.h27 .h27-wall__lbl {
  font-family: 'Inter', sans-serif;
  font-size: 13.5px; line-height: 1.5; font-weight: 500;
  color: var(--h27-onink-mute);
  max-width: 26ch;
}
.h27 .h27-act--paper .h27-wall__lbl,
.h27 .h27-act--ice .h27-wall__lbl { color: var(--h27-mute); }

/* ══ §13 · GIANT MARQUEE — integrations, at display scale ════════════════ */

.h27 .h27-bigrun {
  position: relative;
  padding: clamp(13px, 1.5vw, 19px) 0;
  overflow: hidden;
  border-top: 1px solid var(--h27-onink-hair);
  border-bottom: 1px solid var(--h27-onink-hair);
}
.h27 .h27-bigrun__track {
  display: flex; align-items: center; gap: clamp(18px, 2vw, 30px);
  width: max-content;
  animation: h27-scroll 52s linear infinite;
}
.h27 .h27-bigrun__track--rev { animation-direction: reverse; animation-duration: 62s; }
.h27 .h27-bigrun:hover .h27-bigrun__track { animation-play-state: paused; }
.h27 .h27-bigrun__item {
  font-family: 'Inter', sans-serif;
  font-size: clamp(13px, 1.05vw, 16px);
  font-weight: 600;
  line-height: 1.3; letter-spacing: .005em;
  color: rgba(255,255,255,.42);
  white-space: nowrap;
  transition: color 340ms var(--h27-ease);
}
.h27 .h27-bigrun__item:hover { color: #fff; }
.h27 .h27-bigrun__sep {
  flex: 0 0 auto; width: 4px; height: 4px; border-radius: 50%;
  background: var(--h27-coral); opacity: .75;
}

/* ══ §14 · CARDS — one card language for the whole page ══════════════════ */

.h27 .h27-grid { display: grid; gap: clamp(14px, 1.6vw, 22px); }
.h27 .h27-grid--2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
.h27 .h27-grid--3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
.h27 .h27-grid--4 { grid-template-columns: repeat(4, minmax(0,1fr)); }
.h27 .h27-span-2 { grid-column: span 2; }
.h27 .h27-span-3 { grid-column: span 3; }

.h27 .h27-card {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column;
  padding: clamp(24px, 2.4vw, 34px);
  border-radius: 6px;
  background: var(--h27-paper);
  box-shadow: inset 0 0 0 1px var(--h27-hair);
  text-decoration: none;
  transition: transform 460ms var(--h27-ease), box-shadow 460ms var(--h27-ease);
}
.h27 .h27-card:hover { transform: translateY(-6px); box-shadow: inset 0 0 0 1px rgba(13,27,62,.16), 0 22px 54px rgba(13,27,62,.12); }
.h27 .h27-card::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: var(--h27-coral);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 520ms var(--h27-ease);
}
.h27 .h27-card:hover::before { transform: scaleX(1); }
.h27 .h27-card h3 {
  font-family: 'Inter', sans-serif !important;
  font-size: var(--h27-d3); font-weight: 700; line-height: 1.16; letter-spacing: -.02em;
  color: var(--h27-navy); margin: 0 0 10px;
}
.h27 .h27-card p {
  font-size: 14.5px; line-height: 1.66; color: var(--h27-mute); margin: 0 0 16px;
}
.h27 .h27-card__foot { margin-top: auto; }
.h27 .h27-card__eyebrow {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px; font-weight: 800; letter-spacing: .13em; text-transform: uppercase;
  color: var(--h27-coral); margin-bottom: 14px;
}
.h27 .h27-card__ico {
  width: 46px; height: 46px; border-radius: 8px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--h27-ice-2);
  margin-bottom: 18px;
  transition: transform 460ms var(--h27-out), background 360ms var(--h27-ease);
}
.h27 .h27-card__ico svg { width: 22px; height: 22px; color: var(--h27-navy); stroke: var(--h27-navy); }
.h27 .h27-card:hover .h27-card__ico { transform: translateY(-3px) rotate(-4deg); }

/* dark card variant — one per grid, the lead */
.h27 .h27-card--ink {
  background: var(--h27-navy-up);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.1);
}
.h27 .h27-card--ink h3 { color: #fff; }
.h27 .h27-card--ink p  { color: var(--h27-onink); }
.h27 .h27-card--ink .h27-card__eyebrow { color: var(--h27-coral-lt); }
.h27 .h27-card--ink .h27-card__ico { background: rgba(255,255,255,.1); }
.h27 .h27-card--ink .h27-card__ico svg { color: #fff; stroke: #fff; }
.h27 .h27-card--ink:hover { box-shadow: inset 0 0 0 1px rgba(255,255,255,.2), 0 26px 60px rgba(0,0,0,.34); }
.h27 .h27-card--ink .h27-link { color: var(--h27-coral-lt); }

/* glass card — for dark acts where a solid white card would punch a hole */
.h27 .h27-card--glass {
  background: rgba(255,255,255,.08);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.12);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.h27 .h27-card--glass h3 { color: #fff; }
.h27 .h27-card--glass p  { color: var(--h27-onink); }
.h27 .h27-card--glass .h27-card__eyebrow { color: var(--h27-coral-lt); }
.h27 .h27-card--glass .h27-card__ico { background: rgba(255,255,255,.1); }
.h27 .h27-card--glass .h27-card__ico svg { color: #fff; stroke: #fff; }
.h27 .h27-card--glass .h27-card__arrow { color: #fff; }
.h27 .h27-card--glass:hover { box-shadow: inset 0 0 0 1px rgba(255,255,255,.24), 0 26px 60px rgba(0,0,0,.4); }

/* the arrow that lives at a card's bottom edge */
.h27 .h27-card__arrow {
  margin-top: auto; padding-top: 20px;
  font-size: 20px; line-height: 1; color: var(--h27-navy);
  transition: transform 420ms var(--h27-ease), color 300ms var(--h27-ease);
}
.h27 .h27-card--ink .h27-card__arrow { color: #fff; }
.h27 .h27-card:hover .h27-card__arrow { transform: translateX(8px); color: var(--h27-coral); }

/* ══ §15 · TABS (practice size) ══════════════════════════════════════════ */

.h27 .h27-tabs { display: flex; flex-wrap: wrap; gap: 0; border-bottom: 1px solid var(--h27-hair); margin-bottom: 0; }
.h27 .h27-tabs button {
  position: relative;
  padding: 16px 24px 16px 0; margin-right: 28px;
  border: 0; background: none; cursor: pointer;
  font-family: 'Inter', sans-serif;
  font-size: clamp(15px, 1.3vw, 19px); font-weight: 600; letter-spacing: -.015em;
  color: var(--h27-mute);
  transition: color 300ms var(--h27-ease);
}
.h27 .h27-tabs button::after {
  content: ''; position: absolute; left: 0; right: 24px; bottom: -1px; height: 2px;
  background: var(--h27-coral);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 420ms var(--h27-ease);
}
.h27 .h27-tabs button:hover { color: var(--h27-navy); }
.h27 .h27-tabs button[aria-selected="true"] { color: var(--h27-navy); }
.h27 .h27-tabs button[aria-selected="true"]::after { transform: scaleX(1); }

.h27 .h27-tabpanel { display: none; padding-top: clamp(24px, 3vw, 40px); }
.h27 .h27-tabpanel.is-active { display: block; animation: h27-panel 560ms var(--h27-ease) both; }
/* the panel's entrance. In home-2027.css these frames lived down in the module
   index (§10) — a homepage-only block — so they are re-declared here beside the
   one generic component that depends on them. */
@keyframes h27-panel {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
.h27 .h27-tabpanel p {
  font-size: clamp(17px, 1.5vw, 23px); line-height: 1.6; color: var(--h27-body);
  max-width: 60ch; margin: 0 0 24px;
}

/* pill row (roles) */
.h27 .h27-pills { display: flex; flex-wrap: wrap; gap: 8px; }
.h27 .h27-pills a {
  font-family: 'Inter', sans-serif;
  font-size: 13px; font-weight: 600;
  padding: 10px 18px; border-radius: 999px;
  color: var(--h27-navy); text-decoration: none;
  box-shadow: inset 0 0 0 1px var(--h27-hair);
  transition: background 300ms var(--h27-ease), color 300ms var(--h27-ease), box-shadow 300ms var(--h27-ease);
}
.h27 .h27-pills a:hover { background: var(--h27-navy); color: #fff; box-shadow: inset 0 0 0 1px var(--h27-navy); }

/* ══ §16 · JOURNEY (migration) — a scroll-driven station line ════════════
   The old block was five flat columns under a static rule. The rollout is a
   sequence, so it is drawn as one: ONE line across the act with five stations
   standing on it. home-2027.js §10 maps the reader's scroll position through
   the block onto --jrn-p (0..1) — the persimmon fill runs to that point, a lit
   head travels with it, and each station lights the moment the line reaches it.

   The line deliberately runs past station 05 and fades out: the last step is
   "optimize as you go", so the journey should not visibly terminate.

   DEGRADATION follows the same contract as §11 and §20 — every default here is
   the FINISHED state, and the unlit states are armed only under `.is-live`,
   which the script adds after it has taken over. No script, an exception, or
   reduced motion all leave a fully drawn line with every station lit.

   Below 1024px the same component turns 90°: the rule becomes a left spine and
   the stations stack down it. No markup changes — the script picks the axis off
   the rail's own box. */

.h27 .h27-jrn {
  --jrn-p: 1;                                    /* scroll progress, 0..1 */
  --jrn-node: 42px;
  --jrn-line: calc(var(--jrn-node) / 2);         /* centre of the station row */
  position: relative;
  margin-top: clamp(30px, 3.6vw, 52px);
}

/* ── the line ─────────────────────────────────────────────────────────── */
.h27 .h27-jrn__rail {
  position: absolute; z-index: 0;
  left: 0; right: 0; top: calc(var(--jrn-line) - 1px);
  height: 2px; border-radius: 2px;
  background: var(--h27-hair);
  -webkit-mask-image: linear-gradient(90deg, #000 86%, transparent);
          mask-image: linear-gradient(90deg, #000 86%, transparent);
}
.h27 .h27-jrn__fill {
  position: absolute; inset: 0; border-radius: inherit;
  background: var(--h27-coral-dk);
  transform: scaleX(var(--jrn-p)); transform-origin: 0 50%;
  transition: transform 280ms var(--h27-out);
  will-change: transform;
}
/* the head of the line — sits outside the rail so the fade mask never eats it */
.h27 .h27-jrn__spark {
  position: absolute; z-index: 1;
  top: var(--jrn-line); left: calc(var(--jrn-p) * 100%);
  width: 8px; height: 8px; margin: -4px 0 0 -4px;
  border-radius: 50%;
  background: var(--h27-coral);
  box-shadow: 0 0 0 4px rgba(232,89,58,.13), 0 0 14px 2px rgba(232,89,58,.38);
  opacity: 0;
  transition: left 280ms var(--h27-out), top 280ms var(--h27-out), opacity 420ms var(--h27-ease);
}
/* It dissolves into the same tail the rail's mask fades out, so the head never
   floats detached past the end of the line. */
.h27 .h27-jrn.is-live .h27-jrn__spark { opacity: clamp(0, calc((0.94 - var(--jrn-p)) / 0.1), 1); }

/* ── the stations ─────────────────────────────────────────────────────── */
.h27 .h27-jrn__list {
  position: relative; z-index: 2;
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  column-gap: clamp(16px, 2vw, 30px);
}
.h27 .h27-jrn__step { position: relative; padding-right: clamp(4px, 1vw, 16px); }

/* station — opaque, so it punches a clean hole through the line. Nothing else
   is allowed on the line's row: a numeral sitting on the rule reads as struck
   through, so the numeral stacks under the station instead. */
.h27 .h27-jrn__node {
  position: relative; flex: none;
  margin-bottom: clamp(16px, 1.7vw, 24px);
  width: var(--jrn-node); height: var(--jrn-node);
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--h27-navy); color: #fff;
  box-shadow: inset 0 0 0 1.5px var(--h27-navy), 0 10px 22px -12px rgba(13,27,62,.6);
  transition: background 460ms var(--h27-ease), color 460ms var(--h27-ease),
              box-shadow 460ms var(--h27-ease), transform 560ms var(--h27-ease),
              opacity 340ms var(--h27-ease);
}
.h27 .h27-jrn__node .ico { font-size: 19px; width: 19px; height: 19px; }

/* the one station the line is standing on right now */
.h27 .h27-jrn__step.is-head .h27-jrn__node::after {
  content: ''; position: absolute; inset: -1px; border-radius: 50%;
  animation: h27JrnPulse 2.6s var(--h27-ease) infinite;
}
@keyframes h27JrnPulse {
  0%   { box-shadow: 0 0 0 0 rgba(232,89,58,.42); }
  72%  { box-shadow: 0 0 0 13px rgba(232,89,58,0); }
  100% { box-shadow: 0 0 0 0 rgba(232,89,58,0); }
}

.h27 .h27-jrn__no {
  display: block;
  font-family: 'DM Serif Display', Georgia, serif;
  font-size: clamp(28px, 3vw, 42px); line-height: 1; letter-spacing: -.03em;
  color: rgba(13,27,62,.32);
  margin-bottom: clamp(10px, 1.1vw, 14px);
  transition: color 480ms var(--h27-ease), opacity 340ms var(--h27-ease);
}

.h27 .h27-jrn__body { transition: opacity 340ms var(--h27-ease); }
.h27 .h27-jrn__step h3 {
  position: relative;
  font-family: 'Inter', sans-serif !important;
  font-size: clamp(15px, 1.3vw, 18.5px); font-weight: 700; letter-spacing: -.015em;
  color: var(--h27-navy); margin: 0 0 10px; padding-bottom: 11px;
}
.h27 .h27-jrn__step h3::after {
  content: ''; position: absolute; left: 0; bottom: 0; width: 26px; height: 2px;
  border-radius: 2px; background: var(--h27-coral);
  transform: scaleX(1); transform-origin: 0 50%;
  transition: transform 640ms var(--h27-ease);
}
.h27 .h27-jrn__step p { font-size: 13.5px; line-height: 1.62; color: var(--h27-mute); margin: 0; }

.h27 .h27-jrn__tag {
  display: inline-flex; align-items: center; gap: 7px;
  margin-top: 15px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--h27-mute);
  transition: opacity 520ms var(--h27-ease), transform 520ms var(--h27-ease);
}
.h27 .h27-jrn__tag::before {
  content: ''; flex: none; width: 5px; height: 5px; border-radius: 50%;
  background: var(--h27-coral);
}

/* ── unlit: armed only while the script is actually driving the line ──── */
.h27 .h27-jrn.is-live .h27-jrn__step:not(.is-on) .h27-jrn__node {
  background: var(--h27-paper); color: #A9B8CC;
  box-shadow: inset 0 0 0 1.5px var(--h27-hair);
  transform: scale(.94);
}
.h27 .h27-jrn.is-live .h27-jrn__step:not(.is-on) .h27-jrn__no { color: rgba(13,27,62,.14); }
.h27 .h27-jrn.is-live .h27-jrn__step:not(.is-on) h3::after { transform: scaleX(0); }
.h27 .h27-jrn.is-live .h27-jrn__step:not(.is-on) .h27-jrn__tag {
  opacity: 0; transform: translate3d(0, 5px, 0);
}

/* ── pointer focus: the hovered station holds, its neighbours step back ── */
@media (hover: hover) and (pointer: fine) {
  .h27 .h27-jrn__list:hover .h27-jrn__step:not(:hover) .h27-jrn__node,
  .h27 .h27-jrn__list:hover .h27-jrn__step:not(:hover) .h27-jrn__no,
  .h27 .h27-jrn__list:hover .h27-jrn__step:not(:hover) .h27-jrn__body { opacity: .55; }
  .h27 .h27-jrn__step:hover .h27-jrn__node { transform: translate3d(0, -3px, 0) scale(1.06); }
  .h27 .h27-jrn__step:hover .h27-jrn__no { color: var(--h27-coral); }
}

/* ══ §17 · VOICES — testimonial wall ═════════════════════════════════════ */

.h27 .h27-quote {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column;
  padding: clamp(24px, 2.4vw, 36px);
  border-radius: 6px;
  background: var(--h27-paper);
  box-shadow: inset 0 0 0 1px var(--h27-hair);
  transition: transform 460ms var(--h27-ease), box-shadow 460ms var(--h27-ease);
}
.h27 .h27-quote:hover { transform: translateY(-5px); box-shadow: inset 0 0 0 1px rgba(13,27,62,.16), 0 20px 50px rgba(13,27,62,.1); }
.h27 .h27-quote::before {
  content: '\201C';
  position: absolute; top: -14px; right: 14px;
  font-family: 'DM Serif Display', Georgia, serif;
  font-size: 108px; line-height: 1; color: rgba(13,27,62,.06);
  pointer-events: none;
}
.h27 .h27-quote p {
  position: relative; z-index: 1;
  font-size: 15.5px; line-height: 1.7; color: var(--h27-body); margin: 0 0 20px;
}
.h27 .h27-quote__cite { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--h27-hair); }
.h27 .h27-quote__n { font-family: 'Inter', sans-serif; font-weight: 700; font-size: 14.5px; color: var(--h27-navy); }
.h27 .h27-quote__r { font-family: 'Inter', sans-serif; font-size: 12.5px; color: var(--h27-mute); margin-top: 2px; }
.h27 .h27-quote--ink {
  background: var(--h27-navy-up);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.1);
}

/* On a dark act the whole wall flips to glass — a white card there would punch
   a hole, and the --ink lead card would disappear into the ground. */
.h27 .h27-act--ink .h27-quote,
.h27 .h27-act--void .h27-quote {
  background: rgba(255,255,255,.075);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.12);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.h27 .h27-act--ink .h27-quote--ink,
.h27 .h27-act--void .h27-quote--ink { box-shadow: inset 0 0 0 1px rgba(232,89,58,.42); }
.h27 .h27-act--ink .h27-quote::before,
.h27 .h27-act--void .h27-quote::before { color: rgba(255,255,255,.1); }
.h27 .h27-act--ink .h27-quote p,
.h27 .h27-act--void .h27-quote p { color: rgba(255,255,255,.88); }
.h27 .h27-act--ink .h27-quote__cite,
.h27 .h27-act--void .h27-quote__cite { border-top-color: rgba(255,255,255,.14); }
.h27 .h27-act--ink .h27-quote__n,
.h27 .h27-act--void .h27-quote__n { color: #fff; }
.h27 .h27-act--ink .h27-quote__r,
.h27 .h27-act--void .h27-quote__r { color: var(--h27-onink-mute); }
.h27 .h27-act--ink .h27-quote:hover,
.h27 .h27-act--void .h27-quote:hover {
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.26), 0 24px 56px rgba(0,0,0,.4);
}
.h27 .h27-act--ink .h27-railbtn,
.h27 .h27-act--void .h27-railbtn { color: #fff; box-shadow: inset 0 0 0 1px rgba(255,255,255,.24); }
.h27 .h27-act--ink .h27-railbtn:hover,
.h27 .h27-act--void .h27-railbtn:hover { background: #fff; color: var(--h27-navy); box-shadow: inset 0 0 0 1px #fff; }
.h27 .h27-quote--ink::before { color: rgba(255,255,255,.1); }
.h27 .h27-quote--ink p { color: rgba(255,255,255,.9); }
.h27 .h27-quote--ink .h27-quote__cite { border-top-color: rgba(255,255,255,.14); }
.h27 .h27-quote--ink .h27-quote__n { color: #fff; }
.h27 .h27-quote--ink .h27-quote__r { color: var(--h27-onink-mute); }

/* horizontal rail for the long testimonial list */
.h27 .h27-rail {
  display: flex; gap: 16px;
  overflow-x: auto; scroll-snap-type: x mandatory;
  padding-bottom: 10px;
  scrollbar-width: none;
}
.h27 .h27-rail::-webkit-scrollbar { display: none; }
.h27 .h27-rail > * { flex: 0 0 min(84vw, 380px); scroll-snap-align: start; }
.h27 .h27-railbtns { display: flex; gap: 8px; }
.h27 .h27-railbtn {
  width: 44px; height: 44px; border-radius: 50%;
  border: 0; cursor: pointer;
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--h27-hair);
  color: var(--h27-navy);
  display: flex; align-items: center; justify-content: center;
  transition: background 300ms var(--h27-ease), color 300ms var(--h27-ease), box-shadow 300ms var(--h27-ease);
}
.h27 .h27-railbtn:hover { background: var(--h27-navy); color: #fff; box-shadow: inset 0 0 0 1px var(--h27-navy); }

/* ══ §18 · ACCORDION (FAQ) — full-bleed rules, big triggers ══════════════ */

.h27 .h27-acc { border-top: 1px solid var(--h27-hair); }
.h27 .h27-acc__item { border-bottom: 1px solid var(--h27-hair); }
.h27 .h27-acc__trigger {
  position: relative;
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  width: 100%; padding: clamp(20px, 2.2vw, 30px) 0;
  border: 0; background: none; cursor: pointer; text-align: left;
  font-family: 'Inter', sans-serif;
  font-size: clamp(16px, 1.6vw, 23px); font-weight: 600; letter-spacing: -.02em;
  color: var(--h27-navy);
  transition: color 280ms var(--h27-ease);
}
.h27 .h27-acc__trigger:hover { color: var(--h27-coral); }
.h27 .h27-acc__sign {
  position: relative; flex: 0 0 auto; width: 20px; height: 20px;
}
.h27 .h27-acc__sign::before,
.h27 .h27-acc__sign::after {
  content: ''; position: absolute; left: 50%; top: 50%; background: currentColor;
  transition: transform 420ms var(--h27-ease), opacity 300ms var(--h27-ease);
}
.h27 .h27-acc__sign::before { width: 16px; height: 1.5px; transform: translate(-50%,-50%); }
.h27 .h27-acc__sign::after  { width: 1.5px; height: 16px; transform: translate(-50%,-50%); }
.h27 .h27-acc__trigger[aria-expanded="true"] .h27-acc__sign::after { transform: translate(-50%,-50%) scaleY(0); opacity: 0; }
.h27 .h27-acc__trigger[aria-expanded="true"] { color: var(--h27-coral); }
.h27 .h27-acc__panel {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows 520ms var(--h27-ease);
}
.h27 .h27-acc__panel > div { overflow: hidden; }
.h27 .h27-acc__item.is-open .h27-acc__panel { grid-template-rows: 1fr; }
.h27 .h27-acc__panel p {
  font-size: clamp(15px, 1.15vw, 17px); line-height: 1.72; color: var(--h27-mute);
  margin: 0 0 clamp(20px, 2.2vw, 30px); max-width: 68ch;
}

/* ══ §19 · CLOSING CTA — full-bleed statement ════════════════════════════
   The band every page ends on, directly above the F27 footer. It was built
   as a full-viewport statement — 176px of padding under a 68px headline —
   which read as a dead half-screen once the footer landed under it: the
   visitor scrolls past the last argument and waits through empty steel
   before anything actionable appears.

   It is now a CLOSE, not an act: one screen-quarter that states the ask and
   hands off. Every dimension below is roughly 40% off the original, with the
   vertical rhythm re-tightened around the smaller headline rather than just
   scaled down — the eyebrow sits closer to the line it introduces, the lede
   closer to the buttons it justifies, the proof row closer to the buttons it
   reassures. Same markup on all pages, so this rule is the only lever. */

.h27 .h27-close {
  position: relative; overflow: hidden;
  background: var(--h27-void); color: #fff;
  padding-block: clamp(52px, 5.6vw, 88px);
  text-align: center;
  isolation: isolate;
}
.h27 .h27-close h2 {
  font-size: clamp(27px, 3.4vw, 46px);
  line-height: 1.06; letter-spacing: -.022em;
  color: #fff; margin: 0 0 12px;
  text-wrap: balance;
}
/* No text-transform here: most pages author the kicker in caps already, but the
   homepage sets a sentence-case line — uppercasing it would make it shout. */
.h27 .h27-close .h27-kicker {
  font-family: 'Inter', sans-serif;
  font-size: clamp(12px, .85vw, 14px); font-weight: 600; letter-spacing: .04em;
  color: var(--h27-coral-lt); margin-bottom: 10px;
}
/* responsive-refinement.css §1 turns hyphenation on for bare <p>. In a centred
   48ch column that broke the lede mid-word ("edu-/cation"); the wider measure
   and `pretty` also stop it orphaning the last word onto its own line. */
.h27 .h27-close p {
  font-size: clamp(15.5px, 1.05vw, 17.5px); line-height: 1.6;
  color: var(--h27-onink);
  margin: 0 auto 24px; max-width: 56ch;
  hyphens: none; -webkit-hyphens: none;
  text-wrap: pretty;
}
.h27 .h27-close .h27-cta-row { justify-content: center; }
.h27 .h27-close__proof {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 22px;
  margin-top: 26px; padding-top: 18px;
  border-top: 1px solid var(--h27-onink-hair);
}
.h27 .h27-close__proof span {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: 'Inter', sans-serif;
  font-size: 11.5px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--h27-onink-mute);
}
.h27 .h27-close__proof span::before {
  content: ''; width: 4px; height: 4px; border-radius: 50%; background: var(--h27-coral);
}
/* On a phone the band is already the tightest thing on the page; the buttons go
   full-width (§ mobile), so the row needs less air around it, not more. */
@media (max-width: 640px) {
  .h27 .h27-close { padding-block: 48px; }
  .h27 .h27-close p { margin-bottom: 22px; max-width: 40ch; }
  .h27 .h27-close__proof { margin-top: 22px; padding-top: 16px; gap: 8px 18px; }
}

/* ══ §20 · MOTION ════════════════════════════════════════════════════════ */

/* The starting (hidden) states are gated behind html.h27-ready, which home-2027.js
   sets only once its IntersectionObserver exists. If that script never runs — or
   throws — nothing is ever hidden, so the page degrades to fully visible. */
html.h27-ready .h27 [data-h27] { opacity: 0; will-change: opacity, transform; }
html.h27-ready .h27 [data-h27="up"]    { transform: translate3d(0, 26px, 0); }
html.h27-ready .h27 [data-h27="rise"]  { transform: translate3d(0, 42px, 0); }
html.h27-ready .h27 [data-h27="left"]  { transform: translate3d(-30px, 0, 0); }
html.h27-ready .h27 [data-h27="right"] { transform: translate3d(30px, 0, 0); }
html.h27-ready .h27 [data-h27="mask"]  { clip-path: inset(0 0 100% 0); transform: none; }
html.h27-ready .h27 [data-h27="fade"]  { transform: none; }
.h27 [data-h27] {
  transition:
    opacity 780ms var(--h27-ease),
    transform 880ms var(--h27-ease),
    clip-path 980ms var(--h27-ease);
  transition-delay: calc(var(--h27-i, 0) * 80ms);
}
/* The revealed state has to carry the same `html.h27-ready` prefix as the hidden
   states above — without it the per-variant rules (which are one element more
   specific) win and the element stays at opacity 0 forever. */
.h27 [data-h27].x27-in,
html.h27-ready .h27 [data-h27].x27-in {
  opacity: 1; transform: none;
}
/* clip-path stays off the blanket rule — only "mask" reveals from a clip.
   See the matching note in home-2027.css §31. */
html.h27-ready .h27 [data-h27="mask"].x27-in { clip-path: inset(0 0 0 0); }
html.h27-ready .h27 [data-h27="mask"].x27-in.x27-done { clip-path: none; }

@media (prefers-reduced-motion: reduce) {
  .h27 *, .h27 *::before, .h27 *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .h27 [data-h27] { opacity: 1 !important; transform: none !important; clip-path: none !important; }
  .h27 .h27-ticker__track, .h27 .h27-bigrun__track { animation: none !important; }
}

/* ── §15a · GROUNDS ──────────────────────────────────────────────────────── */

.h27 {
  /* light grounds — sky / sage / navy dissolved into white */
  --h27-mist:    #F4F9FD;   /* sky 3%  — the product bands */
  --h27-mist-2:  #E9F2FB;
  --h27-sage-g:  #F1F6F3;   /* sage 5% — the human / journey bands */
  --h27-sage-g2: #E6EFE9;
  --h27-steel:   #EDF3FA;   /* navy 6% — the one mid-tone step */
  --h27-steel-2: #E0EBF7;
}

/* a tinted band names its own top edge — a hairline, not a hard butt joint */
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) {
  box-shadow: inset 0 1px 0 rgba(13,27,62,.055), inset 0 -1px 0 rgba(13,27,62,.045);
}

.h27 .h27-act.h27-g--mist {
  background: var(--h27-mist);
  --h27-hair: #D9E5F3;
}
.h27 .h27-act.h27-g--sage {
  background: var(--h27-sage-g);
  --h27-hair: #D5E1DA;
}
.h27 .h27-act.h27-g--steel {
  background: var(--h27-steel);
  --h27-hair: #CEDCEC;
}
.h27 .h27-act.h27-g--ice {
  background: var(--h27-ice);
  --h27-hair: #DDE7F2;
}

/* the one raised dark plane — navy lifted off the ink so the four dark bands
   are not four identical black rectangles either */
.h27 .h27-act.h27-g--navy {
  background:
    var(--h27-navy-up);
}

/* ── §15b · TEXTURE LAYER ────────────────────────────────────────────────
   One <div class="h27-tex h27-tex--x" aria-hidden="true"> per band, sitting
   at z-index 0 (the .h27-edge content is z-index 2, so it always stays on
   top). The element itself carries a paper grain; ::before carries the
   pattern; ::after carries the atmosphere. Every pattern is masked so it
   fades out rather than tiling edge to edge like wallpaper. */

.h27 .h27-tex {
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none; overflow: hidden;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.86' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23p)' opacity='.055'/%3E%3C/svg%3E");
}
.h27 .h27-tex--flat { background-image: none; }
.h27 .h27-tex::before,
.h27 .h27-tex::after { content: ''; position: absolute; }

/* (1) BLUEPRINT — engineered graph paper. Act 01: the argument is about
       systems that do not line up, so the ground is literally ruled. */
.h27 .h27-tex--grid::before {
  inset: -2px;
  background-image:
    linear-gradient(rgba(13,27,62,.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(13,27,62,.045) 1px, transparent 1px),
    linear-gradient(rgba(13,27,62,.085) 1px, transparent 1px),
    linear-gradient(90deg, rgba(13,27,62,.085) 1px, transparent 1px);
  background-size: 34px 34px, 34px 34px, 170px 170px, 170px 170px;
  -webkit-mask-image: radial-gradient(115% 92% at 86% -6%, #000 0%, rgba(0,0,0,.5) 44%, transparent 78%);
          mask-image: radial-gradient(115% 92% at 86% -6%, #000 0%, rgba(0,0,0,.5) 44%, transparent 78%);
}
.h27 .h27-tex--grid::after {
  inset: -12% -6% auto -20%; height: 62%;
  background: none;
}

/* (2) DOT MATRIX — the module index. Nine discrete things, on a field of
       discrete marks. */
.h27 .h27-tex--dots::before {
  inset: 0;
  background-image: radial-gradient(rgba(13,27,62,.14) 1.15px, transparent 1.15px);
  background-size: 23px 23px;
  -webkit-mask-image: radial-gradient(88% 76% at 8% 102%, #000 0%, transparent 74%);
          mask-image: radial-gradient(88% 76% at 8% 102%, #000 0%, transparent 74%);
}
.h27 .h27-tex--dots::after {
  inset: -18% -14% auto auto; width: 58%; height: 74%;
  background: none;
}

/* (3) CONTOUR — concentric survey rings. The journey act: one path, mapped. */
.h27 .h27-tex--topo::before {
  inset: -30% -10%;
  background-image: repeating-radial-gradient(circle at 80% 44%,
    transparent 0 27px, rgba(13,27,62,.055) 27px 28px);
  -webkit-mask-image: radial-gradient(64% 82% at 82% 44%, #000 8%, transparent 76%);
          mask-image: radial-gradient(64% 82% at 82% 44%, #000 8%, transparent 76%);
}
.h27 .h27-tex--topo::after {
  inset: auto auto -22% -16%; width: 62%; height: 70%;
  background: none;
}

/* (4) HATCH — 45° hairlines. The number wall: a measured, drafted surface. */
.h27 .h27-tex--rule::before {
  inset: 0;
  background-image: repeating-linear-gradient(45deg,
    rgba(13,27,62,.05) 0 1px, transparent 1px 12px);
  -webkit-mask-image: linear-gradient(102deg, #000 0%, rgba(0,0,0,.42) 40%, transparent 74%);
          mask-image: linear-gradient(102deg, #000 0%, rgba(0,0,0,.42) 40%, transparent 74%);
}
.h27 .h27-tex--rule::after {
  inset: -20% -12% auto auto; width: 64%; height: 86%;
  background: none;
}

/* (5) BEAM — a lit stage. The product act: light falls on the screenshot
       from above, the way a product shot is lit. */
.h27 .h27-tex--beam::before {
  inset: 0;
  background:
    linear-gradient(90deg, rgba(13,27,62,.035) 1px, transparent 1px), linear-gradient(rgba(13,27,62,.035) 1px, transparent 1px);
  background-size: auto, 88px 88px, 88px 88px;
  -webkit-mask-image: radial-gradient(96% 82% at 50% 12%, #000 0%, transparent 82%);
          mask-image: radial-gradient(96% 82% at 50% 12%, #000 0%, transparent 82%);
}
.h27 .h27-tex--beam::after {
  inset: -14% -8%;
  background:
    none;
  animation: h27-tex-drift 46s var(--h27-ease) infinite alternate;
}

/* (6) ARC — quarter rings radiating from the corner. The switching act:
       one origin, everything moving out from it. */
.h27 .h27-tex--arc::before {
  inset: -20%;
  background-image: repeating-radial-gradient(circle at 8% 94%,
    transparent 0 48px, rgba(13,27,62,.055) 48px 49px);
  -webkit-mask-image: radial-gradient(74% 78% at 8% 94%, #000 14%, transparent 78%);
          mask-image: radial-gradient(74% 78% at 8% 94%, #000 14%, transparent 78%);
}
.h27 .h27-tex--arc::after {
  inset: -16% -12% auto auto; width: 60%; height: 78%;
  background: none;
}

/* (7) MESH — atmosphere only, no pattern. For bands whose content already
       carries a lot of ruled structure (tabs, cards) and would fight one. */
.h27 .h27-tex--mesh::before {
  inset: -18% -10%;
  background:
    none;
  animation: h27-tex-drift 52s var(--h27-ease) infinite alternate;
}
.h27 .h27-tex--mesh::after {
  inset: 0;
  background-image: radial-gradient(rgba(13,27,62,.08) 1px, transparent 1px);
  background-size: 40px 40px;
  -webkit-mask-image: radial-gradient(80% 60% at 50% 100%, #000 0%, transparent 72%);
          mask-image: radial-gradient(80% 60% at 50% 100%, #000 0%, transparent 72%);
}

/* (8) RAILS — two long margin rules, like a ruled notebook column. The FAQ
       is a reading band, so its texture is typographic, not graphic. */
.h27 .h27-tex--rails::before {
  inset: 8% 0;
  background-image:
    linear-gradient(90deg, rgba(13,27,62,.11) 1px, transparent 1px),
    linear-gradient(270deg, rgba(13,27,62,.11) 1px, transparent 1px);
  /* outside the h27-edge--tight reading column, so they frame it rather than
     ruling lines through the accordion rows */
  background-position: 9% 0, 91% 0;
  background-size: 100% 100%;
  background-repeat: no-repeat;
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 22%, #000 78%, transparent 100%);
          mask-image: linear-gradient(180deg, transparent 0%, #000 22%, #000 78%, transparent 100%);
}
.h27 .h27-tex--rails::after {
  inset: auto -10% -24% -10%; height: 58%;
  background: none;
}

@keyframes h27-tex-drift {
  0%   { transform: translate3d(0,0,0) scale(1); }
  100% { transform: translate3d(-2.2%, 1.8%, 0) scale(1.05); }
}
@media (prefers-reduced-motion: reduce) {
  .h27 .h27-tex::before,
  .h27 .h27-tex::after { animation: none !important; }
}

/* ── §15c · GROUND-AWARE COMPONENTS ──────────────────────────────────────
   The handful of things that assumed a white or ice ground and have to
   follow the band they now sit on. */

/* the number wall's hover fill has to go LIGHTER than steel, not to ice */
.h27 .h27-act.h27-g--steel .h27-wall__cell:hover,
.h27 .h27-act.h27-g--mist  .h27-wall__cell:hover,
.h27 .h27-act.h27-g--sage  .h27-wall__cell:hover { background: rgba(255,255,255,.62); }

/* icon chips read as a punched hole when the card is white on a tinted
   ground; give them the band's own tint instead of the fixed ice-2 */
.h27 .h27-act.h27-g--sage .h27-card__ico { background: rgba(122,158,142,.15); }
.h27 .h27-act.h27-g--mist .h27-card__ico,
.h27 .h27-act.h27-g--steel .h27-card__ico { background: rgba(59,134,188,.12); }

/* white cards on a tinted ground need a touch more lift than they did on
   white, where the hairline alone did the work */
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) .h27-card,
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) .h27-quote {
  box-shadow: 0 1px 2px rgba(13,27,62,.05), 0 14px 34px rgba(13,27,62,.055);
}

/* the sticky act index sat on flat white; over tinted bands it has to be a
   real pane of glass or it reads as a stray white strip. Retunes §6's tokens
   rather than the `background` shorthand, so the free/stuck pair stays a pair
   — setting `background` here would have out-cascaded only one of them. */
.h27 {
  --h27-idx-bg:       rgba(250,252,255,.82);
  --h27-idx-bg-stuck: rgba(250,252,255,.94);
  --h27-idx-hair:     rgba(13,27,62,.10);
}


/* ── §21a · THE BANDS ─────────────────────────────────────────────────────
   Grounds come from §15a via `.h27-g--steel` / `.h27-g--mist` on the section,
   which also re-scopes --h27-hair. The sequence now reads:
     … ink → steel → mist(beam) …    (Act 02 → interlude → Act 03)
     … navy → mist → steel …         (integrations → Act 06 → Act 07)
     … paper(rails) → steel          (FAQ → close)
   so no two adjacent bands share a ground. */

/* the ground class paints the real surface; this is the fallback so `--lit`
   is never a transparent band on its own */
.h27 .h27-act--lit { background: var(--h27-ice); color: var(--h27-body); }

/* A light band butting straight onto the dark one above it needs the same
   persimmon edge the interlude used to draw — the tone change alone reads as
   an accident at that seam. */
.h27 .h27-act--ink + .h27-act--lit::before,
.h27 .h27-act--void + .h27-act--lit::before {
  content: ''; position: absolute; inset-inline: var(--h27-gut); top: 0; height: 2px;
  z-index: 1;
  background: rgba(232,89,58,.55);
}

/* ── §21b · CLOSING CTA · LIT ─────────────────────────────────────────────
   The light twin of §19. Same band, same rhythm — it just stops the page
   ending on a black rectangle. The ground is the §15a steel ramp with a
   white wash pulled through the top so the headline sits IN light rather
   than on a flat tint, and the band names its own top edge with the same
   persimmon rule §21a draws at a tone seam.

   Markup: <section class="h27-close h27-close--lit"> carrying a §15b
   `.h27-tex` div INSTEAD of `.h27-atm` / `.h27-grain` — both of those draw
   white lines and a dark grain, i.e. nothing, on a light ground.

   Specificity: §3 and §19 name `.h27-close` explicitly in their dark-ground
   lists. Every rule below is the same (0,3,0) but later in the file, so the
   lit band gets the light treatment back without !important. */

.h27 .h27-close--lit {
  background:
    var(--h27-steel);
  color: var(--h27-body);
  --h27-hair: #CEDCEC;
  box-shadow: inset 0 1px 0 rgba(13,27,62,.055);
}
.h27 .h27-close--lit::before {
  content: ''; position: absolute; inset-inline: var(--h27-gut); top: 0; height: 2px;
  z-index: 1;
  background: rgba(232,89,58,.55);
}
/* Alternate ramp for the handful of pages whose last act is ALREADY steel —
   steel on steel is not a band change, it is a seam that vanishes. */
.h27 .h27-close--lit.h27-close--mist {
  background:
    var(--h27-mist);
  --h27-hair: #D9E5F3;
}

.h27 .h27-close--lit h2 { color: var(--h27-navy); }
.h27 .h27-close--lit p  { color: var(--h27-mute); }
.h27 .h27-close--lit .h27-kicker { color: var(--h27-coral); }

.h27 .h27-close--lit .h27-btn--line {
  color: var(--h27-navy); box-shadow: inset 0 0 0 1.5px rgba(13,27,62,.28);
}
.h27 .h27-close--lit .h27-btn--line::before { background: var(--h27-navy); }
.h27 .h27-close--lit .h27-btn--line:hover   { color: #fff; }
.h27 .h27-close--lit .h27-link { color: var(--h27-sky); }
.h27 .h27-close--lit .h27-close__proof { border-top-color: var(--h27-hair); }
.h27 .h27-close--lit .h27-close__proof span { color: var(--h27-mute); }

/* ── §22a · BACKDROP ─────────────────────────────────────────────────────
   Same footprint and stacking as .h27-tex, so a band can carry a photo and a
   texture at once and neither one wins. Tuned per band in §22c through the
   four custom properties below rather than by writing a new rule each time. */

.h27 .h27-phbg {
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none; overflow: hidden;
  /* defaults are the DARK-band values — light bands override in §22c */
  --h27-phbg-o:    .26;
  --h27-phbg-sat:  .52;
  --h27-phbg-br:   .84;
  --h27-phbg-pos:  50% 50%;
  --h27-phbg-mask: linear-gradient(90deg, transparent 0%, rgba(0,0,0,.34) 42%, #000 84%);
}
.h27 .h27-phbg img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: var(--h27-phbg-pos);
  opacity: var(--h27-phbg-o);
  filter: saturate(var(--h27-phbg-sat)) contrast(1.05) brightness(var(--h27-phbg-br));
  -webkit-mask-image: var(--h27-phbg-mask);
          mask-image: var(--h27-phbg-mask);
}

/* the scrim — the band's own ground, laid back over the photo so the text
   column keeps the contrast it had before there was a photo behind it */
.h27 .h27-phbg::after {
  content: ''; position: absolute; inset: 0;
  background:
    var(--h27-ink);
}

/* on a navy band the scrim has to follow the navy plane, not the deeper ink */
.h27 .h27-act.h27-g--navy .h27-phbg::after {
  background:
    rgba(13,27,62,.74);
}

/* LIGHT bands: the photo is a whisper under a white wash, never a picture.
   Brightness goes up rather than opacity, so the frame stays airy instead of
   turning into a grey smudge on the steel ground. */
.h27 .h27-phbg--lit {
  --h27-phbg-o:   .30;
  --h27-phbg-sat: .40;
  --h27-phbg-br:  1.06;
}
.h27 .h27-phbg--lit::after {
  background:
    rgba(237,243,250,.92);
}

/* the same idea on a PAPER band, where the steel-tinted wash above would read
   as a pale blue rectangle laid over white rather than as depth */
.h27 .h27-phbg--paper {
  --h27-phbg-o:   .26;
  --h27-phbg-sat: .34;
  --h27-phbg-br:  1.10;
}
.h27 .h27-phbg--paper::after {
  background:
    rgba(255,255,255,.90);
}

/* ── §22b · PLATE ────────────────────────────────────────────────────────
   The editorial frame. Ratio is a variable because each act's plate is cut to
   a different letterbox on disk — see the PLAN table in the build script. */

.h27 .h27-ph {
  position: relative; display: block;
  aspect-ratio: var(--h27-ph-ar, 2.4);
  margin: 0 0 clamp(38px, 4.6vw, 68px);
  border-radius: 4px; overflow: hidden;
  background: var(--h27-ice-2);
  box-shadow:
    inset 0 0 0 1px var(--h27-hair),
    0 2px 4px rgba(13,27,62,.05),
    0 26px 64px rgba(13,27,62,.11);
  isolation: isolate;
}
.h27 .h27-ph img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block; object-fit: cover;
  object-position: var(--h27-ph-pos, 50% 50%);
  /* plates are seen at full strength, so the grade is gentle here — just
     enough to take the stock cyan off the highlights */
  filter: saturate(.84) contrast(1.04);
}

/* the navy signature every plate shares */
.h27 .h27-ph::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    rgba(13, 27, 62, 0.29);
}
/* mirrored, for a frame whose subject sits on the left */
.h27 .h27-ph--rtl::after {
  background:
    rgba(13, 27, 62, 0.29);
}

/* corner brackets — the Round-6 frame mark, persimmon, same as the eyebrow */
.h27 .h27-ph__bk { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.h27 .h27-ph__bk::before,
.h27 .h27-ph__bk::after {
  content: ''; position: absolute;
  width: 22px; height: 22px;
  border: 2px solid var(--h27-coral);
}
.h27 .h27-ph__bk::before { top: 14px;   left: 14px;   border-right: 0; border-bottom: 0; }
.h27 .h27-ph__bk::after  { right: 14px; bottom: 14px; border-left: 0;  border-top: 0; }

/* caption chip — what the reader is looking at, in the page's own voice */
.h27 .h27-ph__cap {
  position: absolute; z-index: 3;
  left: clamp(16px, 2.2vw, 30px); bottom: clamp(16px, 2.2vw, 30px);
  display: inline-flex; align-items: center; gap: 11px;
  max-width: min(64ch, calc(100% - 60px));
  padding: 10px 16px; border-radius: 3px;
  background: rgba(10,19,48,.62);
  -webkit-backdrop-filter: blur(12px) saturate(1.3);
          backdrop-filter: blur(12px) saturate(1.3);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.14);
  font-family: 'Inter', sans-serif;
  font-size: 13px; font-weight: 600; letter-spacing: .01em; line-height: 1.35;
  color: #fff;
}
.h27 .h27-ph__cap i {
  flex: none; width: 6px; height: 6px; border-radius: 50%;
  background: var(--h27-coral);
}

/* a plate that closes a block rather than opening one */
.h27 .h27-ph--tail { margin: clamp(38px, 4.6vw, 68px) 0 0; }

/* ── §22d · RESPONSIVE ───────────────────────────────────────────────────
   A 3:1 letterbox is a cinematic band at 1320px and a slot at 380px. Below
   the tablet break every plate stands up toward 16:9 and the crop re-centres
   on its subject, which on these frames sits right of centre. */

@media (max-width: 860px) {
  .h27 .h27-ph { --h27-ph-ar: 2.1; }
  .h27 .h27-ph__bk::before,
  .h27 .h27-ph__bk::after { width: 16px; height: 16px; }
}
@media (max-width: 620px) {
  /* 1.9 rather than 16:9: standing a 3:1 all the way up would throw away
     nearly half its width, and these frames do not have half a frame to
     spare. Each one then re-centres on its own subject — object-position is
     the only thing holding the point of the photograph inside the crop. */
  .h27 .h27-ph { --h27-ph-ar: 1.9; border-radius: 3px; }
  .h27 .h27-ph--booking   { --h27-ph-pos: 68% 50%; }  /* the laptop, right of frame  */
  .h27 .h27-ph--consult   { --h27-ph-pos: 50% 50%; }  /* both faces, doctor to patient */
  .h27 .h27-ph--frontdesk { --h27-ph-pos: 62% 50%; }  /* the desk, right of frame    */
  .h27 .h27-ph--clinician { --h27-ph-pos: 56% 50%; }  /* the tablet, just off centre */
  .h27 .h27-ph--outcome   { --h27-ph-pos: 58% 50%; }  /* both faces, patient-side    */
  .h27 .h27-ph__cap {
    left: 12px; right: 12px; bottom: 12px;
    max-width: none; padding: 9px 13px; font-size: 12px;
  }
  /* backdrops lose their directional masks — at this width there is no "other
     side" for the type to sit in, so they simply fade downward */
  .h27 .h27-phbg {
    --h27-phbg-o: .18;
    --h27-phbg-mask: linear-gradient(180deg, #000 0%, rgba(0,0,0,.3) 62%, transparent 100%);
  }
}

/* A decorative photograph is the first thing to go when the reader has asked
   for more contrast. */
@media (prefers-contrast: more) {
  .h27 .h27-phbg { display: none; }
  .h27 .h27-ph::after { background: rgba(13, 27, 62, 0.26); }
}

/* ══ §21 · RESPONSIVE ════════════════════════════════════════════════════
   Only the breakpoints that touch the generic vocabulary above. The hero,
   stage, OS-plane, console, module-index and relay breakpoints stayed behind
   in home-2027.css with the components they belong to. */

/* The station line turns 90° rather than wrapping to a second row — a rule with
   five stops only reads as one journey while it is a single unbroken line. Same
   markup, same script: the axis is inferred from the rail's own box. */
@media (max-width: 1024px) {
  .h27 .h27-jrn__rail {
    left: calc(var(--jrn-line) - 1px); right: auto;
    top: var(--jrn-line); bottom: 0;
    width: 2px; height: auto;
    -webkit-mask-image: linear-gradient(180deg, #000 88%, transparent);
            mask-image: linear-gradient(180deg, #000 88%, transparent);
  }
  .h27 .h27-jrn__fill { transform: scaleY(var(--jrn-p)); transform-origin: 50% 0; }
  .h27 .h27-jrn__spark {
    left: var(--jrn-line);
    top: calc(var(--jrn-line) + var(--jrn-p) * (100% - var(--jrn-line)));
  }
  .h27 .h27-jrn__list {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(26px, 4vw, 40px);
  }
  .h27 .h27-jrn__step {
    display: grid;
    grid-template-columns: var(--jrn-node) minmax(0, 1fr);
    column-gap: clamp(16px, 2.4vw, 26px);
    align-items: start;
    padding-right: 0;
  }
  .h27 .h27-jrn__node { margin-bottom: 0; }
  /* the numeral now heads its own entry, so it drops to the station's baseline */
  .h27 .h27-jrn__no {
    font-size: clamp(26px, 5vw, 34px);
    margin-bottom: clamp(8px, 1.4vw, 12px);
  }
  .h27 .h27-jrn__body { padding-top: 3px; }
  .h27 .h27-jrn__step p { max-width: 62ch; }
}

@media (max-width: 900px) {
  .h27 .h27-head { grid-template-columns: minmax(0,1fr); gap: 20px; align-items: start; }
  .h27 .h27-split { grid-template-columns: minmax(0,1fr); }
  .h27 .h27-split__side { border-left: 0; border-top: 1px solid var(--h27-hair); }
  .h27 .h27-split__side:first-child { border-top: 0; }
  .h27 .h27-wall { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .h27 .h27-grid--3, .h27 .h27-grid--4 { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .h27 .h27-span-2, .h27 .h27-span-3 { grid-column: span 2; }
}

@media (max-width: 640px) {
  .h27 { --h27-act: 62px; }
  .h27 .h27-wall { grid-template-columns: minmax(0,1fr); }
  .h27 .h27-grid--2, .h27 .h27-grid--3, .h27 .h27-grid--4 { grid-template-columns: minmax(0,1fr); }
  .h27 .h27-span-2, .h27 .h27-span-3 { grid-column: span 1; }
  .h27 .h27-jrn { --jrn-node: 38px; }
  .h27 .h27-jrn__node .ico { font-size: 17px; width: 17px; height: 17px; }
  .h27 .h27-strip { flex-direction: column; align-items: flex-start; }
  .h27 .h27-btn { width: 100%; justify-content: center; }
  .h27 .h27-cta-row { width: 100%; }
  .h27 .h27-tabs button { margin-right: 18px; padding-right: 0; font-size: 15px; }
  .h27 .h27-tabs button::after { right: 0; }
}


/* ══ §23 · HYPHENATION GUARD ═════════════════════════════════════════════
   responsive-refinement.css §1 sets `hyphens: auto` on bare h1–h6 / p / li /
   a / span site-wide to stop long words overflowing narrow screens. That is
   right for body copy, but wrong for display type: the act headline sits in a
   ~1fr column of a .82fr-split head, and at --h27-d1 the browser happily
   breaks "network" into "net-work" and "every" into "ev-ery" mid-headline.

   home-2027.css hits the same problem and answers it with targeted
   `hyphens: none` rules (see its §10/§11 — "hyphens are on site-wide; at
   12.5px in a 300px column they break mid-word"). Those rules live in
   homepage-only ranges, so the shared theme needs its own copy.

   Scope: display type, labels and anything short enough that a hyphen reads
   as a typo. Body copy (.h27-lede, card paragraphs, FAQ answers) deliberately
   keeps the site-wide hyphenation. `overflow-wrap: break-word` from the same
   upstream rule is left alone — it only fires when a word genuinely cannot
   fit, which is still the behaviour we want.

   Specificity: upstream is (0,0,1) on the bare element; every selector below
   is at least (0,2,0), so this wins without !important.
   ══════════════════════════════════════════════════════════════════════ */

/* Every heading inside the scope — (0,1,1) already beats the upstream (0,0,1),
   and it catches page heroes whose h1/h2 sit outside a .h27-head wrapper. */
.h27 h1,
.h27 h2,
.h27 h3,
.h27 .h27-head h2,
.h27 h2.h27-h,
.h27 .h27-close h2,
.h27 .h27-close .h27-kicker,
.h27 .h27-kicker,
/* the hero's standfirst runs at 16–20px in a ~600px column; on a 1366 laptop
   that column tightens enough for the site-wide `hyphens: auto` to split
   "answered" across lines as "an-swered", which reads as a typo directly under
   the headline. Body copy further down the page keeps hyphenation. */
.h27 .h27-hero__sub,
.h27 .h27-eyebrow,
.h27 .h27-actno,
.h27 .h27-bignum,
.h27 .h27-bignum b,
.h27 .h27-wall__num,
.h27 .h27-wall__lbl,
.h27 .h27-count,
.h27 .h27-card h3,
.h27 .h27-card__eyebrow,
.h27 .h27-jrn__step h3,
.h27 .h27-quote p,
.h27 .h27-quote__cite,
.h27 .h27-quote__n,
.h27 .h27-split__tag,
.h27 .h27-chip,
.h27 .h27-btn,
.h27 .h27-link,
.h27 .h27-acc__trigger,
.h27 .h27-index a,
.h27 .h27-ticker__item,
.h27 .h27-bigrun__item,
.h27 .h27-tabs button,
.h27 .h27-pills button {
  hyphens: none;
  -webkit-hyphens: none;
}

/* ══ §25 · A11Y CONTRAST ═════════════════════════════════════════════════
   Added after the act-based conversion audit. Every fix below re-points a
   colour to an EXISTING locked token — no new hue is introduced. Ratios in
   the comments are measured against the real rendered ground (screenshot
   sampled), not against an assumed background.

   The recurring root cause is tier leakage: the on-dark tints
   (--h27-coral-lt, --h27-onink-*) landing on light grounds, and the on-light
   tiers (--h27-mute, --h27-navy) landing on the ink ramp.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── §25a · STICKY CHAPTER INDEX ──────────────────────────────────────────
   The numerals were rgba(13,27,62,.34) — 2.13:1, the worst text on the site
   outside the dark-band leaks. --h27-mute reads as the same quiet tier. */
.h27 .h27-index a em           { color: var(--h27-mute); }   /* 2.13 → 4.90 */
.h27 .h27-index a:hover em     { color: var(--h27-body); }   /* 3.30 → 12.1 */
.h27 .h27-index a.is-active em { color: var(--h27-navy); }   /* 3.18 → 15.2 */

/* ── §25b · SMALL PERSIMMON LABELS ON LIGHT GROUNDS ───────────────────────
   #E8593A at 10–13px is 3.0–3.55:1 on white and worse on the tinted ramps.
   --h27-coral-dk clears 4.5:1 on paper; on the §15a tinted ramps even the
   dark persimmon only reaches ~4.1–4.45, so those bands fall back to navy.
   Dark cards/bands are untouched — their own rules (0,3,0) still win. */
.h27 .h27-card__eyebrow,
.h27 .h27-kicker,
.h27 .h27-close--lit .h27-kicker { color: var(--h27-coral-dk); }  /* 3.55 → 4.67 */

.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) .h27-card__eyebrow,
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) .h27-kicker,
.h27 .h27-close--lit .h27-kicker,
.h27 .h27-close--lit .h27-card__eyebrow { color: var(--h27-navy); } /* → 14.0+ */

/* the same ramps also drag --h27-link below the bar (4.45–4.47) */
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) .h27-link,
.h27 .h27-close--lit .h27-link { color: var(--h27-navy); }

/* ── §25c · TEXT LINKS ────────────────────────────────────────────────────
   --h27-sky is 3.95:1 on white and the rule carries no rest-state underline
   (the rule only wipes in on hover), so colour alone had to carry it. */
.h27 .h27-link { color: var(--h27-coral-dk); }               /* 3.95 → 4.67 */

/* the on-dark tint must not leak onto a LIGHT card sitting inside a dark act
   — that produced #FFAB96 on white, 1.82:1, on /payments/ */
.h27 .h27-act--ink  .h27-card:not(.h27-card--ink):not(.h27-card--glass) .h27-link,
.h27 .h27-act--void .h27-card:not(.h27-card--ink):not(.h27-card--glass) .h27-link,
.h27 .h27-close     .h27-card:not(.h27-card--ink):not(.h27-card--glass) .h27-link {
  color: var(--h27-coral-dk);                                /* 1.82 → 4.67 */
}

/* ── §25d · PRIMARY FILL BUTTON ───────────────────────────────────────────
   #fff on #E8593A is 3.55:1. The hover wipe (::before) was already coral-dk,
   so it moves to navy to keep the state change legible. */
.h27 .h27-btn--fill         { background: var(--h27-coral-dk); }  /* 3.55 → 4.67 */
.h27 .h27-btn--fill::before { background: var(--h27-navy); }

/* ── §25e · NUMBER WALL ───────────────────────────────────────────────────
   .h27-wall__cell--coral pinned --h27-coral-lt (an on-dark tint) and only
   .h27-act--paper overrode it, so every tinted/ice band rendered #FFAB96 on
   a light ground — 1.56:1 at 46–92px. */
.h27 .h27-act--ice .h27-wall__cell--coral .h27-wall__num,
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) .h27-wall__cell--coral .h27-wall__num,
.h27 .h27-close--lit .h27-wall__cell--coral .h27-wall__num {
  color: var(--h27-coral-dk);                                /* 1.56 → 3.80 */
}

/* ── §25f · LIGHT-TIER TEXT INSIDE DARK ACTS ──────────────────────────────
   The journey component hard-codes the on-light tiers, so on a dark act its
   headings rendered navy-on-ink at 1.07:1 — effectively invisible
   (/efficient-practice-quiz/). Same class of bug for the module lists. */
.h27 .h27-act--ink  .h27-jrn__step h3,
.h27 .h27-act--void .h27-jrn__step h3,
.h27 .h27-close:not(.h27-close--lit) .h27-jrn__step h3 {
  color: var(--h27-onink);                                   /* 1.07 → 11.3 */
}
.h27 .h27-act--ink  .h27-jrn__step p,
.h27 .h27-act--void .h27-jrn__step p,
.h27 .h27-act--ink  .h27-jrn__tag,
.h27 .h27-act--void .h27-jrn__tag,
.h27 .h27-act--ink  .mx-list li,
.h27 .h27-act--void .mx-list li,
.h27 .h27-act--ink  .mx-note,
.h27 .h27-act--void .mx-note,
.h27 .h27-act--ink  .m27-cap,
.h27 .h27-act--void .m27-cap {
  color: var(--h27-onink-mute);                              /* 3.13 → 5.57 */
}

/* ── §25g · QUIET TEXT ON THE TINTED RAMPS ────────────────────────────────
   --h27-mute (#5F718C) clears 4.5:1 on paper (4.97) and on --h27-ice (4.74)
   but NOT on the lower half of the §15a ramps (4.12–4.48). Re-pointing the
   token on those grounds fixes every component that uses it at once — it is
   only ever used as a `color`, never as a border or fill. */
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy),
.h27 .h27-close--lit {
  --h27-mute: var(--h27-body);                               /* 4.12 → 11.2+ */
}
/* …but a DARK card sitting on one of those light bands must keep the
   on-dark tier, or its quiet text would go near-black on near-black.
   .h27-card--glass is deliberately NOT listed: it is translucent, so on a
   light band it reads light and must keep the on-light tier. */
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) .h27-card--ink,
.h27 .h27-close--lit .h27-card--ink {
  --h27-mute: var(--h27-onink-mute);
}

/* ── §25h · DARK-SURFACE RESTORE ──────────────────────────────────────────
   §25b/§25c darken accents for the tinted light bands, but a dark card can
   sit ON one of those bands. Those selectors carry an [attr] + :not() and so
   out-specify the component's own (0,3,0) rule — without this restore the
   eyebrow of a .h27-card--ink rendered navy-on-navy (1.0:1). Kept last so it
   always wins. */
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) .h27-card--ink .h27-card__eyebrow,
.h27 .h27-close--lit .h27-card--ink .h27-card__eyebrow,
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) .h27-card--ink .h27-link,
.h27 .h27-close--lit .h27-card--ink .h27-link {
  color: var(--h27-coral-lt);
}
/* a glass card on a LIGHT band is light — it takes the on-light accent, not
   the on-dark tint that its own (0,3,0) component rules assume. */
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) .h27-card--glass .h27-card__eyebrow,
.h27 .h27-act--paper .h27-card--glass .h27-card__eyebrow,
.h27 .h27-act--ice   .h27-card--glass .h27-card__eyebrow,
.h27 .h27-close--lit .h27-card--glass .h27-card__eyebrow,
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) .h27-card--glass .h27-link,
.h27 .h27-act--paper .h27-card--glass .h27-link,
.h27 .h27-act--ice   .h27-card--glass .h27-link,
.h27 .h27-close--lit .h27-card--glass .h27-link {
  color: var(--h27-coral-dk);
}
.h27 .h27-act--paper .h27-card--glass h3,
.h27 .h27-act--ice   .h27-card--glass h3,
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) .h27-card--glass h3 { color: var(--h27-navy); }
.h27 .h27-act--paper .h27-card--glass p,
.h27 .h27-act--ice   .h27-card--glass p,
.h27 .h27-act[class*="h27-g--"]:not(.h27-g--navy) .h27-card--glass p { color: var(--h27-body); }

/* ── §25i · QUIET TEXT ON DARK SURFACES ───────────────────────────────────
   The mirror of §25g. --h27-mute (#5F718C) is an on-LIGHT tier; wherever a
   component carried it onto the ink ramp it landed at 3.1–3.5:1 (module
   feature lists, journey captions, dark cards). Re-pointing the token on the
   dark surfaces fixes every such component at once. */
.h27 .h27-act--ink,
.h27 .h27-act--void,
.h27 .h27-act.h27-g--navy,
.h27 .h27-close:not(.h27-close--lit),
.h27 .h27-card--ink,
.h27 .h27-split__side--new {
  --h27-mute: var(--h27-onink-mute);                         /* 3.13 → 5.39+ */
}
/* .h27-card--glass is TRANSLUCENT — it is only dark when its band is dark, so
   it is scoped rather than listed above (it sits on white on the homepage). */
.h27 .h27-act--ink .h27-card--glass,
.h27 .h27-act--void .h27-card--glass,
.h27 .h27-act.h27-g--navy .h27-card--glass,
.h27 .h27-close:not(.h27-close--lit) .h27-card--glass {
  --h27-mute: var(--h27-onink-mute);
}
/* …and a LIGHT card nested inside a dark act must go back to an on-light
   tier, or its quiet text would be white-on-white. */
.h27 .h27-act--ink  .h27-card:not(.h27-card--ink):not(.h27-card--glass),
.h27 .h27-act--void .h27-card:not(.h27-card--ink):not(.h27-card--glass),
.h27 .h27-act.h27-g--navy .h27-card:not(.h27-card--ink):not(.h27-card--glass),
.h27 .h27-close:not(.h27-close--lit) .h27-card:not(.h27-card--ink):not(.h27-card--glass) {
  --h27-mute: var(--h27-body);
}

/* ── §25j · REMAINING PAGE-LEVEL GROUNDS ──────────────────────────────────
   Containers that paint their own near-white/grey panel rather than using a
   §15a ground, so §25g never reached them. */
.h27 .mx-two,
.h27 .sec-list,
.h27 .lg-card { --h27-mute: var(--h27-body); }               /* 4.36 → 11.2+ */

/* the persimmon text link is 4.45–4.47:1 on these tinted panels — just under
   the bar, so they take the navy tier like the §25b ramps do */
.h27 .demo-form__note .h27-link,
.h27 .lg-card .h27-link { color: var(--h27-navy); }

/* an OPEN accordion trigger is 23px — under the 24px large-text threshold,
   so persimmon at 3.49:1 fails the 4.5 bar it is actually held to */
.h27 .h27-acc__trigger[aria-expanded="true"],
.h27 .h27-acc__item.is-open .h27-acc__trigger { color: var(--h27-coral-dk); }
