/* ===========================================================================
   HIGHLINE DESIGN SYSTEM — the approved visual language, in production
   ===========================================================================

   SOURCE OF TRUTH: public/prototype/homepage/styles.css (approved).
   This file is that stylesheet ported onto production class names, tokens and
   markup. It is not a second stylesheet stack: it is the last layer of the
   existing one (tokens → base → layout → components → blocks → THIS), so it
   layers over the generic block defaults rather than competing with them.

   PORTING RULES — follow these when porting the remaining prototype layers
   (service.css, industry.css) so the two never drift:

     * prototype class `.foo`      → `.hl-foo`
     * prototype token `--foo`     → `--hl-foo`
     * prototype keyframe `foo`    → `hls-foo`
     * state classes (`is-`, `has-`) are shared vocabulary and are NOT renamed
     * four families were renamed to the production component they style:
         .nav    → .hl-header      .brand  → .hl-logo
         .promo  → .hl-announce    .foot   → .hl-footer
         .pmodal → .hl-promo-modal .pre    → .hl-loader
       and `.hero` became `.hl-hero--highline`, because the approved hero is a
       VARIANT of the hero block, not a replacement for every hero on the site.

   WHAT IS EDITABLE AND WHAT IS NOT
   Nothing in this file is reachable from Admin. The CMS chooses content, order,
   visibility, variants and which approved presentation option applies; the
   treatment itself lives here. There is no CSS field anywhere in the builder.

   SECTIONS
     A · TOKENS                 (brand kit; brand hues come from the Theme manager)
     B · BASE                   (typography scale, scoped resets)
     C · APPROVED SYSTEM        (ported verbatim from the prototype — primitives,
                                 infrastructure language, device kit, and every
                                 homepage chapter)
     D · LOADER                 (the ONE loader, restyled — no second system)
     E · PRODUCTION BRIDGE      (classes the renderer emits that the prototype
                                 did not have, and aliases for the older
                                 component vocabulary)
     F · SERVICE LAYER          (prototype/service/service.css ported — the
                                 structures an inner page needs and the
                                 homepage does not have)
     G · INDUSTRY LAYER         (prototype/industry/industry.css ported — the
                                 floor, the showcase, the offer band and the
                                 Cash Discount chapter)
     H · FORM LAYER             (the one thing the approved prototypes never
                                 drew, because they had no form: inputs, field
                                 states, the acknowledgement and the contact
                                 panel, built from the same tokens as everything
                                 above so it does not read as a bolted-on
                                 admin-template form)
     I · CATALOG LAYER          (the second thing they never drew, because there
                                 was no catalog: the filter rail, the product
                                 card, pagination, the controlled empty result,
                                 and the product detail page — built from the
                                 same tokens and reusing the approved device kit
                                 rather than becoming a storefront grid)
   =========================================================================== */

/* ── A · TOKENS ───────────────────────────────────────────────────────────
   The brand hues resolve through the ThemeService custom properties, so the
   Theme manager still controls the palette; everything else is the approved
   design scale and is fixed. */
:root{
  --hl-brand-navy:var(--hl-primary, #2A2D7C);
  --hl-brand-red:var(--hl-accent, #CF2927);
  --hl-brand-grey:#606161;

  /* Navy / ink ramp — the dark chapters */
  --hl-ink-950:#04050E;
  --hl-ink-900:#070919;
  --hl-ink-850:#0A0C22;
  --hl-ink-800:#0E1230;
  --hl-ink-750:#141949;
  --hl-ink-700:#1B2166;
  --hl-navy-600:#2A2D7C;
  --hl-navy-500:#3A3FA3;
  --hl-navy-400:#5A61CC;
  --hl-navy-300:#9096E4;

  /* Red ramp */
  --hl-red-700:#8E1614;
  --hl-red-600:#B02220;
  --hl-red-500:#CF2927;
  --hl-red-400:#E5544E;
  --hl-red-300:#F79A95;

  /* Restrained secondaries — data and signal only */
  --hl-signal:#4C8DFF;
  --hl-violet:#7A5CF0;
  --hl-ok:#2FD6A3;

  /* Neutrals */
  --hl-white:#FFFFFF;
  --hl-paper:#F5F7FC;
  --hl-paper-2:#EBEFF7;
  --hl-paper-3:#DFE5F0;

  /* Text */
  --hl-text-dark:#0A0E24;
  --hl-text-body:#454C69;
  /* Darkened at go-live, from #767E96, and this is a legibility fix rather than
     a design change.

     #767E96 gives 4.04:1 on white and 3.77:1 on paper. WCAG AA wants 4.5:1 for
     normal-size text, so every muted paragraph, caption, help line and
     definition term on the site — 56 rules use this token — was failing it.
     Not marginally: failing.

     #626A82 clears it on all three light backgrounds the design uses (5.38 on
     white, 5.02 on paper, 4.67 on paper-2) and is about 7% darker, which is
     below the threshold of noticing as a change of colour and well above the
     threshold of noticing as a change in readability. Nothing else moves: no
     size, weight, spacing or layout.

     The Theme manager's own `text_muted` (#5A5F7A) is darker again; this token
     is the approved system's fixed value and is not resolved through it. */
  --hl-text-muted:#626A82;
  --hl-text-light:#FFFFFF;
  --hl-text-light-2:rgba(255,255,255,.74);
  /* The two quiet inks were raised in the visual correction pass, for the same
     reason --hl-text-muted was darkened at go-live: they failed WCAG AA on the
     bands they are used on, and a rendered-contrast sweep put numbers on it.

       tier 3  .50 → .60   was 4.44:1 on the deep-navy band
       tier 4  .34 → .48   was 2.96:1 on the near-black footer band

     Both now clear 4.5:1 on every band in the approved set from #04050E up to
     #12142E, which is where this ink is actually used — footer small print,
     disclaimers, chapter kickers, index numerals, the announcement meta line.
     They stay clearly quieter than tier 2 (.74), so the hierarchy the design
     depends on is unchanged; what changed is that the bottom of it is now
     readable. Nothing else moves: no size, weight, spacing or layout. */
  --hl-text-light-3:rgba(255,255,255,.60);
  --hl-text-light-4:rgba(255,255,255,.48);

  /* Borders */
  --hl-line:#E3E8F3;
  --hl-line-2:#D3DBEA;
  --hl-line-dark:rgba(255,255,255,.09);
  --hl-line-dark-2:rgba(255,255,255,.16);

  /* Shadows */
  --hl-sh-xs:0 1px 2px rgba(10,14,36,.06);
  --hl-sh-sm:0 2px 8px rgba(10,14,36,.06), 0 1px 2px rgba(10,14,36,.04);
  --hl-sh-md:0 12px 28px -10px rgba(10,14,36,.16), 0 4px 10px -4px rgba(10,14,36,.08);
  --hl-sh-lg:0 30px 60px -22px rgba(10,14,36,.28), 0 10px 24px -12px rgba(10,14,36,.12);
  --hl-sh-xl:0 50px 100px -30px rgba(6,8,24,.42), 0 16px 40px -16px rgba(6,8,24,.20);
  --hl-sh-glass:0 24px 60px -24px rgba(0,0,0,.65), inset 0 1px 0 rgba(255,255,255,.10);
  --hl-sh-red:0 12px 30px -10px rgba(207,41,39,.55);
  --hl-sh-navy:0 12px 30px -10px rgba(42,45,124,.45);

  /* Radii */
  --hl-r-xs:6px; --hl-r-sm:10px; --hl-r-md:14px; --hl-r-lg:20px;
  --hl-r-xl:26px; --hl-r-2xl:36px; --hl-r-3xl:48px; --hl-r-pill:999px;

  /* Spacing scale (4px base) */
  --hl-s-1:4px;  --hl-s-2:8px;   --hl-s-3:12px;  --hl-s-4:16px;  --hl-s-5:20px;
  --hl-s-6:24px; --hl-s-8:32px;  --hl-s-10:40px; --hl-s-12:48px; --hl-s-14:56px;
  --hl-s-16:64px;--hl-s-20:80px; --hl-s-24:96px; --hl-s-32:128px;--hl-s-40:160px;

  /* Section rhythm */
  --hl-sec-pad:clamp(76px, 7.4vw, 124px);
  --hl-sec-pad-sm:clamp(56px, 5vw, 84px);

  /* Flow rhythm — the step BETWEEN content groups inside a section.
     Section N applies these; the values are the ones the approved design
     already used most often, promoted from repetition into a contract. */
  --hl-flow-tight:var(--hl-s-6);   /* a subordinate group: chips, fine print */
  --hl-flow:var(--hl-s-8);         /* two peer groups: copy above an action row */
  --hl-flow-loose:var(--hl-s-12);  /* a group and a distinct composition */

  /* Layout */
  --hl-shell:1280px;
  --hl-gutter:clamp(20px, 3.6vw, 44px);
  --hl-nav-h:100px;
  --hl-logo-h:76px;
  /* Kept in step so the "hero under a transparent header" offset and the
     header itself can never disagree about the header's height. */
  --hl-header-height:var(--hl-nav-h);

  /* Typography — the approved faces, with the Theme manager's font settings as
     the fallback so a configured face still applies if the approved one fails
     to load. */
  --hl-ff-display:'Plus Jakarta Sans', var(--hl-font-heading, 'Segoe UI'), system-ui, -apple-system, sans-serif;
  --hl-ff-body:'Inter', var(--hl-font-body, 'Segoe UI'), system-ui, -apple-system, sans-serif;
  --hl-ff-mono:'IBM Plex Mono', var(--hl-font-mono, ui-monospace), Consolas, monospace;

  --hl-fs-display:clamp(2.4rem, 4vw, 3.5rem);
  --hl-fs-h1:clamp(2.2rem, 3.6vw, 3.15rem);
  --hl-fs-h2:clamp(1.85rem, 3vw, 2.75rem);
  --hl-fs-h3:clamp(1.28rem, 1.7vw, 1.62rem);
  --hl-fs-h4:1.06rem;
  --hl-fs-lede:clamp(1.02rem, 1.15vw, 1.16rem);
  --hl-fs-body:0.97rem;
  --hl-fs-sm:0.875rem;
  --hl-fs-xs:0.8rem;
  --hl-fs-micro:0.695rem;

  --hl-lh-tight:1.04;
  --hl-lh-snug:1.16;
  --hl-lh-body:1.62;

  --hl-ls-tight:-0.028em;
  --hl-ls-wide:0.14em;
  --hl-ls-wider:0.2em;

  /* Motion */
  --hl-e-out:cubic-bezier(.22,1,.36,1);
  --hl-e-inout:cubic-bezier(.65,0,.35,1);
  --hl-e-soft:cubic-bezier(.4,0,.2,1);
  --hl-t-fast:150ms;
  --hl-t-med:320ms;
  --hl-t-slow:600ms;
}

/* ── B · BASE ─────────────────────────────────────────────────────────────
   Only what the approved system needs on top of base.css. The resets are
   scoped to the approved component roots rather than applied globally, so CMS
   rich text keeps its bullets, numbering and indentation. */
html{ scroll-padding-top:calc(var(--hl-nav-h) + 16px); }

body.hl-body{
  background:var(--hl-white); color:var(--hl-text-body);
  font:400 var(--hl-fs-body)/var(--hl-lh-body) var(--hl-ff-body);
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  overflow-x:hidden;
}

/* :where() keeps these at ZERO specificity for the body part, so a component
   class always wins. Without it `body.hl-body h1` outranks `.hl-hero__h1` and
   the approved white headline renders in body ink on a dark hero — which is
   exactly the kind of quiet regression a base layer causes. */
/* The colour is a TOKEN, not the literal ink, and that is the whole point.
   `:where()` removes the body from the specificity sum but `h1` still counts,
   so this rule outranks the `color` a dark band sets by INHERITANCE — which is
   how five published pages ended up with a near-black H1 on a near-black hero
   at 1.02:1: `.hl-heroblock__title` sets no colour of its own, so this rule won
   and the headline was invisible. A component class that names a colour still
   beats this rule; a component that does not now follows the band, because the
   band re-points the token. See section L1. */
:where(body.hl-body) h1,
:where(body.hl-body) h2,
:where(body.hl-body) h3,
:where(body.hl-body) h4{
  font-family:var(--hl-ff-display); color:var(--hl-heading-ink, var(--hl-text-dark));
  letter-spacing:var(--hl-ls-tight); line-height:var(--hl-lh-snug); font-weight:700;
}
:where(body.hl-body) strong{ color:var(--hl-text-dark); font-weight:600; }
:where(body.hl-body) em{ font-style:normal; }
body.hl-body ::selection{ background:var(--hl-red-500); color:#fff; }

/* Inside a dark chapter the emphasis colours invert. */
.hl-section--dark strong, .hl-section--brand strong,
.hl-announce strong, .hl-footer strong, .hl-promo-modal strong{ color:#fff; }

/* The element resets the approved components assume. All at zero specificity,
   so any component class still wins — `.hl-btn` keeps its own background even
   though buttons are reset to none here. */
:where(body.hl-body) button{
  font:inherit; color:inherit; background:none; border:0; cursor:pointer;
}
:where(body.hl-body) a{ color:inherit; text-decoration:none; }
:where(body.hl-body) img, :where(body.hl-body) svg{ display:block; max-width:100%; }
:where(body.hl-body) figure{ margin:0; }
:where(body.hl-body) input, :where(body.hl-body) output{ font:inherit; }

/* List reset for the approved components; rich text is explicitly exempt.

   The reset owns LOOK, not FLOW.

   `padding` and `list-style` clear the browser's indent and bullet. No
   component overrides those, so they stay at this specificity.

   `margin` is a different job, and bundling it here was the single largest
   source of broken vertical rhythm on the site. At (0,1,1) this rule outranked
   every component class, so `.hl-chips{margin:var(--hl-s-6) 0}`,
   `.hl-btile__chips`, `.hl-cdlist`, `.hl-ilist`, `.hl-ioffer__pts`,
   `.hl-footer__contact` and a dozen more declared a vertical rhythm the page
   never received — every one of them computed to `margin:0`. That is why a hero
   CTA row and the capability chips under it ended up touching: the chips were
   asking for 24px and being told no.

   Splitting `margin` onto a (0,1,0) selector keeps the browser default
   suppressed — base.css `ul,ol{margin:0 0 1em}` is (0,0,1), still outranked —
   while letting a component that states its own spacing actually receive it.
   Lists with nothing to say are unaffected and stay at zero. */
.hl-section ul, .hl-section ol,
.hl-header ul, .hl-header ol,
.hl-footer ul, .hl-footer ol,
.hl-announce ul, .hl-drawer ul,
.hl-promo-modal ul{ padding:0; list-style:none; }

.hl-section :where(ul, ol),
.hl-header :where(ul, ol),
.hl-footer :where(ul, ol),
.hl-announce :where(ul, ol),
.hl-drawer :where(ul, ol),
.hl-promo-modal :where(ul, ol){ margin:0; }

.hl-rich ul{ list-style:disc; padding-left:1.35em; margin:0 0 1em; }
.hl-rich ol{ list-style:decimal; padding-left:1.35em; margin:0 0 1em; }

/* The skip link is the first thing in the tab order and must stay visible on
   focus regardless of the surrounding chapter. */
.hl-skip-link{
  position:fixed; top:-100px; left:var(--hl-s-4); z-index:200;
  background:var(--hl-white); color:var(--hl-text-dark); padding:10px 16px;
  border-radius:var(--hl-r-sm); font-weight:600; box-shadow:var(--hl-sh-md);
  transition:top var(--hl-t-med) var(--hl-e-out);
}
.hl-skip-link:focus{ top:var(--hl-s-4); }

/* ── C · APPROVED SYSTEM ──────────────────────────────────────────────────
   Everything below this line is the approved prototype stylesheet, ported.
   Edit the prototype first, then re-port: the prototype is the source of
   truth, this is the copy. */

/* ── 02 · PRIMITIVES ────────────────────────────────────────────────────── */
.hl-shell{ width:100%; max-width:var(--hl-shell); margin-inline:auto; padding-inline:var(--hl-gutter); }

/* The eyebrow, the section title and the outlined chapter numeral all read
   their colour through a token with the approved value as the fallback. Nothing
   changes by default — but it gives the page builder one safe place to alternate
   a section's accent (see section J) without any block view learning about it. */
.hl-eyebrow{
  display:inline-flex; align-items:center; gap:10px; margin-bottom:var(--hl-s-5);
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-body);
  letter-spacing:var(--hl-ls-wider); text-transform:uppercase;
  color:var(--hl-eb-ink, var(--hl-brand-red));
}
.hl-eyebrow i{
  width:3px; height:13px; border-radius:2px; flex:none;
  background:var(--hl-eb-bar, linear-gradient(180deg,var(--hl-red-400),var(--hl-red-600)));
  box-shadow:var(--hl-eb-glow, 0 0 12px rgba(207,41,39,.6));
}
.hl-eyebrow--light{ color:var(--hl-eb-ink, var(--hl-navy-300)); }

/* Section head */
.hl-shead{ margin-bottom:var(--hl-s-16); max-width:840px; }
.hl-shead--tight{ margin-bottom:var(--hl-s-12); }
.hl-shead__title{ font-size:var(--hl-fs-h2); color:var(--hl-hd-ink, inherit); }
.hl-shead__lede{ margin-top:var(--hl-s-5); font-size:var(--hl-fs-lede); color:var(--hl-text-muted); max-width:60ch; }
.hl-shead--light .hl-shead__title{ color:var(--hl-hd-ink, var(--hl-white)); }
.hl-shead--light .hl-shead__lede{ color:var(--hl-text-light-2); }
.hl-shead--center{ max-width:740px; margin-inline:auto; text-align:center; }
.hl-shead--split{
  max-width:none; display:grid; grid-template-columns:1.12fr .88fr;
  gap:var(--hl-s-10) var(--hl-s-16); align-items:end;
}
.hl-shead__aside{
  font-size:var(--hl-fs-sm); line-height:1.7; color:var(--hl-text-light-2);
  padding-left:var(--hl-s-6); border-left:1px solid var(--hl-line-dark-2); max-width:48ch;
}
.hl-shead__aside--dark{ color:var(--hl-text-muted); border-left-color:var(--hl-line); }

/* Buttons */
.hl-btn{
  --hl-btn-h:46px;
  position:relative; display:inline-flex; align-items:center; justify-content:center; gap:9px;
  height:var(--hl-btn-h); padding:0 22px; border-radius:var(--hl-r-pill);
  font:600 var(--hl-fs-sm)/1 var(--hl-ff-display); letter-spacing:-.01em; white-space:nowrap;
  transition:transform var(--hl-t-med) var(--hl-e-out), box-shadow var(--hl-t-med) var(--hl-e-out),
             background-color var(--hl-t-med) var(--hl-e-out), border-color var(--hl-t-med) var(--hl-e-out),
             color var(--hl-t-med) var(--hl-e-out);
}
.hl-btn .hl-arrow{ transition:transform var(--hl-t-med) var(--hl-e-out); }
.hl-btn:hover .hl-arrow{ transform:translateX(4px); }
.hl-btn:active{ transform:translateY(1px); }
.hl-btn--sm{ --hl-btn-h:40px; padding:0 18px; font-size:var(--hl-fs-xs); }
.hl-btn--lg{ --hl-btn-h:54px; padding:0 28px; font-size:.95rem; }
.hl-btn--xl{ --hl-btn-h:60px; padding:0 34px; font-size:1rem; }
.hl-btn--block{ width:100%; }

.hl-btn--primary{
  color:#fff; background:linear-gradient(170deg,var(--hl-red-400),var(--hl-red-600));
  box-shadow:var(--hl-sh-red), inset 0 1px 0 rgba(255,255,255,.28);
}
.hl-btn--primary:hover{ box-shadow:0 16px 38px -10px rgba(207,41,39,.65), inset 0 1px 0 rgba(255,255,255,.3); transform:translateY(-2px); }

.hl-btn--ghost{
  color:#fff; border:1px solid var(--hl-line-dark-2); background:rgba(255,255,255,.03);
  backdrop-filter:blur(6px);
}
.hl-btn--ghost:hover{ background:rgba(255,255,255,.09); border-color:rgba(255,255,255,.3); transform:translateY(-2px); }

.hl-btn--dark{
  color:#fff; background:linear-gradient(170deg,var(--hl-ink-750),var(--hl-ink-850));
  box-shadow:var(--hl-sh-navy), inset 0 1px 0 rgba(255,255,255,.16);
}
.hl-btn--dark:hover{ transform:translateY(-2px); box-shadow:0 18px 40px -12px rgba(42,45,124,.55), inset 0 1px 0 rgba(255,255,255,.2); }

.hl-btn--light{ color:var(--hl-ink-800); background:#fff; box-shadow:0 10px 24px -12px rgba(0,0,0,.6); }
.hl-btn--light:hover{ transform:translateY(-2px); }

.hl-btn--link{
  height:auto; padding:0; border-radius:0; color:var(--hl-brand-red);
  font-size:var(--hl-fs-sm); gap:7px; align-self:flex-start;
}
.hl-btn--link::after{
  content:""; position:absolute; left:0; right:22px; bottom:-4px; height:1px;
  background:currentColor; opacity:.28; transition:opacity var(--hl-t-med), right var(--hl-t-med) var(--hl-e-out);
}
.hl-btn--link:hover::after{ opacity:.7; right:0; }
.hl-btn--link-light{ color:var(--hl-navy-300); }

/* Chips */
.hl-chips{ display:flex; flex-wrap:wrap; gap:8px; margin:var(--hl-s-6) 0; }
.hl-chips li{
  padding:7px 13px; border-radius:var(--hl-r-pill); font-size:var(--hl-fs-xs); font-weight:500;
  color:var(--hl-text-light-2); background:rgba(255,255,255,.05);
  border:1px solid var(--hl-line-dark); backdrop-filter:blur(4px);
}
.hl-chips--light li{ color:var(--hl-text-body); background:var(--hl-paper); border-color:var(--hl-line); }

.hl-caret{
  width:7px; height:7px; flex:none; margin-left:2px;
  border-right:1.6px solid currentColor; border-bottom:1.6px solid currentColor;
  transform:rotate(45deg) translateY(-1px); opacity:.5;
  transition:transform var(--hl-t-med) var(--hl-e-out), opacity var(--hl-t-med);
}

/* Icon system — masked inline SVG so colour follows currentColor */
[data-ico]{
  display:block; flex:none; background:currentColor;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-position:center; mask-position:center;
  -webkit-mask-size:contain; mask-size:contain;
}
[data-ico="card"]{ -webkit-mask-image:var(--hl-i-card); mask-image:var(--hl-i-card); }
[data-ico="ach"]{ -webkit-mask-image:var(--hl-i-ach); mask-image:var(--hl-i-ach); }
[data-ico="pos"]{ -webkit-mask-image:var(--hl-i-pos); mask-image:var(--hl-i-pos); }
[data-ico="tag"]{ -webkit-mask-image:var(--hl-i-tag); mask-image:var(--hl-i-tag); }
[data-ico="route"]{ -webkit-mask-image:var(--hl-i-route); mask-image:var(--hl-i-route); }
[data-ico="grow"]{ -webkit-mask-image:var(--hl-i-grow); mask-image:var(--hl-i-grow); }
[data-ico="shield"]{ -webkit-mask-image:var(--hl-i-shield); mask-image:var(--hl-i-shield); }
[data-ico="layers"]{ -webkit-mask-image:var(--hl-i-layers); mask-image:var(--hl-i-layers); }
[data-ico="bank"]{ -webkit-mask-image:var(--hl-i-bank); mask-image:var(--hl-i-bank); }
[data-ico="support"]{ -webkit-mask-image:var(--hl-i-support); mask-image:var(--hl-i-support); }
[data-ico="grid"]{ -webkit-mask-image:var(--hl-i-grid); mask-image:var(--hl-i-grid); }
[data-ico="map"]{ -webkit-mask-image:var(--hl-i-map); mask-image:var(--hl-i-map); }
[data-ico="retail"]{ -webkit-mask-image:var(--hl-i-retail); mask-image:var(--hl-i-retail); }
[data-ico="rest"]{ -webkit-mask-image:var(--hl-i-rest); mask-image:var(--hl-i-rest); }
[data-ico="fuel"]{ -webkit-mask-image:var(--hl-i-fuel); mask-image:var(--hl-i-fuel); }
[data-ico="salon"]{ -webkit-mask-image:var(--hl-i-salon); mask-image:var(--hl-i-salon); }
[data-ico="prof"]{ -webkit-mask-image:var(--hl-i-prof); mask-image:var(--hl-i-prof); }

:root{
  --hl-i-card:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round"><rect x="2.5" y="5.5" width="19" height="13" rx="2.5"/><path d="M2.5 10h19M6 14.5h4"/></svg>');
  --hl-i-ach:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 8h13l-2.5-2.5M20 16H7l2.5 2.5"/></svg>');
  --hl-i-pos:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round"><rect x="6" y="2.5" width="12" height="19" rx="2.5"/><path d="M9 7h6M9 11h6M9 15h2"/></svg>');
  --hl-i-tag:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12.5 3H20a1 1 0 011 1v7.5L11 21.5 2.5 13z"/><circle cx="16.8" cy="7.2" r="1.4"/></svg>');
  --hl-i-route:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round"><circle cx="5" cy="5.5" r="2.2"/><circle cx="19" cy="18.5" r="2.2"/><path d="M5 7.7v4.8a4 4 0 004 4h6"/></svg>');
  --hl-i-grow:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 19.5h17"/><path d="M6.5 16V11M11 16V7.5M15.5 16v-6M20 16V4.5"/></svg>');
  --hl-i-shield:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2.8l7.5 2.6v6c0 4.6-3.1 8.4-7.5 9.8-4.4-1.4-7.5-5.2-7.5-9.8v-6z"/><path d="M9 12l2.2 2.2L15.5 10"/></svg>');
  --hl-i-layers:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2.8l9 4.7-9 4.7-9-4.7z"/><path d="M3 12.2l9 4.7 9-4.7M3 16.9l9 4.7 9-4.7"/></svg>');
  --hl-i-bank:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9.5l9-5.5 9 5.5"/><path d="M5.5 9.5v9M10 9.5v9M14 9.5v9M18.5 9.5v9"/><path d="M2.5 20h19"/></svg>');
  --hl-i-support:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 14v-2a8 8 0 0116 0v2"/><rect x="2.5" y="13.5" width="4" height="6" rx="1.6"/><rect x="17.5" y="13.5" width="4" height="6" rx="1.6"/><path d="M19.5 19.5v.5a2.5 2.5 0 01-2.5 2.5h-3"/></svg>');
  --hl-i-grid:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round"><rect x="3" y="3" width="7.5" height="7.5" rx="2"/><rect x="13.5" y="3" width="7.5" height="7.5" rx="2"/><rect x="3" y="13.5" width="7.5" height="7.5" rx="2"/><rect x="13.5" y="13.5" width="7.5" height="7.5" rx="2"/></svg>');
  --hl-i-map:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9.2"/><path d="M2.8 12h18.4"/><ellipse cx="12" cy="12" rx="4.2" ry="9.2"/></svg>');
  --hl-i-retail:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8.5L5 3.5h14l2 5"/><path d="M4 8.5v11a1 1 0 001 1h14a1 1 0 001-1v-11"/><path d="M9 20.5v-6h6v6"/></svg>');
  --hl-i-rest:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M7 3v8a2.5 2.5 0 005 0V3M9.5 11v10"/><path d="M16.5 3v18M16.5 3c2 1 3 3 3 5.5s-1 3.5-3 3.5"/></svg>');
  --hl-i-fuel:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="3" width="10" height="18" rx="2"/><path d="M6.5 7h5M14 9h3a2 2 0 012 2v6a1.5 1.5 0 003 0v-6l-2.5-4"/></svg>');
  --hl-i-salon:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="18" r="2.6"/><circle cx="18" cy="18" r="2.6"/><path d="M7.8 16L18 4M16.2 16L6 4"/></svg>');
  --hl-i-prof:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2.5" y="7" width="19" height="13" rx="2.5"/><path d="M9 7V5a2 2 0 012-2h2a2 2 0 012 2v2M2.5 12.5h19"/></svg>');
  --hl-star:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2l2.9 6.3 6.9.8-5.1 4.7 1.4 6.8L12 17.3 5.9 20.6l1.4-6.8L2.2 9.1l6.9-.8z" fill="%23fff"/></svg>');
}

/* Scroll reveal is NOT ported.
   The prototype's `[data-reveal]` engine is replaced by the production one
   (`data-hl-reveal` / `data-hl-stagger`, base.css + modules/animations.js),
   which is strictly safer: the hidden state only applies once JavaScript has
   confirmed it can animate, and a dead-man's switch reveals everything if the
   observer or the library ever stalls. Ported markup therefore carries
   `data-hl-reveal`, never `data-reveal`. */

/* ── 03 · INFRASTRUCTURE LANGUAGE ───────────────────────────────────────── */
.hl-infra{ position:absolute; inset:0; overflow:hidden; pointer-events:none; z-index:0; }
section > .hl-shell,
section > .hl-infra ~ .hl-shell{ position:relative; z-index:1; }

/* `.hl-container` needs the same lift. Every composition that hard-coded this
   layer happened to wrap its content in `.hl-shell`, so the rule above was
   enough — but the treatment is an administrator's choice now, and the CTA and
   content chapters wrap in `.hl-container`. `pointer-events:none` already
   protects the buttons; this keeps the paint order explicit rather than
   depending on source order. */
section > .hl-infra ~ .hl-container{ position:relative; z-index:1; }

.hl-infra__grid{
  position:absolute; inset:0;
  background-image:
    linear-gradient(to right, rgba(255,255,255,.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255,255,255,.05) 1px, transparent 1px);
  background-size:80px 80px;
  mask-image:radial-gradient(ellipse 92% 74% at 50% 22%, #000 18%, transparent 80%);
  -webkit-mask-image:radial-gradient(ellipse 92% 74% at 50% 22%, #000 18%, transparent 80%);
}
.hl-infra__grid--soft{ opacity:.6;
  mask-image:radial-gradient(ellipse 90% 90% at 50% 50%, #000 10%, transparent 78%);
  -webkit-mask-image:radial-gradient(ellipse 90% 90% at 50% 50%, #000 10%, transparent 78%); }
.hl-infra__grid--light{
  background-image:
    linear-gradient(to right, rgba(42,45,124,.055) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(42,45,124,.055) 1px, transparent 1px);
  background-size:72px 72px;
}

.hl-infra__glow{ position:absolute; border-radius:50%; filter:blur(90px); }
.hl-infra__glow--a{ width:46vw; height:46vw; right:-7vw; top:-15vw; background:rgba(58,63,163,.36); }
.hl-infra__glow--b{ width:30vw; height:30vw; right:22vw; top:24vw; background:rgba(207,41,39,.13); }
.hl-infra__glow--c{ width:28vw; height:28vw; left:-9vw; top:6vw;  background:rgba(122,92,240,.13); }
.hl-infra__glow--sys{ width:70vw; height:38vw; left:15vw; bottom:-18vw; background:rgba(42,45,124,.42); }
.hl-infra__glow--ind{ width:44vw; height:44vw; right:-6vw; top:-8vw; background:rgba(42,45,124,.5); }
.hl-infra__glow--net{ width:60vw; height:40vw; left:20vw; top:-14vw; background:rgba(42,45,124,.4); }
.hl-infra__glow--fund{ width:52vw; height:34vw; right:-6vw; bottom:-12vw; background:rgba(207,41,39,.13); }
.hl-infra__glow--story{ width:50vw; height:36vw; right:-12vw; top:8vw; background:rgba(42,45,124,.05); }

/* Routes: a faint permanent path plus a travelling signal */
.hl-infra__routes{ position:absolute; inset:0; width:100%; height:100%; }
.hl-rte__base{ stroke:rgba(255,255,255,.10); stroke-width:1.2; fill:none; }
.hl-rte__base--dim{ stroke:rgba(255,255,255,.06); stroke-dasharray:3 6; }
.hl-infra--light .hl-rte__base{ stroke:rgba(42,45,124,.14); }

.hl-rte__amb{
  stroke:rgba(144,150,228,.65); stroke-width:1.6; fill:none; stroke-linecap:round;
  stroke-dasharray:70 2400; stroke-dashoffset:2470;
  animation:hls-rteFlow 11s linear infinite; animation-delay:var(--hl-d,0s);
}
.hl-infra--light .hl-rte__amb{ stroke:rgba(90,97,204,.55); }
@keyframes hls-rteFlow{ to{ stroke-dashoffset:0 } }

.hl-rte__flow{
  stroke:url(#hl-flow-gradient); stroke-width:2.4; fill:none; stroke-linecap:round;
  stroke-dasharray:26 460; stroke-dashoffset:486;
  animation:hls-flow 3.6s var(--hl-e-inout) infinite; animation-delay:var(--hl-d,0ms);
  filter:drop-shadow(0 0 6px rgba(122,130,255,.65));
}
.hl-rte__flow--dim{ opacity:.5; stroke-width:1.8; }
@keyframes hls-flow{ 0%{stroke-dashoffset:486} 58%,100%{stroke-dashoffset:0} }

/* Seam family — the only section-transition treatments used on the page */
.hl-seam{
  position:absolute; left:0; right:0; bottom:0; height:1px; z-index:3; pointer-events:none;
  background:linear-gradient(90deg, transparent, rgba(255,255,255,.14) 24%,
    rgba(207,41,39,.55) 50%, rgba(255,255,255,.14) 76%, transparent);
}
.hl-seam--top{ top:0; bottom:auto; }
.hl-seam--top::after{
  content:""; position:absolute; left:0; right:0; top:0; height:90px;
  background:linear-gradient(180deg, rgba(245,247,252,.09), transparent);
}
.hl-seam--bottom{ bottom:0; top:auto; }

/* ── 04 · DEVICE KIT + PRODUCT SLOTS ────────────────────────────────────── */
/* Each product sits in a .hl-pslot. To use real artwork, drop an <img> in place
   of the .hl-dev span — the slot centres and height-constrains either one. */
/*
 * THE MEDIA FRAME, and why the first row is a variable.
 *
 * `grid-template-rows` was `1fr auto`: artwork row, caption row. `1fr` in a box
 * with no height of its own is content-sized, so the artwork's own dimensions
 * decided how tall the slot was. In the marketing compositions that is correct
 * and deliberate — a device on a lit stage should be as tall as the device. In a
 * CARD GRID it is the defect requirement 5 describes, and the measurement is
 * unambiguous: on /pos-terminals/catalog the six art areas resolved to 158,
 * 169.1, 201.1, 227.1, 251.1 and 279.1 px — a 121px spread inside one grid, so
 * no two product titles started on the same line. Substituting real photography
 * moved the CARD height by 26px purely on the shape of the upload (a 300x800
 * portrait produced a 442.6px card, a 2000x1000 landscape a 416.6px one).
 *
 * So the first row becomes `var(--hl-pslot-h, 1fr)`. Unset, the fallback is the
 * old value and every existing composition renders exactly as before. A context
 * that needs a deterministic frame — a catalog card, a related-equipment row —
 * sets one custom property and gets a fixed band that the artwork fits INTO
 * rather than one the artwork inflates. Uploaded dimensions then decide only how
 * the picture is letterboxed inside that band, which is requirement 5's
 * "original uploaded dimensions must NOT control card dimensions", enforced by
 * geometry rather than by asking whoever uploads to crop first.
 *
 * The caption's 14px used to be the grid's `gap`. A gutter between two explicit
 * tracks exists whether or not the second one is occupied, so an image-only slot
 * carried 14px of dead space below the picture and a slot with a caption did
 * not — same frame, two heights, which defeats the point. The spacing now
 * belongs to the caption, so it appears exactly when the caption does.
 */
.hl-pslot{ position:relative; display:grid; grid-template-rows:var(--hl-pslot-h, 1fr) auto;
  justify-items:center; align-items:center; width:100%; min-width:0; }
.hl-pslot .hl-dev,
.hl-pslot img{ margin-inline:auto; }
/*
 * `max-width` is the half that was missing. With only `max-height` an upload
 * wider than it is tall resolves a width from its aspect ratio and nothing
 * clamps it — the grid area happens to catch it in a card, but nothing in the
 * cascade said so, and the first context without a grid to absorb it grows a
 * horizontal scrollbar. `--hl-pslot-inset` is the internal padding: the artwork
 * is inset from the frame rather than touching the card's hairline, and because
 * the box is border-box the inset comes out of the frame instead of adding to
 * it, so padding a slot cannot change a card's height.
 */
.hl-pslot img{
  max-width:100%; max-height:100%; width:auto; height:auto;
  padding:var(--hl-pslot-inset, 0); object-fit:contain;
}
/* The illustrative-artwork caption. See `partials/product-slot.php` for why it
   is no longer `[Bracketed Monospace]`: same honesty, in the design system's
   own voice instead of in something that reads as unfinished markup. The name
   is the emphasis, the qualification is the quiet part, and the pair stacks so
   a long product name does not force the slot wider. */
.hl-pslot__ph{
  margin-top:12px; display:flex; flex-direction:column; align-items:center; gap:3px;
  text-align:center; max-width:100%;
}
.hl-pslot__phname{
  font:600 var(--hl-fs-xs)/1.25 var(--hl-ff-body); letter-spacing:-.005em;
  color:var(--hl-ph-name, var(--hl-text-light-2));
  overflow-wrap:anywhere;
}
.hl-pslot__phnote{
  font:500 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-ph-note, var(--hl-text-light-4));
}
/* A slot that stands alone gets a hairline so the qualification reads as a
   caption rather than as stray text under the artwork. */
.hl-pslot__phnote::before{
  content:""; display:block; width:18px; height:1px; margin:0 auto 6px;
  background:currentColor; opacity:.5;
}

/* ── In a CARD the caption must not change the card's height ───────────────
   A row of product cards aligns on its category chip, its title and its foot.
   If the caption is a flow row of the slot then a silhouette card is ~30px
   taller in the media area than a photograph card beside it and the whole row
   goes ragged. Inside a card the caption is therefore laid over the foot of the
   artwork box: same information, no effect on the grid. */
.hl-pcard .hl-pslot,
.hl-hcard .hl-pslot{ position:relative; }
.hl-pcard .hl-pslot__ph,
.hl-hcard .hl-pslot__ph{
  position:absolute; inset:auto 0 0; margin:0; pointer-events:none;
}
.hl-pcard .hl-pslot .hl-dev,
.hl-hcard .hl-pslot .hl-dev,
.hl-pcard .hl-pslot img,
.hl-hcard .hl-pslot img{ margin-bottom:var(--hl-s-4); }
.hl-infra--light ~ .hl-shell .hl-pslot__ph,
.hl-hw .hl-pslot__ph{ --hl-ph-name:var(--hl-text-dark); --hl-ph-note:var(--hl-text-muted); }

.hl-dev{
  --hl-body:linear-gradient(158deg,#252C63 0%,#151A44 42%,#0B0E28 100%);
  --hl-screen:linear-gradient(152deg,#4A52B8 0%,#2B3182 48%,#1A1F5C 100%);
  position:relative; display:block; flex:none; border-radius:16px;
  background:var(--hl-body);
  border:1px solid rgba(255,255,255,.14);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.22),
    inset 0 -14px 26px -14px rgba(0,0,0,.6),
    0 22px 40px -18px rgba(6,8,24,.7);
}
.hl-dev::before,.hl-dev::after{ content:""; position:absolute; }

.hl-dev--counter{ width:196px; height:132px; border-radius:14px;
  background:
    radial-gradient(circle at 90% 12%, var(--hl-red-500) 0 2.6px, transparent 3px) no-repeat,
    var(--hl-body); }
.hl-dev--counter::before{ inset:13px 13px auto 13px; height:54px; border-radius:7px;
  background:var(--hl-screen); box-shadow:inset 0 0 0 1px rgba(255,255,255,.1), inset 0 8px 14px -8px rgba(255,255,255,.4); }
.hl-dev--counter::after{ left:13px; right:13px; bottom:13px; height:44px; border-radius:6px;
  background:radial-gradient(circle, rgba(255,255,255,.4) 1.7px, transparent 2px) 0 0/25% 33.34%; }

.hl-dev--smart{ width:134px; height:214px; border-radius:20px; }
.hl-dev--smart::before{ inset:11px 11px 30px 11px; border-radius:13px;
  background:var(--hl-screen); box-shadow:inset 0 0 0 1px rgba(255,255,255,.1), inset 0 12px 20px -12px rgba(255,255,255,.45); }
.hl-dev--smart::after{ left:50%; bottom:11px; width:44px; height:4px; margin-left:-22px;
  border-radius:3px; background:rgba(255,255,255,.3); }

.hl-dev--portable{ width:116px; height:190px; border-radius:18px; }
.hl-dev--portable::before{ inset:11px 11px auto 11px; height:96px; border-radius:10px;
  background:var(--hl-screen); box-shadow:inset 0 0 0 1px rgba(255,255,255,.1), inset 0 10px 18px -10px rgba(255,255,255,.45); }
.hl-dev--portable::after{ left:13px; right:13px; bottom:12px; height:60px;
  background:radial-gradient(circle, rgba(255,255,255,.4) 1.6px, transparent 2px) 0 0/33.34% 25%; }

.hl-dev--reader{ width:108px; height:108px; border-radius:26px; }
.hl-dev--reader::before{ inset:22px; border-radius:50%;
  background:conic-gradient(from 210deg, rgba(255,255,255,.06), rgba(255,255,255,.02));
  box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.28), 0 0 0 6px rgba(255,255,255,.05); }
.hl-dev--reader::after{ left:50%; top:50%; width:26px; height:26px; transform:translate(-50%,-50%);
  border-radius:50%; border:1.5px solid var(--hl-red-400);
  box-shadow:0 0 0 5px rgba(207,41,39,.16), 0 0 16px rgba(207,41,39,.5); }

.hl-dev--rest{ width:186px; height:164px; background:none; border:0; box-shadow:none; border-radius:0; }
.hl-dev--rest::before{ inset:0 0 46px 0; border-radius:12px;
  background:var(--hl-body); border:1px solid rgba(255,255,255,.14);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 22px 38px -20px rgba(6,8,24,.75); }
.hl-dev--rest::after{
  left:50%; bottom:0; width:86px; height:46px; margin-left:-43px;
  background:linear-gradient(180deg,#1B2158,#0B0E28);
  clip-path:polygon(34% 0,66% 0,100% 100%,0 100%);
  border-bottom:2px solid rgba(255,255,255,.16);
}

.hl-dev--pump{ width:136px; height:242px; border-radius:16px 16px 8px 8px;
  background:
    linear-gradient(var(--hl-red-500),var(--hl-red-500)) 24px calc(100% - 30px)/7px 46px no-repeat,
    linear-gradient(var(--hl-red-500),var(--hl-red-500)) 38px calc(100% - 30px)/7px 28px no-repeat,
    linear-gradient(rgba(255,255,255,.34),rgba(255,255,255,.34)) 52px calc(100% - 30px)/7px 36px no-repeat,
    linear-gradient(rgba(255,255,255,.2),rgba(255,255,255,.2)) 66px calc(100% - 30px)/7px 22px no-repeat,
    var(--hl-body);
}
.hl-dev--pump::before{ inset:18px 16px auto 16px; height:78px; border-radius:6px;
  background:var(--hl-screen); box-shadow:inset 0 0 0 1px rgba(255,255,255,.1); }
.hl-dev--pump::after{ right:-14px; top:112px; width:16px; height:56px; border-radius:6px;
  background:linear-gradient(180deg,#2A3070,#12163C); border:1px solid rgba(255,255,255,.13); }

.hl-dev--invoice{ width:200px; height:146px; border-radius:12px; }
.hl-dev--invoice::before{ inset:12px 12px auto 12px; height:26px; border-radius:6px;
  background:linear-gradient(90deg,rgba(207,41,39,.9),rgba(207,41,39,.15)); }
.hl-dev--invoice::after{ left:12px; right:12px; top:50px; height:70px;
  background:
    linear-gradient(rgba(255,255,255,.34),rgba(255,255,255,.34)) 0 0/70% 5px no-repeat,
    linear-gradient(rgba(255,255,255,.2),rgba(255,255,255,.2)) 0 16px/88% 5px no-repeat,
    linear-gradient(rgba(255,255,255,.2),rgba(255,255,255,.2)) 0 32px/52% 5px no-repeat,
    linear-gradient(rgba(255,255,255,.34),rgba(255,255,255,.34)) 0 54px/38% 8px no-repeat;
}

/* ── 05 · ANNOUNCEMENT BAR ──────────────────────────────────────────────── */
.hl-announce{
  position:relative; z-index:60; background:var(--hl-ink-950);
  border-bottom:1px solid rgba(255,255,255,.07); overflow:hidden;
  /* The footprint the close button occupies at the right edge. It is
     `position:absolute` at EVERY width, so it reserves no space of its own and
     the row has to keep clear of it deliberately: its inset, plus its width,
     plus a gap so type never sits hard against it. */
  --hl-announce-close:calc(2rem + clamp(.35rem,1.5vw,1rem) + 10px);
}
.hl-announce.is-closed{ display:none; }
.hl-announce__glow{
  position:absolute; inset:0;
  background:
    radial-gradient(600px 60px at 22% 120%, rgba(207,41,39,.30), transparent 70%),
    radial-gradient(700px 70px at 72% -20%, rgba(42,45,124,.55), transparent 70%);
}
.hl-announce__inner{
  position:relative; display:flex; align-items:center; justify-content:space-between;
  gap:var(--hl-s-6); min-height:46px; padding-block:8px;
  /* layout.css styles this same element for an EARLIER, centred bar design:
     `justify-content:center; text-align:center`. This block supersedes it, but
     it only restated `justify-content`, so the centring survived in the half
     nobody had restated — invisibly on desktop, where every flex child is
     shrink-to-fit and centring inside it changes nothing, and visibly on a
     phone, where the message wraps to the full row and its prose then sat
     CENTRED between a left-flush badge and a left-flush CTA. Restating it
     finishes the override. */
  text-align:left;
  /* Keep the row clear of the absolutely-positioned close button.
     layout.css reserved this as a flat `padding-right:2.75rem`, on the very
     element `.hl-shell` (line 320) gives `padding-inline:var(--hl-gutter)` to —
     so the gutter overwrote it at every width, and the clearance only appeared
     to work because that gutter is `clamp(20px,3.6vw,44px)` and 44px is about
     the button's width. Where the clamp bottoms out the reservation vanished
     with it: at 430 and 390 the message's first line ran 28-30px UNDERNEATH
     the button. Taking the larger of the two is what was meant all along, and
     it no longer depends on a page gutter happening to be wide enough. */
  padding-right:max(var(--hl-gutter),var(--hl-announce-close));
}
.hl-announce__message{ display:flex; align-items:center; gap:14px; margin:0; flex-wrap:wrap;
  font-size:var(--hl-fs-xs); color:var(--hl-text-light-2); }
.hl-announce__tag{
  padding:4px 10px; border-radius:var(--hl-r-xs); background:rgba(207,41,39,.16);
  border:1px solid rgba(207,41,39,.38); color:var(--hl-red-300);
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide); text-transform:uppercase;
}
.hl-announce__text strong{ color:#fff; font-weight:600; }
.hl-announce__cta{
  display:inline-flex; align-items:center; gap:6px; color:#fff; font-weight:600;
  border-bottom:1px solid rgba(255,255,255,.3); padding-bottom:1px;
  transition:border-color var(--hl-t-fast), color var(--hl-t-fast);
}
.hl-announce__cta:hover{ color:var(--hl-red-300); border-color:var(--hl-red-400); }
.hl-announce__cta .hl-arrow{ transition:transform var(--hl-t-med) var(--hl-e-out); }
.hl-announce__cta:hover .hl-arrow{ transform:translateX(3px); }
.hl-announce__aside{ display:flex; align-items:center; gap:var(--hl-s-5); }

/* The supporting metric only earns its place when the bar still reads as ONE
   line with it. The old breakpoint was 1199px, set when the message was
   wrapping to two lines from 901px up (audit CH-02) — but the cause of that
   wrapping was invalid markup, not width: `rich()` was emitting a <p> into
   `.hl-announce__text`, which sits inside `.hl-announce__message`'s own <p>,
   so the parser closed the outer paragraph early and turned one flex child
   into four. With `richInline()` supplying the message that no longer happens.
   Re-measured afterwards, the metric holds the same row down to 1100px, so the
   breakpoint moves down with it and the metric is now visible on tablet
   landscape where it was previously hidden.
   1024px is where it genuinely stops fitting: the bar goes 47px → 82px there,
   and 74px even with the gaps tightened, which is the second row this pass
   exists to remove. Below 1100 the metric gives way rather than the height. */
@media (max-width:1099px){
  .hl-announce__meta{ display:none }
}
.hl-announce__meta{ color:var(--hl-text-light-3); font-size:var(--hl-fs-micro);
  letter-spacing:.08em; text-transform:uppercase; white-space:nowrap; }
.hl-announce__close{
  width:26px; height:26px; display:grid; place-items:center; border-radius:var(--hl-r-xs);
  color:var(--hl-text-light-3); transition:background var(--hl-t-fast), color var(--hl-t-fast);
}
.hl-announce__close:hover{ background:rgba(255,255,255,.08); color:#fff; }
.hl-announce__close svg{ width:12px; height:12px; stroke:currentColor; stroke-width:1.6; fill:none; }

/* ── 06 · NAVIGATION ────────────────────────────────────────────────────── */
/* Official stacked lockup, unmodified. The file carries its own clear space;
   the negative margin only cancels the built-in left inset so the wordmark
   aligns optically with the content grid. */
.hl-logo{ display:block; flex:none; }
.hl-logo img{ height:var(--hl-logo-h); width:auto; margin-left:calc(var(--hl-logo-h) * -0.1123); }
.hl-logo--sm{ --hl-logo-h:56px; }
.hl-logo--foot{ --hl-logo-h:118px; }
.hl-logo--foot img{ margin-left:calc(var(--hl-logo-h) * -0.1123); }

.hl-header{
  position:sticky; top:0; z-index:50; background:transparent;
  border-bottom:1px solid transparent;
  transition:background var(--hl-t-med) var(--hl-e-soft), box-shadow var(--hl-t-med), border-color var(--hl-t-med);
}
/* Height is fixed so becoming "stuck" can never reflow the document. */
.hl-header__inner{ display:flex; align-items:center; gap:var(--hl-s-8); height:var(--hl-nav-h); }
.hl-header.is-stuck{
  background:rgba(7,9,25,.94); backdrop-filter:blur(18px) saturate(140%);
  border-bottom-color:var(--hl-line-dark); box-shadow:0 18px 40px -24px rgba(0,0,0,.8);
}

.hl-nav{ margin-left:auto; }
.hl-nav__list{ display:flex; align-items:center; gap:2px; }
.hl-nav__link{
  display:inline-flex; align-items:center; gap:6px; padding:10px 14px; border-radius:var(--hl-r-sm);
  font:500 var(--hl-fs-sm)/1 var(--hl-ff-display); color:var(--hl-text-light-2); letter-spacing:-.01em;
  white-space:nowrap; transition:color var(--hl-t-fast), background var(--hl-t-fast);
}
.hl-nav__link:hover,.hl-nav__item.is-open .hl-nav__link{ color:#fff; background:rgba(255,255,255,.06); }
.hl-nav__item.is-open .hl-caret{ transform:rotate(-135deg) translateY(-1px); opacity:.9; }
.hl-nav__item{ position:relative; }
.hl-nav__item.is-open::after{
  content:""; position:absolute; left:14px; right:14px; bottom:-6px; height:2px; border-radius:2px;
  background:var(--hl-red-500);
}
.hl-header__actions{ display:flex; align-items:center; gap:12px; flex:none; }
.hl-header__login{
  font:500 var(--hl-fs-sm)/1 var(--hl-ff-display); color:var(--hl-text-light-2); padding:8px 4px;
  transition:color var(--hl-t-fast);
}
.hl-header__login:hover{ color:#fff; }

.hl-mega{
  position:absolute; left:0; right:0; top:100%;
  background:linear-gradient(180deg, #0A0C22, #070919);
  backdrop-filter:blur(22px) saturate(150%);
  border-top:1px solid var(--hl-line-dark); border-bottom:1px solid var(--hl-line-dark);
  box-shadow:0 40px 80px -30px rgba(0,0,0,.9);
  opacity:0; transform:translateY(-10px); pointer-events:none;
  transition:opacity var(--hl-t-med) var(--hl-e-out), transform var(--hl-t-med) var(--hl-e-out);
}
.hl-mega[hidden]{ display:none; }
.hl-mega.is-open{ opacity:1; transform:none; pointer-events:auto; }
.hl-mega__shell{ display:grid; grid-template-columns:.85fr 1.6fr; gap:var(--hl-s-16);
  padding-block:var(--hl-s-12) var(--hl-s-14); }
.hl-mega__shell--2{ grid-template-columns:.8fr 1.7fr; }
.hl-mega__title{ font-size:1.5rem; color:#fff; margin-bottom:var(--hl-s-4); }
.hl-mega__copy{ font-size:var(--hl-fs-sm); color:var(--hl-text-light-2); margin-bottom:var(--hl-s-6); max-width:34ch; }
.hl-mega__grid{ display:grid; grid-template-columns:repeat(4,1fr); gap:10px; align-content:start; }
.hl-mega__grid--5{ grid-template-columns:repeat(5,1fr); }
.hl-mega__card{
  display:flex; flex-direction:column; gap:6px; padding:16px;
  border-radius:var(--hl-r-md); border:1px solid var(--hl-line-dark); background:rgba(255,255,255,.045);
  transition:background var(--hl-t-med), border-color var(--hl-t-med), transform var(--hl-t-med) var(--hl-e-out);
}
.hl-mega__card:hover{ background:rgba(255,255,255,.09); border-color:var(--hl-line-dark-2); transform:translateY(-3px); }
.hl-mega__ico{ width:19px; height:19px; color:var(--hl-navy-300); margin-bottom:6px; transition:color var(--hl-t-med); }
.hl-mega__card:hover .hl-mega__ico{ color:var(--hl-red-400); }
.hl-mega__card b{ font:600 var(--hl-fs-sm)/1.3 var(--hl-ff-display); color:#fff; letter-spacing:-.012em; }
.hl-mega__card i{ font-size:var(--hl-fs-xs); color:var(--hl-text-light-3); line-height:1.45; }

.hl-burger{ display:none; width:44px; height:44px; border-radius:var(--hl-r-sm);
  border:1px solid var(--hl-line-dark-2); background:rgba(255,255,255,.04);
  flex-direction:column; align-items:center; justify-content:center; gap:5px; margin-left:auto; }
.hl-burger span{ display:block; width:18px; height:1.6px; background:#fff; border-radius:2px;
  transition:transform var(--hl-t-med) var(--hl-e-out), opacity var(--hl-t-med); }
.hl-burger[aria-expanded="true"] span:nth-child(1){ transform:translateY(6.6px) rotate(45deg); }
.hl-burger[aria-expanded="true"] span:nth-child(2){ opacity:0; }
.hl-burger[aria-expanded="true"] span:nth-child(3){ transform:translateY(-6.6px) rotate(-45deg); }

.hl-drawer{ position:fixed; inset:0; z-index:90; }
.hl-drawer[hidden]{ display:none; }
.hl-drawer__scrim{ position:absolute; inset:0; background:rgba(4,5,14,.7);
  backdrop-filter:blur(4px); opacity:0; transition:opacity var(--hl-t-med); }
.hl-drawer.is-open .hl-drawer__scrim{ opacity:1; }
.hl-drawer__panel{
  position:absolute; inset:0 0 0 auto; width:min(420px,100%);
  background:linear-gradient(180deg,var(--hl-ink-850),var(--hl-ink-950));
  border-left:1px solid var(--hl-line-dark);
  display:flex; flex-direction:column; overflow-y:auto;
  transform:translateX(100%); transition:transform 420ms var(--hl-e-out);
}
.hl-drawer.is-open .hl-drawer__panel{ transform:none; }
.hl-drawer__top{ display:flex; align-items:center; justify-content:space-between;
  padding:var(--hl-s-4) var(--hl-s-6); border-bottom:1px solid var(--hl-line-dark); }
.hl-drawer__x{ width:40px; height:40px; display:grid; place-items:center; border-radius:var(--hl-r-sm);
  color:var(--hl-text-light-2); border:1px solid var(--hl-line-dark); flex:none; }
.hl-drawer__x svg{ width:16px; height:16px; stroke:currentColor; stroke-width:1.6; fill:none; }
.hl-drawer__nav{ padding:var(--hl-s-4) var(--hl-s-6); flex:1; }
.hl-dacc{ border-bottom:1px solid var(--hl-line-dark); }
.hl-dacc summary{ display:flex; align-items:center; justify-content:space-between;
  padding:18px 0; font:600 1.05rem/1 var(--hl-ff-display); color:#fff; cursor:pointer;
  list-style:none; letter-spacing:-.015em; }
.hl-dacc summary::-webkit-details-marker{ display:none; }
.hl-dacc[open] summary .hl-caret{ transform:rotate(-135deg) translateY(-1px); }
.hl-dacc__body{ display:grid; grid-template-columns:1fr 1fr; gap:2px 14px; padding:0 0 16px; }
.hl-dacc__body a{ padding:8px 0; font-size:var(--hl-fs-sm); color:var(--hl-text-light-3); }
.hl-dacc__body a:hover{ color:var(--hl-red-300); }
/*
 * The panel's own action, last in its group. It spans both columns of the
 * two-column body — it is not one of the siblings, it is the route past them —
 * and it takes the accent colour so it reads as an action rather than as a
 * sixth industry. Added with the mobile "View All Industries" control; a panel
 * with no promo action renders no row, so this styles nothing on its own.
 */
.hl-dacc__body .hl-dacc__all{
    grid-column:1 / -1; margin-top:6px; padding-top:12px;
    border-top:1px solid var(--hl-hair-light, rgba(255,255,255,.10));
    color:var(--hl-red-300); font-weight:600;
}
.hl-dacc__body .hl-dacc__all:hover{ color:#fff; }
.hl-dlink{ display:block; padding:18px 0; border-bottom:1px solid var(--hl-line-dark);
  font:600 1.05rem/1 var(--hl-ff-display); color:#fff; letter-spacing:-.015em; }
.hl-drawer__foot{ padding:var(--hl-s-6); display:grid; gap:10px;
  background:rgba(255,255,255,.02); border-top:1px solid var(--hl-line-dark); }
.hl-drawer__login{ text-align:center; padding:8px; font-size:var(--hl-fs-sm); color:var(--hl-text-light-3); }
.hl-drawer__rule{ height:1px; background:var(--hl-line-dark); margin:4px 0; }
.hl-drawer__meta{ margin:0; text-align:center; font-size:var(--hl-fs-micro); letter-spacing:.08em;
  text-transform:uppercase; color:var(--hl-text-light-4); }

/* ── 07 · HERO ──────────────────────────────────────────────────────────── */
/* ── THE HERO CLOSING-AIR CONTRACT ─────────────────────────────────────────
   How much air a hero leaves under its last line was never a value; it was a
   residue. Every marketing hero renders `padding-bottom:0` on the SECTION and
   pays its space on the inner shell instead, and each shell had picked its own
   number: 75px on Home, 86px on the service/industry heroes, 63px on a product
   hero — plus whatever trailing margin the last element happened to carry.
   Measured across the site the reader saw 75, 86, 87, 98 and 110px for one
   relationship, and Home — the tightest at 75px, running into a section that is
   also dark, so no seam marks the change — is the one the owner reported.

   `--hl-hero-air` names it once. The three shells read the token instead of
   their own clamps, and the last element in each hero column stands its
   trailing margin down so the token is the whole distance rather than a floor
   under an accident. Hero HEIGHTS are untouched: this is the gap between the
   last thing a reader sees in the hero and the edge of the band, nothing else. */
:root{ --hl-hero-air: clamp(64px, 6vw, 96px); }

.hl-hero--highline{
  position:relative; isolation:isolate; overflow:hidden;
  background:
    radial-gradient(1200px 700px at 78% 6%, #1B2166 0%, transparent 62%),
    radial-gradient(900px 620px at 6% 94%, #191E58 0%, transparent 60%),
    linear-gradient(168deg, #0B0E28 0%, #080A1D 55%, #05060F 100%);
  margin-top:calc(var(--hl-nav-h) * -1); padding-top:var(--hl-nav-h);
}
.hl-hero__shell{
  position:relative; z-index:1; display:grid; grid-template-columns:1.04fr .96fr;
  gap:clamp(28px,3.4vw,64px); align-items:center;
  padding-block:clamp(36px,4vw,60px) var(--hl-hero-air);
}
.hl-hero__copy{ max-width:700px; }
.hl-hero__h1{
  font-size:var(--hl-fs-display); font-weight:800; line-height:var(--hl-lh-tight);
  color:#fff; letter-spacing:-.035em; margin-bottom:var(--hl-s-8);
}
.hl-hero__h1 .hl-line{ display:block; position:relative; }
/* The emphasised run in the home H1.

   `padding-right` is here for the background-clip gradient: without it the
   skewed final glyph is clipped by its own painting box. It used to be
   cancelled by `margin-right:-.08em`, so the LAYOUT got nothing back — and
   because no italic face is shipped (§8) this is a synthesised oblique whose
   last glyph leans past its advance width, on a line already tracked at
   -.05em. The result was "built aroundyour" on the most-read line of type on
   the site (audit M-01).

   The negative margin is gone. `.hl-shero__h1 em` has always used a POSITIVE
   `margin-right:.08em` for exactly this reason and has never collided; Home is
   now the same relationship. */
.hl-hero__h1 em{
  font-weight:300; font-style:italic;
  padding-right:.08em; margin-right:.02em;
  background:linear-gradient(96deg,#fff 26%,var(--hl-navy-300));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.hl-h1-rule{
  position:absolute; left:.06em; bottom:-.06em; width:2.6em; height:5px; border-radius:3px;
  background:linear-gradient(90deg,var(--hl-red-500),rgba(207,41,39,0));
}

.hl-rotator{
  display:inline-flex; align-items:center; gap:12px; margin-bottom:var(--hl-s-8);
  padding:11px 20px 11px 16px; border-radius:var(--hl-r-md);
  background:linear-gradient(100deg, rgba(255,255,255,.075), rgba(255,255,255,.02));
  border:1px solid var(--hl-line-dark-2); position:relative; overflow:hidden;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.09);
}
.hl-rotator__rail{ position:absolute; left:0; top:0; bottom:0; width:3px;
  background:linear-gradient(180deg,var(--hl-red-400),var(--hl-red-700)); }
.hl-rotator__pre{ font:600 var(--hl-fs-micro)/1 var(--hl-ff-body); color:var(--hl-text-light-3);
  letter-spacing:var(--hl-ls-wide); text-transform:uppercase; }
.hl-rotator__slot{
  display:grid; overflow:hidden; padding-block:2px;
  font:700 clamp(1.05rem,1.5vw,1.32rem)/1.25 var(--hl-ff-display); letter-spacing:-.02em;
}
.hl-rotator__word{
  /* --hl-red-400 measured 3.17:1 against the hero band once the word drops
     below 24px, which it does on a phone; the dark-band member of the ramp
     clears AA at every size the clamp produces. */
  grid-area:1/1; white-space:nowrap; color:var(--hl-red-300);
  opacity:0; transform:translateY(105%); filter:blur(5px);
  transition:opacity 460ms var(--hl-e-out), transform 460ms var(--hl-e-out), filter 460ms var(--hl-e-out);
}
.hl-rotator__word.is-active{ opacity:1; transform:none; filter:none; }
.hl-rotator__word.is-out{ opacity:0; transform:translateY(-105%); filter:blur(5px); }
.hl-rotator__caret{ width:2px; height:1.15em; background:var(--hl-red-400); border-radius:2px;
  animation:hls-blink 1.1s steps(1,end) infinite; }
@keyframes hls-blink{ 0%,49%{opacity:1} 50%,100%{opacity:0} }

.hl-hero__lede{ font-size:var(--hl-fs-lede); color:var(--hl-text-light-2); max-width:52ch;
  margin-bottom:var(--hl-s-10); }
.hl-hero__cta{ display:flex; flex-wrap:wrap; gap:12px; margin-bottom:var(--hl-s-10); }

.hl-trust{ display:flex; flex-wrap:wrap; gap:10px 24px; padding-top:var(--hl-s-6);
  border-top:1px solid var(--hl-line-dark); }
.hl-trust li{ display:flex; align-items:center; gap:9px; font-size:var(--hl-fs-xs);
  color:var(--hl-text-light-3); }
.hl-trust li::before{ content:""; width:5px; height:5px; border-radius:2px; flex:none;
  background:var(--hl-red-500); box-shadow:0 0 8px rgba(207,41,39,.7); }

/* ── payment flow composition ──────────────────────────────────────────── */
.hl-eco{
  position:relative; width:100%; aspect-ratio:1/1; max-width:660px; margin-inline:auto;
  font-family:var(--hl-ff-body);
}
.hl-eco__halo{
  position:absolute; inset:6% 4%; border-radius:50%;
  background:radial-gradient(circle at 55% 42%, rgba(90,97,204,.30), transparent 62%);
  filter:blur(30px);
}
.hl-eco__routes{ position:absolute; inset:0; width:100%; height:100%; overflow:visible; }
.hl-eco__routes .hl-rte__base{ stroke:rgba(255,255,255,.20); stroke-dasharray:4 6; }
.hl-eco__routes .hl-rte__base--dim{ stroke:rgba(255,255,255,.11); }

.hl-ecard{
  position:absolute; border-radius:var(--hl-r-lg); padding:14px;
  background:linear-gradient(158deg, rgba(255,255,255,.10), rgba(255,255,255,.025));
  border:1px solid var(--hl-line-dark-2);
  backdrop-filter:blur(16px) saturate(140%);
  box-shadow:var(--hl-sh-glass);
  animation:hls-bob 7s var(--hl-e-inout) infinite; animation-delay:calc(var(--hl-i,0) * -1.1s);
}
.hl-ecard[data-float="1"]{ --hl-i:1 } .hl-ecard[data-float="2"]{ --hl-i:2 }
.hl-ecard[data-float="3"]{ --hl-i:3 } .hl-ecard[data-float="4"]{ --hl-i:4 } .hl-ecard[data-float="5"]{ --hl-i:5 }
@keyframes hls-bob{ 0%,100%{ transform:translateY(0) } 50%{ transform:translateY(-9px) } }

.hl-ecard__head{ display:flex; align-items:center; gap:8px; margin-bottom:11px; }
.hl-ecard__step{
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:var(--hl-red-300);
  padding:3px 6px; border-radius:4px; background:rgba(207,41,39,.16);
  border:1px solid rgba(207,41,39,.32);
}
.hl-ecard__tag{ font:600 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-text-light-3); }
.hl-ecard__note{ margin:10px 0 0; font-size:var(--hl-fs-micro); color:var(--hl-text-light-4);
  letter-spacing:.06em; text-transform:uppercase; }
.hl-live{ margin-left:auto; width:7px; height:7px; border-radius:50%; background:var(--hl-ok);
  animation:hls-ping 2s var(--hl-e-out) infinite; }
@keyframes hls-ping{ 0%{box-shadow:0 0 0 0 rgba(47,214,163,.55)} 100%{box-shadow:0 0 0 11px rgba(47,214,163,0)} }

.hl-ecard--tap{ left:0; top:0; width:42%; }
.hl-tap{ display:flex; align-items:center; gap:12px; }
.hl-tap__wave{ display:flex; flex-direction:column; gap:3px; align-items:flex-start; }
.hl-tap__wave b{ height:2px; border-radius:2px; background:var(--hl-navy-300);
  animation:hls-wv 1.6s var(--hl-e-inout) infinite; }
.hl-tap__wave b:nth-child(1){ width:8px; animation-delay:0s }
.hl-tap__wave b:nth-child(2){ width:13px; animation-delay:.14s }
.hl-tap__wave b:nth-child(3){ width:18px; animation-delay:.28s }
@keyframes hls-wv{ 0%,100%{opacity:.25} 50%{opacity:1} }
.hl-tap__card{
  flex:1; height:54px; border-radius:8px; padding:8px; display:flex; flex-direction:column;
  justify-content:space-between;
  background:linear-gradient(128deg,#3A3FA3,#1B2166 60%,#0E1230);
  border:1px solid rgba(255,255,255,.18);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22), 0 8px 18px -8px rgba(0,0,0,.7);
}
.hl-tap__chip{ width:16px; height:12px; border-radius:2px;
  background:linear-gradient(150deg,#E9C978,#B99342); opacity:.9; }
.hl-tap__num{ font:500 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:rgba(255,255,255,.8); letter-spacing:.1em; }

.hl-ecard--pos{ right:0; top:3%; width:46%; }
.hl-pos{ display:flex; flex-direction:column; gap:10px; }
.hl-pos__screen{
  border-radius:12px; padding:13px;
  background:linear-gradient(160deg,#252C63,#0E1230);
  border:1px solid rgba(255,255,255,.13);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.16);
}
.hl-pos__label{ font:500 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-text-light-4); }
.hl-pos__amount{ margin:7px 0 10px; font:700 clamp(1.3rem,2.4vw,1.85rem)/1 var(--hl-ff-display);
  color:#fff; letter-spacing:-.03em; font-variant-numeric:tabular-nums; }
.hl-pos__amount span{ font-size:.6em; color:var(--hl-text-light-3); }
.hl-pos__state{ display:flex; align-items:center; gap:8px; }
.hl-pos__spinner{
  width:12px; height:12px; border-radius:50%; flex:none;
  border:1.6px solid rgba(255,255,255,.2); border-top-color:var(--hl-navy-300);
  animation:hls-spin .9s linear infinite;
}
@keyframes hls-spin{ to{ transform:rotate(360deg) } }
.hl-pos__word{ font:600 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-navy-300); }
.hl-pos__state.is-ok .hl-pos__spinner{ border-color:var(--hl-ok); border-top-color:var(--hl-ok); animation:none; }
.hl-pos__state.is-ok .hl-pos__word{ color:var(--hl-ok); }
.hl-pos__meter{ margin-top:11px; height:3px; border-radius:2px; background:rgba(255,255,255,.1);
  overflow:hidden; }
.hl-pos__meter span{ display:block; height:100%; width:40%; border-radius:2px;
  background:linear-gradient(90deg,var(--hl-navy-400),var(--hl-red-500));
  animation:hls-meter 3.6s var(--hl-e-inout) infinite; }
@keyframes hls-meter{ 0%{width:6%} 58%{width:100%} 100%{width:100%} }
.hl-pos__keys{ display:grid; grid-template-columns:repeat(3,1fr); gap:6px; padding:0 4px; }
.hl-pos__keys b{ height:6px; border-radius:3px; background:rgba(255,255,255,.12); }
.hl-pos__slot{ display:block; height:4px; border-radius:2px; margin:2px 14px 0;
  background:rgba(255,255,255,.2); }
.hl-stamp{
  position:absolute; right:-14px; bottom:-16px;
  display:inline-flex; align-items:center; gap:6px; padding:8px 13px; border-radius:var(--hl-r-pill);
  background:linear-gradient(150deg,#12483A,#0B2A22);
  border:1px solid rgba(47,214,163,.45); color:var(--hl-ok);
  font:700 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide); text-transform:uppercase;
  box-shadow:0 12px 26px -12px rgba(47,214,163,.6);
  opacity:0; transform:scale(.82) translateY(6px);
  transition:opacity 300ms var(--hl-e-out), transform 380ms var(--hl-e-out);
}
.hl-stamp.is-on{ opacity:1; transform:none; }
.hl-stamp svg{ width:11px; height:11px; stroke:currentColor; stroke-width:2.2; fill:none; stroke-linecap:round; }

.hl-ecard--gate{ left:1%; top:38%; width:46%; }
.hl-hops{ display:grid; gap:9px; }
.hl-hops li{ display:flex; align-items:center; gap:9px; font-size:var(--hl-fs-xs); }
.hl-hops b{ font-weight:500; color:var(--hl-text-light-2); }
.hl-hops i{ margin-left:auto; font:400 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:var(--hl-text-light-4); }
.hl-hops__dot{ width:7px; height:7px; border-radius:50%; flex:none;
  border:1.4px solid rgba(255,255,255,.28); transition:all var(--hl-t-med) var(--hl-e-out); }
.hl-hops li.is-done .hl-hops__dot{ background:var(--hl-ok); border-color:var(--hl-ok);
  box-shadow:0 0 10px rgba(47,214,163,.7); }
.hl-hops li.is-done b{ color:#fff; }

.hl-ecard--net{ right:0; top:55%; width:41%; }
.hl-net__marks{ display:flex; gap:5px; margin-bottom:11px; }
.hl-net__mark{ width:26px; height:17px; border-radius:3px; flex:none;
  background:linear-gradient(140deg, rgba(255,255,255,.20), rgba(255,255,255,.06));
  border:1px solid rgba(255,255,255,.18); }
.hl-net__mark:nth-child(2){ background:linear-gradient(140deg, rgba(207,41,39,.45), rgba(207,41,39,.12));
  border-color:rgba(229,84,78,.4); }
.hl-net__auth{ display:flex; align-items:center; gap:8px; padding:9px 10px; border-radius:var(--hl-r-sm);
  background:rgba(4,5,14,.45); border:1px solid var(--hl-line-dark); }
.hl-net__pulse{ width:6px; height:6px; border-radius:50%; flex:none; background:var(--hl-red-400);
  animation:hls-ping2 2.2s var(--hl-e-out) infinite; }
@keyframes hls-ping2{ 0%{box-shadow:0 0 0 0 rgba(229,84,78,.6)} 100%{box-shadow:0 0 0 10px rgba(229,84,78,0)} }
.hl-net__label{ font:500 var(--hl-fs-micro)/1.3 var(--hl-ff-body); letter-spacing:.06em;
  text-transform:uppercase; color:var(--hl-text-light-3); }
.hl-net__auth b{ margin-left:auto; font:500 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:#fff;
  letter-spacing:.14em; }

.hl-ecard--paid{ right:3%; bottom:0; width:64%; }
.hl-paid{ display:flex; align-items:flex-end; gap:14px; }
.hl-paid__figure{ flex:1; }
.hl-paid__label{ display:block; font:500 var(--hl-fs-micro)/1.3 var(--hl-ff-body);
  letter-spacing:var(--hl-ls-wide); text-transform:uppercase; color:var(--hl-text-light-4); }
.hl-paid__amount{ margin-top:6px; font:700 clamp(1.15rem,2vw,1.5rem)/1 var(--hl-ff-display);
  color:#fff; letter-spacing:-.03em; font-variant-numeric:tabular-nums; }
.hl-paid__chart{ display:flex; align-items:flex-end; gap:3px; height:46px; }
.hl-paid__chart b{
  width:6px; height:var(--hl-h); border-radius:2px 2px 0 0;
  background:linear-gradient(180deg,var(--hl-navy-400),rgba(90,97,204,.15));
  transform-origin:bottom; animation:hls-grow 1.1s var(--hl-e-out) backwards;
}
.hl-paid__chart b.is-red{ background:linear-gradient(180deg,var(--hl-red-400),rgba(207,41,39,.2)); }
.hl-paid__chart b:nth-child(1){animation-delay:.05s} .hl-paid__chart b:nth-child(2){animation-delay:.1s}
.hl-paid__chart b:nth-child(3){animation-delay:.15s} .hl-paid__chart b:nth-child(4){animation-delay:.2s}
.hl-paid__chart b:nth-child(5){animation-delay:.25s} .hl-paid__chart b:nth-child(6){animation-delay:.3s}
.hl-paid__chart b:nth-child(7){animation-delay:.35s} .hl-paid__chart b:nth-child(8){animation-delay:.4s}
.hl-paid__chart b:nth-child(9){animation-delay:.45s}
@keyframes hls-grow{ from{ transform:scaleY(0) } to{ transform:scaleY(1) } }
.hl-paid__foot{ display:flex; justify-content:space-between; align-items:center; margin-top:12px;
  padding-top:10px; border-top:1px solid var(--hl-line-dark);
  font:400 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:var(--hl-text-light-4); letter-spacing:.08em; }
.hl-paid__ok{ color:var(--hl-ok); }

/* ambient reporting sliver */
.hl-report{
  position:absolute; left:4%; bottom:14%; width:24%; padding:12px 12px 14px;
  border-radius:var(--hl-r-md); background:rgba(255,255,255,.045);
  border:1px solid var(--hl-line-dark); transform:rotate(-5deg);
  animation:hls-bob 8s var(--hl-e-inout) -2s infinite;
}
.hl-report__tag{ display:block; margin-bottom:9px; font:500 var(--hl-fs-micro)/1 var(--hl-ff-body);
  letter-spacing:var(--hl-ls-wide); text-transform:uppercase; color:var(--hl-text-light-4); }
.hl-report b{ display:block; height:3px; border-radius:2px; background:rgba(255,255,255,.16);
  margin-bottom:6px; }
.hl-report b:nth-of-type(2){ width:72% } .hl-report b:nth-of-type(3){ width:50% }
.hl-report__spark{ display:flex; align-items:flex-end; gap:3px; height:22px; margin-top:10px; }
.hl-report__spark i{ flex:1; border-radius:1px; background:rgba(144,150,228,.5); }
.hl-report__spark i:nth-child(1){height:38%} .hl-report__spark i:nth-child(2){height:56%}
.hl-report__spark i:nth-child(3){height:44%} .hl-report__spark i:nth-child(4){height:72%}
.hl-report__spark i:nth-child(5){height:60%} .hl-report__spark i:nth-child(6){height:88%}
.hl-report__spark i:nth-child(7){height:100%; background:var(--hl-red-400)}

/* ── 08 · ACCEPT / MANAGE / GROW ────────────────────────────────────────── */
.hl-sys{ position:relative; padding-block:var(--hl-sec-pad); overflow:hidden;
  background:linear-gradient(180deg,#05060F 0%,#0A0C22 42%,#0E1230 100%); }

.hl-psys{
  position:relative; padding:var(--hl-s-10) var(--hl-s-10) 0; border-radius:var(--hl-r-2xl) var(--hl-r-2xl) 0 0;
  background:linear-gradient(160deg, rgba(255,255,255,.06), rgba(255,255,255,.015));
  border:1px solid var(--hl-line-dark-2); border-bottom:0;
}
.hl-psys__track{ position:relative; padding-bottom:var(--hl-s-10); }
.hl-psys__rail{ position:absolute; left:0; right:0; top:5px; height:2px; display:flex;
  border-radius:2px; overflow:hidden; }
.hl-pseg{ position:relative; height:2px; background:rgba(255,255,255,.11);
  transition:background var(--hl-t-med); }
.hl-pseg--accept{ flex:2 } .hl-pseg--manage{ flex:3 } .hl-pseg--grow{ flex:2 }
.hl-pseg.is-lit{ background:rgba(207,41,39,.3); }
.hl-pseg.is-lit::after{
  content:""; position:absolute; inset:0; width:40%; border-radius:2px;
  background:linear-gradient(90deg,transparent,var(--hl-red-400),transparent);
  animation:hls-segRun 2.2s var(--hl-e-inout) infinite;
}
@keyframes hls-segRun{ from{ transform:translateX(-40%) } to{ transform:translateX(250%) } }

.hl-psys__nodes{ display:grid; grid-template-columns:repeat(7,1fr); }
.hl-pn{ position:relative; padding-top:26px; text-align:left; padding-right:10px; }
.hl-pn__dot{
  position:absolute; left:0; top:0; width:12px; height:12px; border-radius:50%;
  background:var(--hl-ink-800); border:2px solid rgba(255,255,255,.22);
  transition:all var(--hl-t-med) var(--hl-e-out);
}
.hl-pn b{ display:block; font:600 var(--hl-fs-sm)/1.2 var(--hl-ff-display); color:var(--hl-text-light-3);
  letter-spacing:-.015em; transition:color var(--hl-t-med); }
.hl-pn i{ display:block; margin-top:3px; font-size:var(--hl-fs-micro); color:var(--hl-text-light-4);
  transition:color var(--hl-t-med); }
.hl-pn.is-lit .hl-pn__dot{ background:var(--hl-red-500); border-color:var(--hl-red-300);
  box-shadow:0 0 0 5px rgba(207,41,39,.16), 0 0 18px rgba(207,41,39,.8); }
.hl-pn.is-lit b{ color:#fff; }
.hl-pn.is-lit i{ color:var(--hl-text-light-3); }

.hl-psys__zones{ display:grid; grid-template-columns:2fr 3fr 2fr; gap:1px;
  border-top:1px solid var(--hl-line-dark-2); }
.hl-pz{
  position:relative; text-align:left; padding:22px 24px 24px; display:grid; gap:4px;
  border-right:1px solid var(--hl-line-dark);
  transition:background var(--hl-t-med);
}
.hl-pz:last-child{ border-right:0; }
.hl-pz::before{
  content:""; position:absolute; left:24px; right:24px; top:-1px; height:2px; border-radius:2px;
  background:var(--hl-red-500); opacity:0; transition:opacity var(--hl-t-med);
}
.hl-pz:hover{ background:rgba(255,255,255,.035); }
.hl-pz.is-active{ background:rgba(255,255,255,.06); }
.hl-pz.is-active::before{ opacity:1; }
.hl-pz em{ font:500 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:var(--hl-text-light-4); letter-spacing:.16em; }
.hl-pz b{ font:800 clamp(1.4rem,2.2vw,1.95rem)/1 var(--hl-ff-display); letter-spacing:-.035em;
  color:var(--hl-text-light-4); transition:color var(--hl-t-med); }
.hl-pz.is-active b{ color:#fff; }
.hl-pz:hover b{ color:var(--hl-text-light-2); }
.hl-pz span{ font-size:var(--hl-fs-xs); color:var(--hl-text-light-3); }
.hl-pz.is-active span{ color:var(--hl-red-300); }

.hl-pstage{ position:relative; }
.hl-ppanel{
  display:grid; grid-template-columns:1.18fr .82fr; gap:clamp(28px,3.4vw,64px); align-items:center;
  padding:clamp(28px,3.2vw,48px); border-radius:0 0 var(--hl-r-2xl) var(--hl-r-2xl);
  background:linear-gradient(170deg, rgba(255,255,255,.055), rgba(255,255,255,.015));
  border:1px solid var(--hl-line-dark-2); border-top:0;
  box-shadow:0 40px 90px -40px rgba(0,0,0,.85);
}
.hl-ppanel[hidden]{ display:none; }
.hl-ppanel.is-active{ animation:hls-panelIn 480ms var(--hl-e-out); }
@keyframes hls-panelIn{ from{ opacity:0; transform:translateY(12px) } to{ opacity:1; transform:none } }
.hl-ppanel__kicker{ display:inline-block; margin-bottom:14px; padding:5px 11px; border-radius:var(--hl-r-xs);
  background:rgba(255,255,255,.07); border:1px solid var(--hl-line-dark-2);
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-navy-300); }
.hl-ppanel__title{ font-size:var(--hl-fs-h3); color:#fff; margin-bottom:var(--hl-s-4); max-width:28ch; }
.hl-ppanel__copy{ font-size:var(--hl-fs-body); color:var(--hl-text-light-2); max-width:58ch; }
.hl-ppanel__body{ display:flex; flex-direction:column; align-items:flex-start; }

.hl-mini{ padding:var(--hl-s-6); border-radius:var(--hl-r-lg); background:rgba(4,5,14,.5);
  border:1px solid var(--hl-line-dark); }
.hl-mini__head{ display:flex; justify-content:space-between; align-items:center; margin-bottom:16px;
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide); text-transform:uppercase;
  color:var(--hl-text-light-4); }
.hl-mini__ok{ color:var(--hl-ok); }
.hl-mini__row{ display:flex; align-items:center; gap:12px; margin-bottom:13px; font-size:var(--hl-fs-xs);
  color:var(--hl-text-light-2); }
.hl-mini__row span{ width:86px; flex:none; }
.hl-mini__row i{ font:400 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:var(--hl-text-light-3); width:30px;
  text-align:right; }
.hl-mini__bar{ flex:1; height:6px; border-radius:3px; background:rgba(255,255,255,.08); position:relative; }
.hl-mini__bar::after{ content:""; position:absolute; inset:0; width:var(--hl-w); border-radius:3px;
  background:linear-gradient(90deg,var(--hl-navy-400),var(--hl-navy-300));
  transform-origin:left; animation:hls-barIn 900ms var(--hl-e-out) backwards; }
.hl-mini__bar--red::after{ background:linear-gradient(90deg,var(--hl-red-600),var(--hl-red-400)); }
@keyframes hls-barIn{ from{ transform:scaleX(0) } to{ transform:scaleX(1) } }
.hl-mini__cap{ margin:14px 0 0; font-size:var(--hl-fs-micro); color:var(--hl-text-light-4); }
.hl-mini__list li{ display:flex; align-items:center; gap:10px; padding:9px 0;
  border-top:1px solid var(--hl-line-dark); font-size:var(--hl-fs-xs); }
.hl-mini__list b{ width:48px; flex:none; color:var(--hl-text-light-3); font-weight:500; }
.hl-mini__list span{ color:#fff; }
.hl-mini__list i{ margin-left:auto; font:400 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:var(--hl-text-light-4); }
.hl-mini__steps{ display:flex; align-items:flex-end; gap:10px; height:150px; margin-bottom:26px; }
.hl-mini__steps b{ flex:1; height:var(--hl-h); border-radius:5px 5px 0 0; position:relative;
  background:linear-gradient(180deg,var(--hl-navy-400),rgba(90,97,204,.12));
  transform-origin:bottom; animation:hls-grow 900ms var(--hl-e-out) backwards; }
.hl-mini__steps b.is-red{ background:linear-gradient(180deg,var(--hl-red-400),rgba(207,41,39,.15)); }
.hl-mini__steps b:nth-child(2){ animation-delay:.1s } .hl-mini__steps b:nth-child(3){ animation-delay:.2s }
.hl-mini__steps b:nth-child(4){ animation-delay:.3s }
.hl-mini__steps i{ position:absolute; left:-6px; right:-6px; bottom:-22px; text-align:center;
  font:500 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:.06em; text-transform:uppercase;
  color:var(--hl-text-light-4); }

/* ── 09 · POS & HARDWARE ────────────────────────────────────────────────── */
.hl-hw{ position:relative; padding-block:var(--hl-sec-pad); overflow:hidden;
  background:linear-gradient(180deg,var(--hl-paper) 0%,#fff 55%,var(--hl-paper) 100%); }
.hl-hw__arc{
  position:absolute; right:-16%; top:-10%; width:74%; aspect-ratio:1/1; border-radius:50%;
  background:
    radial-gradient(circle at 40% 40%, rgba(42,45,124,.08), transparent 64%),
    conic-gradient(from 200deg, rgba(42,45,124,.09), transparent 42%);
  mask-image:radial-gradient(circle at 50% 50%, #000 55%, transparent 78%);
  -webkit-mask-image:radial-gradient(circle at 50% 50%, #000 55%, transparent 78%);
}
.hl-hw .hl-shead--split{ grid-template-columns:1fr 1fr; }
.hl-hw__lead{ display:flex; flex-direction:column; gap:var(--hl-s-5); }
.hl-hw__lead p{ font-size:var(--hl-fs-sm); color:var(--hl-text-muted); margin:0; max-width:46ch; }
.hl-hw__leadcta{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--hl-s-4); }
.hl-finnote{
  display:flex; align-items:center; gap:10px; padding:11px 14px;
  border-radius:var(--hl-r-md); background:var(--hl-white); border:1px solid var(--hl-line);
  box-shadow:var(--hl-sh-sm); font-size:var(--hl-fs-xs); color:var(--hl-text-muted); max-width:34ch;
}
.hl-finnote__pill{
  flex:none; padding:4px 9px; border-radius:var(--hl-r-xs); background:rgba(207,41,39,.09);
  border:1px solid rgba(207,41,39,.24); color:var(--hl-red-600);
  font:700 var(--hl-fs-micro)/1.4 var(--hl-ff-body); letter-spacing:.04em;
}

/* featured stage */
.hl-hstage{
  position:relative; display:grid; grid-template-columns:1.15fr .85fr;
  gap:clamp(24px,3vw,56px); align-items:center;
  padding:clamp(28px,3vw,48px); border-radius:var(--hl-r-3xl); overflow:hidden;
  background:linear-gradient(150deg,#fff 0%,#F2F5FB 60%,#EAEFF8 100%);
  border:1px solid var(--hl-line); box-shadow:var(--hl-sh-lg);
  margin-bottom:clamp(20px,2.4vw,32px);
}
.hl-hstage__bg{ position:absolute; inset:0; overflow:hidden; }
.hl-hstage__bg svg{ position:absolute; inset:0; width:100%; height:100%; }
.hl-hstage__bg .hl-rte__base{ stroke:rgba(42,45,124,.16); }
.hl-hstage__bg .hl-rte__amb{ stroke:rgba(90,97,204,.5); }
.hl-hstage__pad{
  position:absolute; left:22%; top:50%; width:min(420px,42%); aspect-ratio:1/1;
  transform:translate(-50%,-46%); border-radius:50%;
  background:radial-gradient(circle, rgba(42,45,124,.13), transparent 66%);
}
.hl-hstage__art{ position:relative; z-index:1; display:grid; place-items:center;
  min-height:340px; padding-block:var(--hl-s-6); }
/* Devices are scaled with transform, which does not reserve layout space —
   margin-block absorbs the overflow so the caption never collides. */
.hl-pslot--xl .hl-dev{ margin-block:46px; }
.hl-pslot--lg .hl-dev{ margin-block:24px; }
.hl-hstage__art .hl-pslot{ position:relative; z-index:2; }
.hl-hstage__art .hl-dev{ animation:hls-hover 6.5s var(--hl-e-inout) infinite; }
@keyframes hls-hover{ 0%,100%{ transform:scale(var(--hl-k,1)) translateY(0) rotate(0deg) }
                  50%{ transform:scale(var(--hl-k,1)) translateY(-10px) rotate(-.8deg) } }
.hl-pslot--xl .hl-dev{ --hl-k:1.42; transform:scale(1.42); }
.hl-hstage__art::before{
  content:""; position:absolute; left:50%; bottom:24px; width:44%; height:18px;
  transform:translateX(-50%); border-radius:50%;
  background:radial-gradient(ellipse, rgba(10,14,36,.22), transparent 70%); filter:blur(5px);
}
.hl-hlabel{
  position:absolute; z-index:3; padding:8px 13px; border-radius:var(--hl-r-pill);
  background:#fff; border:1px solid var(--hl-line); box-shadow:var(--hl-sh-md);
  font:600 var(--hl-fs-xs)/1 var(--hl-ff-display); color:var(--hl-text-dark); white-space:nowrap;
  letter-spacing:-.01em;
}
.hl-hlabel::before{
  content:""; position:absolute; width:6px; height:6px; border-radius:50%;
  background:var(--hl-brand-red); box-shadow:0 0 0 3px rgba(207,41,39,.16);
  top:50%; margin-top:-3px;
}
.hl-hlabel--1{ top:8%;  left:2%;  animation:hls-bob 7s var(--hl-e-inout) infinite; }
.hl-hlabel--1::before{ right:-13px; }
.hl-hlabel--2{ top:30%; right:0;   animation:hls-bob 7s var(--hl-e-inout) -2s infinite; }
.hl-hlabel--2::before{ left:-13px; }
.hl-hlabel--3{ bottom:26%; left:0;  animation:hls-bob 7s var(--hl-e-inout) -4s infinite; }
.hl-hlabel--3::before{ right:-13px; }
.hl-hlabel--4{ bottom:6%; right:4%; animation:hls-bob 7s var(--hl-e-inout) -5.5s infinite; }
.hl-hlabel--4::before{ left:-13px; }

.hl-hstage__meta{ position:relative; z-index:1; }
.hl-hstage__badge{
  display:inline-block; margin-bottom:var(--hl-s-4); padding:5px 12px; border-radius:var(--hl-r-pill);
  background:var(--hl-ink-800); color:#fff;
  font:700 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide); text-transform:uppercase;
}
.hl-hstage__meta h3{ font-size:var(--hl-fs-h3); margin-bottom:var(--hl-s-4); }
.hl-hstage__meta p{ font-size:var(--hl-fs-sm); color:var(--hl-text-muted); margin-bottom:var(--hl-s-6); }
.hl-hspec{ display:grid; gap:1px; margin-bottom:var(--hl-s-6); }
.hl-hspec li{ display:grid; grid-template-columns:104px 1fr; gap:14px; align-items:baseline;
  padding:11px 0; border-top:1px solid var(--hl-line); font-size:var(--hl-fs-xs); }
.hl-hspec li:last-child{ border-bottom:1px solid var(--hl-line); }
.hl-hspec b{ font:600 var(--hl-fs-micro)/1.5 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-text-muted); }
.hl-hspec span{ color:var(--hl-text-dark); font-weight:500; }

/* ── THE DEVICE COLLECTION: COUNT DECIDES THE SHAPE ────────────────────────
   A row of device cards is whatever the Admin selection holds — one product or
   fifty — so the shape is derived from the count rather than from a layout
   switch somebody has to remember to flip.

     1-5 products   a static grid of exactly that many columns
     6+ products    a carousel, every product reachable

   `--hl-row-n` is the column count the view calculates (its own maximum, capped
   by how many products there actually are), so four products fill the row as
   four balanced cards instead of leaving a fifth column of air — which is what
   `repeat(5,1fr)` did however many products were selected.

   `--hl-row-min` is the floor a card may shrink to before the row stops trying
   to fit them all side by side; it is what keeps five cards from becoming five
   slivers on a tablet. */
.hl-hrow{
  display:grid;
  grid-template-columns:repeat(var(--hl-row-n, 5), minmax(0,1fr));
  gap:clamp(12px,1.2vw,18px);
}

/* ── CAROUSEL MODE ─────────────────────────────────────────────────────────
   Not a library and not a second markup path: the same <ul> of the same cards,
   scrolling. CSS scroll-snap does the work, `carousel.js` points the existing
   arrow controls at it with `scrollBy`, and with scripting off it is still a
   swipeable row — which is why nothing here depends on JavaScript having run.

   `scroll-padding` and the snap alignment make a paged jump land a card flush
   against the row's left edge rather than halfway under it. */
.hl-collection--carousel .hl-hrow,
.hl-collection--carousel .hl-rhw__row,
.hl-collection--carousel .hl-hw2__grid{
  /* `--hl-vis` is how many cards are VISIBLE, which is not the same question as
     how many products there are. The count decides whether this is a carousel
     at all; the viewport decides how much of it you can see at once, and the
     breakpoints below narrow it so five cards never become five slivers. */
  --hl-vis:var(--hl-row-n, 5);
  --hl-gap:clamp(12px,1.2vw,18px);

  grid-auto-flow:column;
  /* A FIXED track, not `minmax(0, …)`.

     `minmax(0, X)` sets X as the MAXIMUM and zero as the minimum, so the grid
     was free to shrink the tracks to fit — measured with six products in a
     five-across row, every card came out 184px and `scrollWidth` equalled
     `clientWidth`. A carousel that fits is not a carousel: it silently became a
     six-column grid of narrower cards, and nothing scrolled. */
  grid-auto-columns:calc((100% - (var(--hl-vis) - 1) * var(--hl-gap)) / var(--hl-vis));
  grid-template-columns:none;
  gap:var(--hl-gap);
  overflow-x:auto; scroll-snap-type:x mandatory; scroll-behavior:smooth;
  scroll-padding-inline:0;
  /* The scrollbar is suppressed because the arrows and the partial next card
     are the affordance; `.hl-scrollcue` is not used here for that reason. */
  scrollbar-width:none;
  padding-bottom:4px;
}
/* Fewer cards in view as the viewport narrows. These carry more specificity
   than the static grid's own breakpoints, so carousel mode stays a carousel at
   every width instead of reverting to a wrapping grid halfway down. */
@media (max-width:1280px){
  .hl-collection--carousel .hl-hrow,
  .hl-collection--carousel .hl-rhw__row,
  .hl-collection--carousel .hl-hw2__grid{ --hl-vis:var(--hl-row-md, 3); }
}
@media (max-width:900px){
  .hl-collection--carousel .hl-hrow,
  .hl-collection--carousel .hl-rhw__row,
  .hl-collection--carousel .hl-hw2__grid{ --hl-vis:var(--hl-row-sm, 2); }
}
@media (max-width:640px){
  /* A fraction on purpose: the sliver of the next card is what says "there is
     more this way" on a phone, where the arrows are furthest from the thumb. */
  .hl-collection--carousel .hl-hrow,
  .hl-collection--carousel .hl-rhw__row,
  .hl-collection--carousel .hl-hw2__grid{ --hl-vis:1.15; }
}
.hl-collection--carousel .hl-hrow::-webkit-scrollbar,
.hl-collection--carousel .hl-rhw__row::-webkit-scrollbar,
.hl-collection--carousel .hl-hw2__grid::-webkit-scrollbar{ display:none; }
.hl-collection--carousel .hl-hcard{ scroll-snap-align:start; }
/* The hover lift would be clipped by the scroller, so it stands down in a
   carousel and the shadow carries the state instead. */
.hl-collection--carousel .hl-hcard:hover{ transform:none; }

/* The controls sit with the chapter rather than over the cards: no giant
   arrows, no overlay furniture, and nothing that covers a product. */
.hl-collection__nav{
  display:flex; justify-content:flex-end; gap:8px; margin-top:var(--hl-s-5);
}
.hl-collection__btn{
  display:grid; place-items:center; width:40px; height:40px; border-radius:50%;
  color:var(--hl-text-dark); background:#fff; border:1px solid var(--hl-line);
  box-shadow:var(--hl-sh-sm);
  transition:background var(--hl-t-fast), border-color var(--hl-t-fast),
             color var(--hl-t-fast), opacity var(--hl-t-fast);
}
.hl-collection__btn:hover{ border-color:var(--hl-line-2); color:var(--hl-brand-red); }
.hl-collection__btn:focus-visible{ outline:2px solid var(--hl-brand-red); outline-offset:3px; }
/* A control that cannot do anything says so, and stops taking the tab stop. */
.hl-collection__btn[disabled]{ opacity:.36; cursor:default; }
.hl-collection__btn svg{ width:15px; height:15px; }
.hl-section--dark .hl-collection__btn,
.hl-section--navy .hl-collection__btn{
  color:#fff; background:rgba(255,255,255,.06); border-color:var(--hl-line-dark);
  box-shadow:none;
}
.hl-section--dark .hl-collection__btn:hover,
.hl-section--navy .hl-collection__btn:hover{ background:rgba(255,255,255,.13); color:#fff; }

@media (prefers-reduced-motion:reduce){
  .hl-collection--carousel .hl-hrow,
  .hl-collection--carousel .hl-rhw__row,
  .hl-collection--carousel .hl-hw2__grid{ scroll-behavior:auto; }
}
.hl-hcard{
  position:relative; display:flex; flex-direction:column; padding:20px 18px;
  border-radius:var(--hl-r-xl); background:#fff; border:1px solid var(--hl-line);
  box-shadow:var(--hl-sh-sm); overflow:hidden;
  transition:transform 420ms var(--hl-e-out), box-shadow 420ms var(--hl-e-out);
}
.hl-hcard::after{
  content:""; position:absolute; inset:auto -30% -60% -30%; height:70%;
  background:radial-gradient(ellipse at 50% 0%, rgba(42,45,124,.09), transparent 68%);
  pointer-events:none;
}
.hl-hcard:hover{ transform:translateY(-7px); box-shadow:var(--hl-sh-md); }
/* ── THE MEDIA ZONE IS FIXED, AND THAT IS WHAT ALIGNS THE TITLES ───────────
   It used to be `flex:1; min-height:176px`, so the zone grew with whatever the
   artwork wanted: a square canvas took 203px and a wide one took 182px, and the
   title under the square one therefore started 20px lower than its neighbours'.
   Measured on the home range row before this change — Valor VP300's title at
   y=3206 against y=3186 for the other three.

   A fixed height makes the alignment structural rather than coincidental: every
   title in the row starts at the same place because every media zone ends at
   the same place, whatever was uploaded. `overflow:hidden` is what lets a
   trimmed asset scale past the zone's edge without pushing anything. */
.hl-hcard .hl-pslot{
  flex:none; height:var(--hl-hcard-media, 186px); min-height:0;
  justify-content:center; margin-bottom:16px;
  position:relative; overflow:hidden;
}
.hl-hcard .hl-pslot img{
  width:100%; height:100%; max-width:100%; max-height:100%;
  object-fit:contain; object-position:center;
}
/* The caption takes the leftover height, so "View details" keeps its bottom
   edge however tall the artwork was. */
.hl-hcard .hl-hcard__meta{ flex:1; }

/* ── TRIMMED ARTWORK ───────────────────────────────────────────────────────
   `media_trim_style()` supplies the scale and the offset; the order here is
   load-bearing. `scale()` is written first so it applies LAST, about the
   element's centre: the translate moves the device's centre onto the canvas
   centre, and the scale then grows it about that same point. Written the other
   way round the picture is scaled first and the shift is multiplied with it,
   which walks the device out of the zone.

   Whatever whitespace this pushes past the zone's edge is clipped by the
   `overflow:hidden` above. Nothing is cropped from the file — the asset is
   untouched and a different zone shows a different amount of it. */
/* The DEVICE is contained in the zone, and the canvas follows it.

   `min(100%, media-height * ar)` is the contain fit of the CONTENT box in this
   zone — the zone's width from `100%`, its height from the same token that set
   it. Multiplying by `z` (canvas width over content width) gives the width the
   whole picture must be drawn at for its device to come out that size; the
   height follows from the image's own ratio, so nothing is ever stretched.

   Container query units expressed this first and had to go: `container-type:
   size` on the slot renders only the first card's artwork in Chromium — the
   rest measure as loaded, visible, opaque and correctly positioned, and paint
   nothing. The zone's height is already a token, so the query was never needed. */
/* THE CANVAS IS CENTRED BY MARGIN, NOT BY THE GRID.

   `.hl-pslot` centres its child, and for a trimmed asset the child is
   deliberately WIDER than the zone — the whitespace is meant to hang outside
   and be clipped. A grid item bigger than its area does not stay centred:
   the engine falls back to start alignment so nothing is lost off the start
   edge. Measured on the home row, the Clover Kiosk's 314px canvas sat flush
   against the left of its 187px zone and overflowed 127px to the right, putting
   the device's centre 64px right of the zone's. Every trimmed card was off by
   the same mechanism — 19px, 23px, 26px — and the device that overflowed most
   was displaced most, which is why the Kiosk looked both small and wrong.

   Explicit margins remove the guesswork. `--hl-trim-w` is the canvas width and
   `--hl-trim-h` its height, so each axis is centred against a dimension the
   stylesheet knows: the zone's own width for one, the media token for the
   other. `place-items:start` stops the grid contributing a second opinion. */
.hl-hcard--trim .hl-pslot{ place-items:start; }
.hl-hcard--trim .hl-pslot img{
  /* IN FLOW, and that is not incidental. Taking the picture out of flow —
     `position:absolute; left:50%; top:50%` — computed correctly and painted
     nothing on most cards: they measured loaded, visible, opaque and correctly
     positioned, and the media zone came out blank. */
  --hl-trim-w:calc(min(100%, var(--hl-hcard-media, 186px) * var(--hl-trim-ar)) * var(--hl-trim-z));
  --hl-trim-h:calc(var(--hl-trim-w) / var(--hl-trim-car, 1));

  width:var(--hl-trim-w);
  height:auto; max-width:none; max-height:none;

  /* Percentage margins resolve against the containing block's WIDTH, which is
     the zone — correct for the inline axis and wrong for the block one, so the
     vertical centring uses the media token instead of a percentage. */
  margin-left:calc((100% - var(--hl-trim-w)) / 2);
  margin-top:calc((var(--hl-hcard-media, 186px) - var(--hl-trim-h)) / 2);

  /* Then slide the DEVICE's centre onto the zone's. */
  transform:translate(var(--hl-trim-x, 0), var(--hl-trim-y, 0));
}
.hl-hcard .hl-dev{ animation:hls-hover 7s var(--hl-e-inout) infinite; }
.hl-hcard:nth-child(2) .hl-dev{ animation-delay:-1.4s }
.hl-hcard:nth-child(3) .hl-dev{ animation-delay:-2.8s }
.hl-hcard:nth-child(4) .hl-dev{ animation-delay:-4.2s }
.hl-hcard:nth-child(5) .hl-dev{ animation-delay:-5.6s }
.hl-hcard .hl-dev--counter{ transform:scale(.82) } .hl-hcard .hl-dev--counter{ --hl-k:.82 }
.hl-hcard .hl-dev--portable{ transform:scale(.86) } .hl-hcard .hl-dev--portable{ --hl-k:.86 }
.hl-hcard .hl-dev--reader{ transform:scale(1)    } .hl-hcard .hl-dev--reader{ --hl-k:1 }
.hl-hcard .hl-dev--rest{ transform:scale(.8)     } .hl-hcard .hl-dev--rest{ --hl-k:.8 }
.hl-hcard .hl-dev--pump{ transform:scale(.7)     } .hl-hcard .hl-dev--pump{ --hl-k:.7 }
/*
 * The caption is a column, so the card's affordance can sit on its bottom edge.
 *
 * It used to be a plain block, which meant "View details" floated wherever the
 * description happened to end. On the hardware insert that put the same control
 * at four different heights — 355px down a 396px card next to 315px down a
 * 376px one — and since the card's own ::after glow IS the light band across
 * the bottom, the link landed inside that band on a long caption and above it
 * on a short one. Two cards side by side looked like two different components.
 *
 * `margin-top:auto` on the link is the whole fix, and it only does anything
 * where the caption has spare height to give it — see the two chapters below
 * that make the caption `flex:1`. Where the SLOT is the growing child
 * (`.hl-hrow`, the POS landing chapter), the caption stays at its natural
 * height and this resolves to zero, so that chapter renders exactly as before.
 *
 * `align-self:flex-start` keeps the anchor shrink-wrapped: as a column flex
 * item it would otherwise stretch the full card width, and with it the focus
 * ring. `padding-top` replaces the old `margin-top:12px`, because a margin that
 * has become `auto` can no longer also be the minimum gap.
 */
.hl-hcard__meta{ display:flex; flex-direction:column; min-width:0; }
.hl-hcard__meta b{ display:block; font:700 var(--hl-fs-h4)/1.3 var(--hl-ff-display); color:var(--hl-text-dark);
  letter-spacing:-.02em; }
.hl-hcard__meta i{ display:block; margin-top:4px; font-size:var(--hl-fs-xs); color:var(--hl-text-muted); }

/* The card's link to the device's own page.
   It sits in the caption rather than around the card because `.hl-pslot` is the
   flex:1 child that keeps the silhouettes aligned across a row — an anchor
   wrapping the contents would become the flex item and the row would go ragged.
   So the anchor stays in flow and stretches a transparent overlay across the
   card instead: one tab stop, one click target the size of the card.

   The overlay is the anchor's ::after, positioned against `.hl-hcard` (which is
   already position:relative) — so the anchor itself must NOT be a positioned
   element, or the overlay would cover the three words instead of the card. The
   card's own ::after is the glow and is pointer-events:none, so nothing
   competes for the click. */
.hl-hcard__link{
  display:inline-flex; align-items:center; gap:6px; align-self:flex-start;
  margin-top:auto; padding-top:12px; color:var(--hl-brand-red);
  font:600 var(--hl-fs-xs)/1.4 var(--hl-ff-body);
}
.hl-hcard__link::after{ content:""; position:absolute; inset:0; z-index:1; }
.hl-hcard__link .hl-arrow{ transition:transform var(--hl-t-med) var(--hl-e-out); }
.hl-hcard--linked:hover .hl-hcard__link{ color:var(--hl-red-600); }
.hl-hcard--linked:hover .hl-hcard__link .hl-arrow{ transform:translateX(3px); }
.hl-hcard__link:focus-visible{ outline:2px solid var(--hl-brand-red); outline-offset:3px; }

/* ── 10 · ABOUT + WHY ───────────────────────────────────────────────────── */
/* two light chapters meet here — the shared tone means a full double pad
   would read as one empty band, so the opening pad is reduced */
.hl-story{ position:relative; padding-block:var(--hl-sec-pad-sm) var(--hl-sec-pad); overflow:hidden;
  background:linear-gradient(180deg,var(--hl-paper) 0%,#fff 30%,#fff 70%,var(--hl-paper) 100%); }
.hl-story__about{ display:grid; grid-template-columns:1.06fr .94fr; gap:clamp(40px,5vw,88px);
  align-items:center; padding-bottom:var(--hl-sec-pad-sm); }
.hl-story__title{ font-size:var(--hl-fs-h2); margin-bottom:var(--hl-s-6); max-width:22ch; }
.hl-story__copy p{ color:var(--hl-text-body); max-width:54ch; }
.hl-story__points{ margin-top:var(--hl-s-8); display:grid; gap:2px; }
.hl-story__points li{ display:flex; align-items:center; gap:14px; padding:14px 0;
  border-top:1px solid var(--hl-line); font-size:var(--hl-fs-sm); color:var(--hl-text-dark); font-weight:500; }
.hl-story__points li:last-child{ border-bottom:1px solid var(--hl-line); }
.hl-story__points span{ font:500 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:var(--hl-brand-red);
  letter-spacing:.14em; }

.hl-stack{ position:relative; display:grid; gap:12px; padding:0 0 0 40px; }
.hl-stack__slab{
  position:relative; padding:18px 22px; border-radius:var(--hl-r-md);
  border:1px solid var(--hl-line); background:#fff; box-shadow:var(--hl-sh-sm);
  transition:transform 420ms var(--hl-e-out);
}
.hl-stack__slab b{ display:block; font:700 var(--hl-fs-h4)/1.2 var(--hl-ff-display); color:var(--hl-text-dark);
  letter-spacing:-.02em; }
.hl-stack__slab i{ display:block; margin-top:3px; font-size:var(--hl-fs-xs); color:var(--hl-text-muted); }
.hl-stack__slab--4{ margin-left:54px; background:linear-gradient(120deg,var(--hl-ink-750),var(--hl-ink-850));
  border-color:transparent; box-shadow:var(--hl-sh-md); }
.hl-stack__slab--4 b{ color:#fff; } .hl-stack__slab--4 i{ color:var(--hl-text-light-3); }
.hl-stack__slab--3{ margin-left:36px; }
.hl-stack__slab--2{ margin-left:18px; }
.hl-stack__slab--1{ margin-left:0; border-left:3px solid var(--hl-red-500); }
.hl-stack:hover .hl-stack__slab{ transform:translateX(-6px); }
.hl-stack:hover .hl-stack__slab--4{ transform:translateX(-14px); }
.hl-stack__brace{
  position:absolute; left:16px; top:8px; bottom:8px; width:16px;
  border-left:1.5px solid var(--hl-line-2); border-top:1.5px solid var(--hl-line-2);
  border-bottom:1.5px solid var(--hl-line-2); border-radius:8px 0 0 8px;
}
.hl-stack__caption{
  position:absolute; left:-6px; top:50%; transform:translateY(-50%) rotate(-90deg);
  transform-origin:center; font:600 var(--hl-fs-micro)/1 var(--hl-ff-body);
  letter-spacing:var(--hl-ls-wider); text-transform:uppercase; color:var(--hl-text-muted);
  white-space:nowrap;
}

.hl-why{ border-top:1px solid var(--hl-line); padding-top:var(--hl-sec-pad-sm); }
.hl-wgrid{ display:grid; grid-template-columns:repeat(12,1fr); gap:16px;
  grid-auto-rows:minmax(170px,auto); }

.hl-wprime{
  grid-column:1/span 7; grid-row:1/span 2; position:relative; overflow:hidden;
  display:grid; grid-template-columns:1.05fr .95fr; gap:var(--hl-s-8); align-items:center;
  padding:clamp(26px,2.6vw,38px); border-radius:var(--hl-r-xl);
  background:linear-gradient(155deg,var(--hl-ink-750) 0%,var(--hl-ink-850) 55%,var(--hl-ink-950) 100%);
  color:var(--hl-text-light-2);
}
.hl-wprime::before{
  content:""; position:absolute; right:-18%; top:-28%; width:64%; aspect-ratio:1;
  border-radius:50%; background:radial-gradient(circle, rgba(207,41,39,.22), transparent 62%);
}
.hl-wprime__copy{ position:relative; }
.hl-wprime__ico{ width:24px; height:24px; color:var(--hl-navy-300); margin-bottom:var(--hl-s-5); }
.hl-wprime h3{ color:#fff; font-size:var(--hl-fs-h3); max-width:20ch; margin-bottom:var(--hl-s-4); }
.hl-wprime p{ color:var(--hl-text-light-2); font-size:var(--hl-fs-sm); max-width:42ch; }
.hl-wprime__list{ margin-top:var(--hl-s-6); display:grid; gap:1px; }
.hl-wprime__list li{ position:relative; padding:9px 0 9px 18px; border-top:1px solid var(--hl-line-dark);
  font-size:var(--hl-fs-xs); color:var(--hl-text-light-3); }
.hl-wprime__list li:last-child{ border-bottom:1px solid var(--hl-line-dark); }
.hl-wprime__list li::before{ content:""; position:absolute; left:0; top:15px; width:6px; height:6px;
  border-radius:2px; background:var(--hl-red-500); }

/* square stage keeps the three circles in a predictable overlap at any width */
.hl-wprime__viz{ position:relative; width:100%; max-width:330px; aspect-ratio:1/1;
  margin-inline:auto; }
.hl-venn__c{
  position:absolute; width:52%; aspect-ratio:1/1; border-radius:50%; display:grid;
  font:600 var(--hl-fs-xs)/1.1 var(--hl-ff-display); letter-spacing:-.01em; color:#fff;
  border:1px solid rgba(255,255,255,.26); backdrop-filter:blur(2px);
}
.hl-venn__c--a{ left:0;   top:22%; background:rgba(58,63,163,.34); place-items:center start; padding-left:7%; }
.hl-venn__c--b{ left:24%; top:0;   background:rgba(90,97,204,.30); place-items:start center; padding-top:7%; }
.hl-venn__c--c{ left:48%; top:22%; background:rgba(207,41,39,.26); border-color:rgba(229,84,78,.5);
  place-items:center end; padding-right:7%; }
.hl-venn__core{
  position:absolute; left:0; right:0; bottom:0; width:auto; height:auto;
  text-align:center; font:700 var(--hl-fs-micro)/1.4 var(--hl-ff-body); letter-spacing:.16em;
  text-transform:uppercase; color:var(--hl-text-light-3); pointer-events:none;
}

.hl-wtile{
  position:relative; padding:26px; border-radius:var(--hl-r-xl); background:#fff;
  border:1px solid var(--hl-line); box-shadow:var(--hl-sh-sm); overflow:hidden;
  display:flex; flex-direction:column;
  transition:transform 420ms var(--hl-e-out), box-shadow 420ms var(--hl-e-out);
}
.hl-wtile:hover{ transform:translateY(-5px); box-shadow:var(--hl-sh-md); }
.hl-wtile h3{ font-size:1.04rem; margin-bottom:9px; letter-spacing:-.02em; }
.hl-wtile p{ font-size:var(--hl-fs-sm); color:var(--hl-text-muted); }
.hl-wtile__ico{ width:22px; height:22px; color:var(--hl-brand-navy); margin-bottom:16px; }
/* explicit placement by document order (nth-child, not nth-of-type) */
.hl-wgrid > :nth-child(2){ grid-column:8/span 5; grid-row:1; }
.hl-wgrid > :nth-child(3){ grid-column:8/span 5; grid-row:2; }
.hl-wgrid > :nth-child(4){ grid-column:1/span 4; grid-row:3; }
.hl-wgrid > :nth-child(5){ grid-column:5/span 4; grid-row:3; }
.hl-wgrid > :nth-child(6){ grid-column:9/span 4; grid-row:3; }

.hl-wtile--metric{ flex-direction:row; align-items:flex-start; gap:var(--hl-s-8); }
.hl-wtile--metric .hl-wtile__ico{ margin-bottom:0; }
.hl-wtile--metric > div,
.hl-wtile--metric > h3,
.hl-wtile--metric > p{ }
.hl-wtile__figure{ font:800 clamp(2.6rem,4.4vw,3.5rem)/1 var(--hl-ff-display);
  color:var(--hl-text-dark); letter-spacing:-.045em; }
.hl-wtile--metric{ display:grid; grid-template-columns:auto 1fr; grid-template-rows:auto auto auto;
  gap:6px 22px; align-content:center; }
.hl-wtile--metric .hl-wtile__ico{ grid-row:1/span 3; align-self:center; width:30px; height:30px;
  color:var(--hl-navy-500); }
.hl-wtile--metric .hl-wtile__figure{ grid-column:2; }
.hl-wtile--metric h3{ grid-column:2; margin:0; }
.hl-wtile--metric p{ grid-column:2; }
.hl-wtile__bars{ grid-column:2; display:flex; align-items:flex-end; gap:2px; height:30px; margin-top:12px; }
.hl-wtile__bars b{ flex:1; border-radius:1.5px; background:var(--hl-paper-3); }

/* ── The Why tile's foot accents ───────────────────────────────────────────
   `grid-auto-rows:1fr` gives every tile in the row the tallest tile's height,
   and these two accents were pinned to the card's FLOOR with `margin-top:auto`.
   On Home the tallest tile carries seven chips, so "Equipment options" showed
   280px of blank before its `$0` line and "Dedicated support" showed 300px and
   then a 2px red rule with nothing above it — a hairline floating in empty
   space, which reads as a rendering fault rather than an accent (audit H-03).

   The accents now follow their copy at the flow contract's distance, and a
   tile with spare height centres what it has instead of pushing its last
   element to the bottom of a box it did not ask to be. In a naturally-sized
   tile `margin-top:auto` was already 0, so nothing that was correct moves. */
.hl-wtile:not(.hl-wtile--metric):not(.hl-wtile--ind){ justify-content:center; }
.hl-wtile__stat{ margin-top:var(--hl-flow); padding-top:16px; display:flex; align-items:baseline; gap:10px; }
.hl-wtile__stat b{ font:800 2.1rem/1 var(--hl-ff-display); color:var(--hl-brand-red); letter-spacing:-.04em; }
.hl-wtile__stat i{ font-size:var(--hl-fs-micro); color:var(--hl-text-muted); max-width:16ch; line-height:1.4; }

.hl-pulse-line{ margin-top:var(--hl-flow); padding-top:0; height:2px; }
.hl-pulse-line span{ display:block; height:2px; border-radius:2px;
  background:linear-gradient(90deg, var(--hl-paper-3) 0 40%, var(--hl-red-500) 50%, var(--hl-paper-3) 60% 100%);
  background-size:250% 100%; animation:hls-sweep 3.2s var(--hl-e-inout) infinite; }
@keyframes hls-sweep{ 0%{background-position:120% 0} 100%{background-position:-40% 0} }

.hl-wtile--ind{ gap:var(--hl-s-5); }
.hl-wtile__half{ display:flex; flex-direction:column; align-items:flex-start; }
.hl-wtile__chips{ margin:0; align-content:flex-start; }

/* ── 11 · INDUSTRIES ────────────────────────────────────────────────────── */
.hl-ind{ position:relative; padding-block:var(--hl-sec-pad); overflow:hidden;
  background:linear-gradient(180deg,#0E1230 0%,#080A1D 100%); }
.hl-ind__wrap{ display:grid; grid-template-columns:minmax(240px,296px) 1fr;
  gap:clamp(28px,3.2vw,52px); align-items:start; }
.hl-ind__nav{ grid-column:1; grid-row:1; display:grid; gap:2px; align-content:start; }
.hl-itab{
  position:relative; width:100%; text-align:left; display:flex; align-items:center; gap:14px;
  padding:18px 16px; border-radius:var(--hl-r-md); border-left:2px solid var(--hl-line-dark);
  transition:background var(--hl-t-med), border-color var(--hl-t-med);
}
.hl-itab:hover{ background:rgba(255,255,255,.04); }
.hl-itab.is-active{ background:rgba(255,255,255,.07); border-left-color:var(--hl-red-500); }
.hl-itab__idx{ font:500 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:var(--hl-text-light-4); letter-spacing:.14em; }
.hl-itab__name{ font:600 1.02rem/1.25 var(--hl-ff-display); color:var(--hl-text-light-3);
  letter-spacing:-.02em; transition:color var(--hl-t-med); }
.hl-itab.is-active .hl-itab__name{ color:#fff; }
.hl-itab__prog{ position:absolute; left:0; right:16px; bottom:6px; height:1.5px;
  background:rgba(255,255,255,.08); border-radius:2px; overflow:hidden; opacity:0;
  transition:opacity var(--hl-t-med); }
.hl-itab.is-active .hl-itab__prog{ opacity:1; }
.hl-itab__prog b{ display:block; height:100%; width:0; background:var(--hl-red-500); border-radius:2px; }
.hl-itab.is-active .hl-itab__prog b{ animation:hls-prog var(--hl-dur,7s) linear forwards; }
.hl-ind__wrap.is-paused .hl-itab.is-active .hl-itab__prog b{ animation-play-state:paused; }
@keyframes hls-prog{ from{ width:0 } to{ width:100% } }

.hl-ind__aside{ grid-column:1; grid-row:2; padding:22px 20px; border-radius:var(--hl-r-lg);
  background:linear-gradient(155deg, rgba(255,255,255,.07), rgba(255,255,255,.015));
  border:1px solid var(--hl-line-dark); }
.hl-ind__aside-ico{ width:20px; height:20px; color:var(--hl-navy-300); margin-bottom:14px; }
.hl-ind__aside b{ display:block; font:700 1.02rem/1.2 var(--hl-ff-display); color:#fff;
  letter-spacing:-.02em; margin-bottom:8px; }
.hl-ind__aside p{ font-size:var(--hl-fs-xs); color:var(--hl-text-light-3); line-height:1.6;
  margin-bottom:var(--hl-s-5); }

.hl-ind__stage{ grid-column:2; grid-row:1/span 2; position:relative; }
.hl-ipanel{
  display:grid; grid-template-columns:1.04fr .96fr; gap:clamp(24px,2.8vw,44px); align-items:center;
  padding:clamp(28px,2.8vw,44px); border-radius:var(--hl-r-2xl); height:100%;
  background:linear-gradient(150deg, rgba(255,255,255,.08), rgba(255,255,255,.02));
  border:1px solid var(--hl-line-dark-2);
  box-shadow:0 40px 90px -40px rgba(0,0,0,.9), inset 0 1px 0 rgba(255,255,255,.08);
  min-height:470px;
}
.hl-ipanel[hidden]{ display:none; }
.hl-ipanel.is-active{ animation:hls-panelIn 480ms var(--hl-e-out); }
.hl-ipanel__kicker{ display:inline-block; margin-bottom:14px; padding:5px 11px; border-radius:var(--hl-r-xs);
  background:rgba(255,255,255,.07); border:1px solid var(--hl-line-dark-2);
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-navy-300); }
.hl-ipanel__copy h3{ font-size:var(--hl-fs-h3); color:#fff; margin-bottom:var(--hl-s-4); max-width:26ch; }
.hl-ipanel__copy p{ font-size:var(--hl-fs-body); color:var(--hl-text-light-2); max-width:46ch;
  margin-bottom:var(--hl-s-5); }
.hl-offer{
  display:flex; align-items:center; gap:10px; margin-bottom:var(--hl-s-5); padding:11px 14px;
  border-radius:var(--hl-r-sm); font-size:var(--hl-fs-xs); color:#fff;
  background:linear-gradient(100deg, rgba(42,45,124,.55), rgba(42,45,124,.12));
  border:1px solid rgba(144,150,228,.3);
}
.hl-offer b{ flex:none; font:700 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-navy-300); }
.hl-offer--red{ background:linear-gradient(100deg, rgba(207,41,39,.32), rgba(207,41,39,.06));
  border-color:rgba(229,84,78,.42); }
.hl-offer--red b{ color:var(--hl-red-300); }
.hl-ilist{ display:grid; gap:1px; margin-bottom:var(--hl-s-6); }
.hl-ilist li{ position:relative; padding:10px 0 10px 20px; border-top:1px solid var(--hl-line-dark);
  font-size:var(--hl-fs-sm); color:var(--hl-text-light-2); }
.hl-ilist li:last-child{ border-bottom:1px solid var(--hl-line-dark); }
.hl-ilist li::before{ content:""; position:absolute; left:0; top:17px; width:7px; height:7px;
  border-radius:2px; background:var(--hl-red-500); }
.hl-ipanel__foot{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--hl-s-5); }
.hl-ipanel__equip{ font-size:var(--hl-fs-micro); color:var(--hl-text-light-4); letter-spacing:.04em; }
.hl-ipanel__equip b{ color:var(--hl-text-light-2); font-weight:500; }

.hl-ipanel__viz{ position:relative; display:grid; place-items:center; min-height:360px; }
.hl-scene__ring{
  position:absolute; inset:6% 4%; border-radius:50%;
  border:1px solid rgba(255,255,255,.10);
  background:radial-gradient(circle at 50% 45%, rgba(90,97,204,.22), transparent 62%);
}
.hl-scene__ring::after{
  content:""; position:absolute; inset:14%; border-radius:50%;
  border:1px dashed rgba(255,255,255,.09); animation:hls-rot 44s linear infinite;
}
@keyframes hls-rot{ to{ transform:rotate(360deg) } }
.hl-scene__rte{ position:absolute; inset:0; width:100%; height:100%; }
.hl-ipanel__viz .hl-pslot{ position:relative; z-index:1; }
.hl-ipanel__viz .hl-dev{ animation:hls-hover 7s var(--hl-e-inout) infinite; }
.hl-pslot--lg .hl-dev{ --hl-k:1.2; transform:scale(1.2); }
.hl-ichip{
  position:absolute; z-index:2; padding:8px 12px; border-radius:var(--hl-r-sm);
  background:rgba(10,12,34,.86); border:1px solid var(--hl-line-dark-2);
  backdrop-filter:blur(10px); box-shadow:0 14px 30px -14px rgba(0,0,0,.85);
  font:500 var(--hl-fs-xs)/1 var(--hl-ff-body); color:#fff; white-space:nowrap;
}
.hl-ichip--a{ top:12%; right:0; animation:hls-bob 7s var(--hl-e-inout) infinite; }
.hl-ichip--b{ bottom:30%; left:0; animation:hls-bob 7s var(--hl-e-inout) -3.5s infinite; }

/* ── 12 · HIGHLINE NETWORK ──────────────────────────────────────────────── */
.hl-net-sec{ position:relative; padding-block:var(--hl-sec-pad); overflow:hidden;
  background:linear-gradient(180deg,#080A1D,#04050E); }
.hl-netgrid{ display:grid; grid-template-columns:1.25fr .75fr; gap:clamp(24px,3vw,52px);
  align-items:stretch; }

.hl-nstar{
  position:relative; display:grid; place-items:center; min-height:420px; overflow:hidden;
  padding:clamp(28px,3vw,48px); border-radius:var(--hl-r-2xl);
  background:linear-gradient(155deg, rgba(255,255,255,.07), rgba(255,255,255,.015));
  border:1px solid var(--hl-line-dark-2);
  box-shadow:0 40px 90px -40px rgba(0,0,0,.9);
}
.hl-nstar__web{ position:absolute; left:50%; top:50%; width:min(560px,108%); aspect-ratio:1/1;
  transform:translate(-50%,-50%); }
.hl-nstar__ring{ stroke:rgba(255,255,255,.10); stroke-width:1; fill:none; }
.hl-nstar__spokes path{ stroke:rgba(255,255,255,.07); stroke-width:1; }
.hl-nstar__dots circle{ fill:var(--hl-navy-300); opacity:.55;
  animation:hls-nodePulse 4s var(--hl-e-inout) infinite; }
.hl-nstar__dots circle:nth-child(2){ animation-delay:.4s } .hl-nstar__dots circle:nth-child(3){ animation-delay:.8s }
.hl-nstar__dots circle:nth-child(4){ animation-delay:1.2s } .hl-nstar__dots circle:nth-child(5){ animation-delay:1.6s }
.hl-nstar__dots circle:nth-child(6){ animation-delay:2s }  .hl-nstar__dots circle:nth-child(7){ animation-delay:2.4s }
.hl-nstar__dots circle:nth-child(8){ animation-delay:2.8s }
.hl-nstar__dots circle.is-red{ fill:var(--hl-red-400); opacity:.9; }
@keyframes hls-nodePulse{ 0%,100%{ opacity:.28 } 50%{ opacity:.9 } }
.hl-nstar__figure{ position:relative; text-align:center; max-width:34ch; }
.hl-nstar__figure b{ display:block; font:800 clamp(4.4rem,9vw,7.5rem)/.9 var(--hl-ff-display);
  color:#fff; letter-spacing:-.05em; font-variant-numeric:tabular-nums;
  text-shadow:0 24px 60px rgba(0,0,0,.6); }
.hl-nstar__figure span{ display:block; margin-top:var(--hl-s-4);
  font:700 clamp(1.05rem,1.5vw,1.3rem)/1.2 var(--hl-ff-display); color:#fff; letter-spacing:-.02em; }
.hl-nstar__figure i{ display:block; margin-top:var(--hl-s-3); font-size:var(--hl-fs-sm);
  color:var(--hl-text-light-3); line-height:1.6; }

.hl-ncol{ display:grid; gap:clamp(12px,1.2vw,16px); }
.hl-ncard{
  display:flex; flex-direction:column; justify-content:center; gap:6px;
  padding:clamp(20px,2vw,28px); border-radius:var(--hl-r-xl);
  background:linear-gradient(155deg, rgba(255,255,255,.055), rgba(255,255,255,.012));
  border:1px solid var(--hl-line-dark); transition:background var(--hl-t-med), border-color var(--hl-t-med);
}
.hl-ncard:hover{ background:rgba(255,255,255,.085); border-color:var(--hl-line-dark-2); }
.hl-ncard b{ font:800 clamp(2.4rem,3.6vw,3.1rem)/1 var(--hl-ff-display); color:#fff;
  letter-spacing:-.045em; font-variant-numeric:tabular-nums; }
.hl-ncard span{ font:700 1.02rem/1.25 var(--hl-ff-display); color:#fff; letter-spacing:-.02em; }
.hl-ncard i{ font-size:var(--hl-fs-xs); color:var(--hl-text-light-3); line-height:1.55; }
.hl-ncard__ico{ width:26px; height:26px; color:var(--hl-navy-300); margin-bottom:10px; }
.hl-net-sec__disc{ margin:var(--hl-s-8) 0 0; font-size:var(--hl-fs-micro); color:var(--hl-text-light-4);
  max-width:80ch; }

/* ── 13 · CALCULATOR ────────────────────────────────────────────────────── */
.hl-calc{ position:relative; padding-block:var(--hl-sec-pad); overflow:hidden;
  background:linear-gradient(180deg,var(--hl-paper),#fff 65%); }
.hl-calcbox{
  display:grid; grid-template-columns:1.06fr .94fr; border-radius:var(--hl-r-2xl); overflow:hidden;
  background:#fff; border:1px solid var(--hl-line); box-shadow:var(--hl-sh-lg);
}
.hl-calcbox__inputs{ padding:clamp(28px,2.8vw,44px); display:grid; gap:var(--hl-s-8); align-content:start; }

.hl-field__top{ display:flex; justify-content:space-between; align-items:baseline; margin-bottom:14px; }
.hl-field label{ font:600 var(--hl-fs-sm)/1 var(--hl-ff-display); color:var(--hl-text-dark); letter-spacing:-.01em; }
.hl-field__val{ font:700 1.32rem/1 var(--hl-ff-display); color:var(--hl-text-dark); letter-spacing:-.03em;
  font-variant-numeric:tabular-nums; }
.hl-field__val--red{ color:var(--hl-brand-red); }
.hl-field__scale{ display:flex; justify-content:space-between; margin-top:8px;
  font:400 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:var(--hl-text-muted); }

input[type=range]{ -webkit-appearance:none; appearance:none; width:100%; height:22px;
  background:none; cursor:pointer; }
input[type=range]::-webkit-slider-runnable-track{
  height:6px; border-radius:3px;
  background:linear-gradient(90deg, var(--hl-brand-navy) var(--hl-p,50%), var(--hl-paper-2) var(--hl-p,50%));
}
input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none; width:22px; height:22px; margin-top:-8px; border-radius:50%;
  background:#fff; border:2px solid var(--hl-brand-navy);
  box-shadow:0 4px 12px -3px rgba(10,14,36,.4);
  transition:transform var(--hl-t-fast), border-color var(--hl-t-fast);
}
input[type=range]:hover::-webkit-slider-thumb{ transform:scale(1.12); }
input[type=range]::-moz-range-track{ height:6px; border-radius:3px; background:var(--hl-paper-2); }
input[type=range]::-moz-range-progress{ height:6px; border-radius:3px; background:var(--hl-brand-navy); }
input[type=range]::-moz-range-thumb{ width:18px; height:18px; border-radius:50%; background:#fff;
  border:2px solid var(--hl-brand-navy); }
/* No Highline-rate readout exists in this UI by design — see app.js module 11.
   The `.hl-hlrate` block, the `.hl-rrow--hl` cost row and the `.hl-cbars` comparison bars
   were all removed because each exposed the internal comparison percentage. */

/* pricing mode selector */
.hl-modes{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
.hl-mode{
  text-align:left; padding:15px 16px; border-radius:var(--hl-r-md);
  border:1px solid var(--hl-line); background:var(--hl-paper);
  transition:border-color var(--hl-t-med), background var(--hl-t-med), box-shadow var(--hl-t-med);
}
.hl-mode b{ display:block; font:600 var(--hl-fs-sm)/1.2 var(--hl-ff-display); color:var(--hl-text-dark);
  letter-spacing:-.01em; }
.hl-mode i{ display:block; margin-top:4px; font-size:var(--hl-fs-micro); color:var(--hl-text-muted); }
.hl-mode:hover{ border-color:var(--hl-line-2); }
.hl-mode.is-on{ background:#fff; border-color:var(--hl-brand-red);
  box-shadow:0 0 0 3px rgba(207,41,39,.10), var(--hl-sh-sm); }
.hl-mode.is-on b{ color:var(--hl-brand-red); }

.hl-calcbox__rows{ border-top:1px solid var(--hl-line); padding-top:var(--hl-s-6); }
.hl-rrow{ display:flex; justify-content:space-between; align-items:baseline; gap:12px;
  padding:11px 0; }
.hl-rrow__k{ font-size:var(--hl-fs-sm); color:var(--hl-text-muted); }
.hl-rrow__k em{ font-size:var(--hl-fs-micro); color:var(--hl-text-muted); opacity:.7; }
.hl-rrow__v{ font:700 1.22rem/1 var(--hl-ff-display); color:var(--hl-text-dark); letter-spacing:-.03em;
  font-variant-numeric:tabular-nums; }
.hl-rrow + .hl-rrow{ border-top:1px solid var(--hl-line); }
.hl-calcbox__hint{ margin:var(--hl-s-3) 0 0; font-size:var(--hl-fs-micro); color:var(--hl-text-muted);
  line-height:1.5; }

.hl-calcbox__result{
  position:relative; overflow:hidden; padding:clamp(28px,2.8vw,44px);
  background:linear-gradient(165deg,var(--hl-ink-750) 0%,var(--hl-ink-850) 60%,var(--hl-ink-950) 100%);
  display:flex; flex-direction:column;
}
.hl-calcbox__result > *{ position:relative; z-index:1; }
.hl-calcbox__result .hl-infra{ z-index:0; }
.hl-calcbox__result::before{
  content:""; position:absolute; right:-30%; top:-20%; width:80%; aspect-ratio:1; border-radius:50%;
  background:radial-gradient(circle, rgba(207,41,39,.20), transparent 62%); z-index:0;
}
.hl-calcbox__resultHead{ display:flex; justify-content:space-between; align-items:center;
  margin-bottom:var(--hl-s-8); }
.hl-calcbox__resultHead .hl-eyebrow{ margin-bottom:0; }
.hl-calcbox__mode{ font:600 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:.06em;
  text-transform:uppercase; color:var(--hl-text-light-3); padding:5px 10px; border-radius:var(--hl-r-xs);
  background:rgba(255,255,255,.06); border:1px solid var(--hl-line-dark); white-space:nowrap; }

.hl-bigsave{ margin-bottom:var(--hl-s-6); }
.hl-bigsave__k{ display:block; font:600 var(--hl-fs-micro)/1 var(--hl-ff-body);
  letter-spacing:var(--hl-ls-wider); text-transform:uppercase; color:var(--hl-text-light-4); }
.hl-bigsave__v{
  display:block; margin:var(--hl-s-4) 0 var(--hl-s-3);
  font:800 clamp(3rem,5.4vw,4.4rem)/.92 var(--hl-ff-display); color:#fff; letter-spacing:-.05em;
  font-variant-numeric:tabular-nums; text-shadow:0 20px 50px rgba(0,0,0,.55);
}
.hl-bigsave__sub{ display:inline-flex; align-items:center; gap:8px; padding:7px 13px;
  border-radius:var(--hl-r-pill); background:rgba(207,41,39,.18); border:1px solid rgba(229,84,78,.34);
  font-size:var(--hl-fs-xs); color:#fff; }
.hl-bigsave__sub span{ font-weight:700; font-variant-numeric:tabular-nums; }

.hl-cdnote{
  display:none; margin:0 0 var(--hl-s-6); padding:14px;
  border-radius:var(--hl-r-md); font-size:var(--hl-fs-xs); color:var(--hl-text-light-2);
  background:rgba(47,214,163,.08); border:1px solid rgba(47,214,163,.3);
}
.hl-cdnote b{ color:var(--hl-ok); }
.hl-cdnote__pill{ display:inline-block; margin-right:6px; padding:3px 8px; border-radius:4px;
  background:rgba(47,214,163,.16); color:var(--hl-ok);
  font:700 var(--hl-fs-micro)/1.5 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide); text-transform:uppercase; }
.hl-calcbox__result[data-cd-state="on"] .hl-cdnote{ display:block; }
.hl-calcbox__result[data-cd-state="on"] .hl-bigsave__sub{
  background:rgba(47,214,163,.16); border-color:rgba(47,214,163,.35); }

.hl-calcbox__list{ display:grid; gap:1px; margin-bottom:var(--hl-s-6); }
.hl-calcbox__list li{ position:relative; padding:9px 0 9px 20px; border-top:1px solid var(--hl-line-dark);
  font-size:var(--hl-fs-xs); color:var(--hl-text-light-3); }
.hl-calcbox__list li:last-child{ border-bottom:1px solid var(--hl-line-dark); }
.hl-calcbox__list li::before{ content:""; position:absolute; left:0; top:15px; width:6px; height:6px;
  border-radius:2px; background:var(--hl-red-500); }
.hl-calcbox__disc{ margin:auto 0 var(--hl-s-5); padding-top:var(--hl-s-4);
  font-size:var(--hl-fs-micro); color:var(--hl-text-light-4); border-top:1px solid var(--hl-line-dark); }

/* ── 14 · FUNDING ───────────────────────────────────────────────────────── */
.hl-fund{ position:relative; padding-block:var(--hl-sec-pad); overflow:hidden;
  background:linear-gradient(175deg,#0B0E28 0%,#141949 46%,#080A1D 100%); }
.hl-fund__wrap{ display:grid; grid-template-columns:1.08fr .92fr; gap:clamp(28px,3.4vw,64px);
  align-items:center; }

.hl-fchart{ position:relative; padding:clamp(22px,2.4vw,34px); border-radius:var(--hl-r-2xl);
  background:linear-gradient(155deg, rgba(255,255,255,.06), rgba(255,255,255,.012));
  border:1px solid var(--hl-line-dark-2); }
.hl-fchart__plot{ position:relative; }
.hl-fchart__svg{ display:block; width:100%; height:clamp(220px,24vw,300px); }
.hl-fchart__area{ fill:url(#hl-fund-area); }
.hl-fchart__line{ stroke:url(#hl-fund-line); stroke-width:2.4; fill:none; stroke-linecap:round;
  vector-effect:non-scaling-stroke; }
.hl-fchart__live{ stroke:#fff; stroke-width:2.4; fill:none; stroke-linecap:round;
  vector-effect:non-scaling-stroke;
  stroke-dasharray:60 1400; stroke-dashoffset:1460;
  animation:hls-rteFlow 6s linear infinite; opacity:.85; }
.hl-fmark{
  position:absolute; left:var(--hl-x); top:var(--hl-y);
  width:34px; height:34px; margin:-17px 0 0 -17px; border-radius:50%;
  display:grid; place-items:center; z-index:2;
  background:rgba(10,12,34,.85); border:1.5px solid var(--hl-line-dark-2);
  backdrop-filter:blur(8px);
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:var(--hl-text-light-3); letter-spacing:.06em;
  transition:transform var(--hl-t-med) var(--hl-e-out), background var(--hl-t-med),
             border-color var(--hl-t-med), color var(--hl-t-med), box-shadow var(--hl-t-med);
}
.hl-fmark:hover{ transform:scale(1.12); border-color:rgba(255,255,255,.34); color:#fff; }
.hl-fmark.is-active{
  background:linear-gradient(160deg,var(--hl-red-400),var(--hl-red-600)); border-color:var(--hl-red-300);
  color:#fff; box-shadow:0 0 0 6px rgba(207,41,39,.16), 0 12px 26px -10px rgba(207,41,39,.7);
  transform:scale(1.1);
}
.hl-fchart__axis{ display:grid; grid-template-columns:repeat(4,1fr); gap:8px; margin-top:var(--hl-s-5);
  padding-top:var(--hl-s-4); border-top:1px solid var(--hl-line-dark); }
.hl-fchart__axis span{ font:500 var(--hl-fs-micro)/1.3 var(--hl-ff-body); letter-spacing:.06em;
  text-transform:uppercase; color:var(--hl-text-light-4); }
.hl-fchart__axis span:nth-child(2),.hl-fchart__axis span:nth-child(3){ text-align:center; }
.hl-fchart__axis span:last-child{ text-align:right; color:var(--hl-red-300); }
.hl-fchart__cap{ display:block; margin-top:var(--hl-s-3); font-size:var(--hl-fs-micro);
  color:var(--hl-text-light-4); }

.hl-frows{ display:grid; gap:1px; margin-bottom:var(--hl-s-8); }
.hl-frow{
  position:relative; display:flex; align-items:flex-start; gap:18px; padding:20px 18px;
  border-top:1px solid var(--hl-line-dark); border-radius:var(--hl-r-md); cursor:pointer;
  transition:background var(--hl-t-med) var(--hl-e-out), transform var(--hl-t-med) var(--hl-e-out);
}
.hl-frow:last-child{ border-bottom:1px solid var(--hl-line-dark); }
.hl-frow::before{
  content:""; position:absolute; left:0; top:50%; width:2px; height:0; border-radius:2px;
  background:var(--hl-red-500); transform:translateY(-50%);
  transition:height var(--hl-t-med) var(--hl-e-out);
}
.hl-frow:hover,.hl-frow.is-active{ background:rgba(255,255,255,.055); }
.hl-frow.is-active{ transform:translateX(5px); }
.hl-frow:hover::before,.hl-frow.is-active::before{ height:64%; }
.hl-frow__idx{ font:500 var(--hl-fs-micro)/1.6 var(--hl-ff-mono); color:var(--hl-text-light-4);
  letter-spacing:.14em; flex:none; transition:color var(--hl-t-med); }
.hl-frow.is-active .hl-frow__idx{ color:var(--hl-red-300); }
.hl-frow__body b{ display:block; font:700 1.1rem/1.25 var(--hl-ff-display); color:#fff;
  letter-spacing:-.025em; margin-bottom:5px; }
.hl-frow__body i{ display:block; font-size:var(--hl-fs-xs); color:var(--hl-text-light-3); max-width:52ch;
  line-height:1.6; }
.hl-frow__go{ margin-left:auto; align-self:center; color:var(--hl-text-light-4); flex:none;
  transition:transform var(--hl-t-med) var(--hl-e-out), color var(--hl-t-med); }
.hl-frow:hover .hl-frow__go,.hl-frow.is-active .hl-frow__go{ color:var(--hl-red-400); transform:translateX(5px); }
.hl-fund__cta{ display:flex; align-items:center; gap:var(--hl-s-5); flex-wrap:wrap; }
.hl-fund__note{ font-size:var(--hl-fs-xs); color:var(--hl-text-light-3); }

/* ── 15 · REVIEWS ───────────────────────────────────────────────────────── */
.hl-revs{ padding-block:var(--hl-sec-pad); background:#fff; }
.hl-revs__grid{ display:grid; grid-template-columns:1.35fr 1fr .85fr; gap:18px; align-items:stretch; }
.hl-rev{
  position:relative; padding:30px 26px 22px; border-radius:var(--hl-r-xl);
  background:linear-gradient(160deg,#fff,var(--hl-paper)); border:1px solid var(--hl-line);
  box-shadow:var(--hl-sh-sm); display:flex; flex-direction:column; min-height:340px;
  transition:transform 420ms var(--hl-e-out), box-shadow 420ms var(--hl-e-out);
}
.hl-rev:hover{ transform:translateY(-5px); box-shadow:var(--hl-sh-md); }
.hl-rev--primary{ background:linear-gradient(155deg,#fff,#EEF2FA); }
.hl-rev__quote{ position:absolute; top:6px; right:22px; font:800 5rem/1 var(--hl-ff-display);
  color:var(--hl-paper-2); pointer-events:none; }
.hl-rev__slot{
  position:relative; align-self:flex-start; padding:9px 13px; border-radius:var(--hl-r-xs);
  border:1px dashed var(--hl-line-2); background:#fff; color:var(--hl-brand-navy);
  font:700 .86rem/1.2 var(--hl-ff-display); letter-spacing:var(--hl-ls-wide); text-transform:uppercase;
}
.hl-rev__hint{ margin:16px 0 0; font-size:var(--hl-fs-xs); color:var(--hl-text-muted); max-width:34ch; }
.hl-rev__ph{ display:grid; gap:11px; margin:22px 0 auto; }
.hl-rev__ph b{ height:9px; border-radius:5px; background:var(--hl-paper-2); }
.hl-rev__ph b:nth-child(2){ width:92% } .hl-rev__ph b:nth-child(3){ width:78% }
.hl-rev__ph b:nth-child(4){ width:56% } .hl-rev__ph b:nth-child(5){ width:34% }
.hl-rev__foot{ display:flex; justify-content:space-between; align-items:center; gap:10px;
  padding-top:16px; border-top:1px solid var(--hl-line); font-size:var(--hl-fs-micro); }
.hl-rev__src{ color:var(--hl-text-muted); font-weight:500; }
.hl-rev__pending{ padding:3px 8px; border-radius:4px; background:var(--hl-paper-2);
  color:var(--hl-text-muted); font-family:var(--hl-ff-mono); letter-spacing:.04em; }

.hl-tp{ display:flex; flex-direction:column; gap:16px; padding:26px 24px; border-radius:var(--hl-r-xl);
  background:var(--hl-ink-850); border:1px solid transparent; }
.hl-tp__score{ display:grid; gap:12px; }
.hl-tp__num{ font:500 1.35rem/1 var(--hl-ff-mono); color:#fff; letter-spacing:.02em; }
.hl-tp__stars{ display:flex; gap:5px; }
.hl-tp__stars b{ width:22px; height:22px; background:rgba(255,255,255,.22);
  -webkit-mask:var(--hl-star) center/contain no-repeat; mask:var(--hl-star) center/contain no-repeat; }
.hl-tp__meta{ font-size:var(--hl-fs-micro); color:var(--hl-text-light-3); line-height:1.5; }
.hl-tp .hl-btn--dark{ margin-top:auto; background:#fff; color:var(--hl-ink-800); box-shadow:none; }
.hl-tp .hl-btn--dark:hover{ background:#fff; }
.hl-tp__note{ margin:0; font-size:var(--hl-fs-micro); color:var(--hl-text-light-4); line-height:1.5; }

/* ── 16 · PARTNERS ──────────────────────────────────────────────────────── */
.hl-partners{ padding-block:var(--hl-sec-pad-sm); background:var(--hl-paper);
  border-top:1px solid var(--hl-line); border-bottom:1px solid var(--hl-line); }
.hl-partners__label{ margin:0; font:600 var(--hl-fs-micro)/1 var(--hl-ff-body);
  letter-spacing:var(--hl-ls-wider); text-transform:uppercase; color:var(--hl-text-muted);
  text-align:center; }
.hl-marquee{
  position:relative; display:flex; overflow:hidden; margin-top:var(--hl-s-10); padding-block:26px;
  border-top:1px solid var(--hl-line); border-bottom:1px solid var(--hl-line);
  background:linear-gradient(180deg, rgba(255,255,255,.7), rgba(255,255,255,0));
  mask-image:linear-gradient(90deg,transparent,#000 11%,#000 89%,transparent);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 11%,#000 89%,transparent);
}
.hl-marquee__track{ display:flex; align-items:center; gap:clamp(32px,4.4vw,72px); flex:none;
  padding-right:clamp(32px,4.4vw,72px); animation:hls-slide 38s linear infinite; }
.hl-marquee:hover .hl-marquee__track{ animation-play-state:paused; }
@keyframes hls-slide{ to{ transform:translateX(-100%) } }
.hl-plogo{ font:500 clamp(.9rem,1.2vw,1.06rem)/1 var(--hl-ff-mono); letter-spacing:.04em;
  color:var(--hl-brand-navy); opacity:.52; white-space:nowrap; transition:opacity var(--hl-t-med); }
.hl-marquee:hover .hl-plogo{ opacity:.78; }
.hl-plogo__sep{ display:block; width:3px; height:26px; border-radius:2px; background:var(--hl-paper-3);
  flex:none; }
.hl-plogo__sep:nth-of-type(3n){ background:rgba(207,41,39,.45); height:18px; }
.hl-partners__note{ margin:var(--hl-s-6) 0 0; text-align:center; font-size:var(--hl-fs-micro);
  color:var(--hl-text-muted); }

/* ── 17 · FINAL CTA ─────────────────────────────────────────────────────── */
.hl-final{ position:relative; padding-block:clamp(88px,9vw,140px); overflow:hidden;
  background:linear-gradient(165deg,#0B0E28 0%,#1B2166 44%,#05060F 100%); }
/* This is the one section whose background is part of its artwork rather than a
   band it inherits, so the page builder's theme selection has to be re-asserted
   or the control would be inert here alone. Only the dark family: cta-final.php
   coerces a light selection back to deep navy, because every piece of the
   composition — white title, red glow, converging routes — is drawn for a dark
   ground and recolouring it is not something a select can do safely. */
.hl-final.hl-section--navy{
  background:linear-gradient(178deg, var(--hl-primary-dark,#1b1e45) 0%, var(--hl-primary,#2a2d7c) 100%);
}
.hl-final.hl-section--brand{ background:var(--hl-gradient-brand); }
.hl-final__conv .hl-rte__base{ stroke:rgba(255,255,255,.09); }
.hl-final__conv .hl-rte__amb{ stroke:rgba(144,150,228,.5); stroke-dasharray:54 1800;
  stroke-dashoffset:1854; animation-duration:7s; }
.hl-final__mark{
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  display:flex; align-items:flex-end; gap:clamp(18px,3vw,46px); height:76%; opacity:.13;
}
.hl-final__mark b{ width:clamp(24px,4vw,64px); border-radius:6px 6px 0 0;
  background:linear-gradient(180deg, rgba(144,150,228,.9), transparent 82%); }
.hl-final__mark b:nth-child(1){ height:44% } .hl-final__mark b:nth-child(2){ height:72% }
.hl-final__mark b:nth-child(3){ height:32% } .hl-final__mark b:nth-child(4){ height:100% }
.hl-final__mark b:nth-child(5){ height:86% } .hl-final__mark b:nth-child(6){ height:24% }
.hl-final__mark b:nth-child(7){ height:58% }
.hl-final__mark b.is-red{ background:linear-gradient(180deg, rgba(229,84,78,.95), transparent 82%); }
.hl-final__glow{ position:absolute; left:50%; bottom:-34%; width:70vw; height:min(520px,80%);
  transform:translateX(-50%); border-radius:50%; filter:blur(80px);
  background:radial-gradient(circle, rgba(207,41,39,.28), transparent 66%); }
.hl-final__shell{ position:relative; z-index:1; text-align:center; }
.hl-final__eyebrow{ margin-bottom:var(--hl-s-6); }
.hl-final__title{ font-size:var(--hl-fs-h1); font-weight:800; color:#fff; letter-spacing:-.038em;
  max-width:22ch; margin:0 auto var(--hl-s-8); }
.hl-final__stack{ display:flex; flex-wrap:wrap; justify-content:center; align-items:center; gap:10px 14px;
  margin:0 auto var(--hl-s-10); }
.hl-final__stack span,.hl-final__stack em{
  font:700 clamp(1.02rem,1.6vw,1.32rem)/1 var(--hl-ff-display); letter-spacing:-.025em;
  padding:11px 18px; border-radius:var(--hl-r-pill);
  background:rgba(255,255,255,.055); border:1px solid var(--hl-line-dark-2); color:#fff;
}
.hl-final__stack em{ background:linear-gradient(150deg, rgba(207,41,39,.34), rgba(207,41,39,.10));
  border-color:rgba(229,84,78,.44); color:#fff; }
/* The button row carried a bottom margin AND the chips a top margin — two
   answers to one question, stacking to 72px under the buttons. The chips keep
   theirs and the row stops adding a second, which takes 24px off the band
   (669 -> 645) without moving anything else.

   Measured before and after: the band's own padding is symmetric (129.6 top and
   bottom) and the residual 168-above / 102-below reading is the qualification
   row rendering past the bottom of its shell, not a padding fault. It is
   unchanged by this, and it is not visible — recorded so nobody re-measures it
   and goes looking for a bug that is not there. */
.hl-final__cta{ display:flex; flex-wrap:wrap; gap:14px; justify-content:center; }
.hl-final__chips{ display:flex; flex-wrap:wrap; gap:10px 28px; justify-content:center;
  margin-top:var(--hl-s-10); }
.hl-final__chips li{ display:flex; align-items:center; gap:9px; font-size:var(--hl-fs-xs);
  color:var(--hl-text-light-3); }
.hl-final__chips li::before{ content:""; width:5px; height:5px; border-radius:2px;
  background:var(--hl-red-500); flex:none; }

/* ── 18 · FOOTER ────────────────────────────────────────────────────────── */
.hl-footer{ background:var(--hl-ink-950); padding-top:var(--hl-sec-pad-sm);
  border-top:1px solid var(--hl-line-dark); }
.hl-footer__top{ display:grid; grid-template-columns:minmax(280px,1fr) 1.7fr;
  gap:clamp(36px,5vw,88px); padding-bottom:var(--hl-s-12); }
.hl-footer__about{ margin:var(--hl-s-6) 0 var(--hl-s-8); font-size:var(--hl-fs-sm); color:var(--hl-text-light-3);
  max-width:40ch; line-height:1.7; }
.hl-footer__contact{ display:grid; gap:10px; margin-bottom:var(--hl-s-8); }
.hl-footer__contact li{ display:flex; gap:14px; align-items:baseline; font-size:var(--hl-fs-sm); }
.hl-footer__contact span{ width:52px; flex:none; font:600 var(--hl-fs-micro)/1.6 var(--hl-ff-body);
  letter-spacing:var(--hl-ls-wide); text-transform:uppercase; color:var(--hl-text-light-4); }
.hl-footer__contact a{ color:#fff; border-bottom:1px solid rgba(255,255,255,.24); }
.hl-footer__contact a:hover{ color:var(--hl-red-300); border-color:var(--hl-red-400); }
.hl-footer__contact em{ font-family:var(--hl-ff-mono); font-size:var(--hl-fs-xs); color:var(--hl-text-light-4);
  letter-spacing:.04em; }
.hl-footer__social{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.hl-footer__social a{ width:38px; height:38px; display:grid; place-items:center; border-radius:var(--hl-r-sm);
  border:1px solid var(--hl-line-dark); color:var(--hl-text-light-3);
  transition:background var(--hl-t-fast), color var(--hl-t-fast), border-color var(--hl-t-fast); }
.hl-footer__social a:hover{ background:rgba(255,255,255,.08); color:#fff; border-color:var(--hl-line-dark-2); }
.hl-footer__social svg{ width:17px; height:17px; fill:currentColor; }
.hl-footer__tp{ width:auto !important; padding:0 14px; gap:8px; display:inline-flex !important;
  font:600 var(--hl-fs-xs)/1 var(--hl-ff-display); }
.hl-footer__social .hl-footer__bbb{ display:inline-flex; align-items:center; }
.hl-footer__social .hl-footer__bbb a{ width:auto; height:auto; display:inline-block; border:0; border-radius:0; }
.hl-footer__social .hl-footer__bbb a:hover{ background:none; }
.hl-footer__bbb img{ display:block; height:auto; max-height:96px; width:auto; max-width:100%; }
.hl-tp__starmini{ width:13px; height:13px; background:var(--hl-ok);
  -webkit-mask:var(--hl-star) center/contain no-repeat; mask:var(--hl-star) center/contain no-repeat; }

.hl-footer__cols{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:var(--hl-s-10) var(--hl-s-8); }
.hl-footer__col h2{ font:600 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-white); margin-bottom:var(--hl-s-5); }
.hl-footer__col li{ margin-bottom:11px; }
.hl-footer__col a{ font-size:var(--hl-fs-xs); color:var(--hl-text-light-3); transition:color var(--hl-t-fast); }
.hl-footer__col a:hover{ color:#fff; }

/* ── W · THE FOOTER LEGAL ROW ──────────────────────────────────────────────
   Two disclaimers — the Highline underwriting/pricing/funding statement, and
   the card-network and third-party trademark notice.

   ── THE FIRST DEFECT (fixed earlier) ───────────────────────────────────────
   This element was in the §S fine-print measure list, and it is the two-column
   GRID rather than the prose. `max-width` on a grid container caps the LAYOUT,
   so both columns were squeezed into the first 605px of a 1,192px row and
   631px — over half the footer — sat empty.

   ── THE SECOND DEFECT (fixed here) ─────────────────────────────────────────
   Moving the measure onto the paragraphs let the GRID span the footer, but the
   tracks were `max-content` and each paragraph still carried the same ~86
   character cap. So both columns sized to exactly 434px, `space-between` pinned
   one to each edge, and 324px of the 1,192px row — 27% of it — was dead air in
   the middle. Both edges were flush, which is why it read as deliberate; it was
   not. It was two identical columns holding a 427-character statement and a
   108-character one, the long column wrapping to six lines while the short one
   used two and the space that would have shortened it sat unused between them.

   The tracks are now PROPORTIONAL and sized to the copy they carry, 1.62fr to
   1fr — about 60/36 of the row with a normal column gutter between them, which
   is the composition the rest of the site's two-column rows already use. The
   long disclaimer runs on toward the centre and closes at four lines instead of
   six; the trademark notice keeps a comfortable paragraph rather than a strip.
   Neither edge is ragged and there is no gap wide enough to read as a third
   column.

   The paragraphs no longer carry `--hl-measure-note` (removed from the §S list
   in the same change): the TRACK is the measure here. A cap of 434px inside a
   720px track would have reinstated the dead space one level down, which is
   precisely the defect this rule exists to remove.

   Vertical: the row was 181px (32px padding, six lines, 32px padding). Four
   lines and 24px padding bring it to ~126px. Padding is still on the scale and
   still reads as a band between two rules — the height comes off the wrapping,
   not off the breathing room. Nothing here is a fixed height. */
.hl-footer__disc{ padding:var(--hl-s-6) 0; border-top:1px solid var(--hl-line-dark);
  display:grid; grid-template-columns:minmax(0,1.62fr) minmax(0,1fr);
  align-items:start; gap:var(--hl-s-6) clamp(32px,3.4vw,56px); }

/* Tablet keeps the pair side by side but evens the tracks: below ~1024 the
   1.62fr column stops being long enough to justify the extra width, and 1fr/1fr
   gives the short notice a readable paragraph instead of a column of two-word
   lines. Measured at 900: 55 characters a column; at 768: 66.

   Stacking waits until 640, where a second column would drop under ~50
   characters. Below that the single column fills the content box — no measure
   cap, so there is never a large empty band beside a stacked paragraph. */
@media (max-width:1024px){
  .hl-footer__disc{ grid-template-columns:repeat(2,minmax(0,1fr));
    gap:var(--hl-s-6) var(--hl-s-10); }
}
@media (max-width:640px){
  .hl-footer__disc{ grid-template-columns:1fr; gap:var(--hl-s-5); }
}
.hl-footer__disc p{ margin:0; font-size:var(--hl-fs-micro); line-height:1.75; color:var(--hl-text-light-4); }
.hl-footer__disc em{ font-family:var(--hl-ff-mono); color:var(--hl-text-light-3); }

.hl-footer__bar{ display:flex; align-items:center; justify-content:space-between; gap:var(--hl-s-6);
  flex-wrap:wrap; padding:var(--hl-s-6) 0; border-top:1px solid var(--hl-line-dark); }
.hl-footer__bar p{ margin:0; font-size:var(--hl-fs-xs); color:var(--hl-text-light-4); }
.hl-footer__barlinks{ display:flex; gap:var(--hl-s-6); }
.hl-footer__barlinks a{ font-size:var(--hl-fs-xs); color:var(--hl-text-light-4); }
.hl-footer__barlinks a:hover{ color:#fff; }
.hl-footer__proto{ padding:5px 11px; border-radius:var(--hl-r-xs);
  border:1px dashed rgba(255,255,255,.2); font-family:var(--hl-ff-mono);
  font-size:var(--hl-fs-micro) !important; letter-spacing:.04em; }

/* ── 19 · RESPONSIVE ────────────────────────────────────────────────────── */
@media (max-width:1280px){
  .hl-nav__list{ gap:0 } .hl-nav__link{ padding:10px 11px; font-size:var(--hl-fs-xs) }
  .hl-hrow{ grid-template-columns:repeat(var(--hl-row-md, 3), minmax(0,1fr)) }
  .hl-hcard:nth-child(4),.hl-hcard:nth-child(5){ grid-column:auto }
}

@media (max-width:1120px){
  .hl-header__actions .hl-btn--ghost{ display:none }
  .hl-mega__grid{ grid-template-columns:repeat(3,1fr) }
  .hl-mega__grid--5{ grid-template-columns:repeat(3,1fr) }
  .hl-netgrid{ grid-template-columns:1fr }
  .hl-nstar{ min-height:360px }
  .hl-ncol{ grid-template-columns:repeat(3,1fr) }
  .hl-wprime{ grid-column:1/span 12; grid-row:auto; }
  .hl-wgrid > :nth-child(2){ grid-column:1/span 6; grid-row:auto }
  .hl-wgrid > :nth-child(3){ grid-column:7/span 6; grid-row:auto }
  .hl-wgrid > :nth-child(4){ grid-column:1/span 4; grid-row:auto }
  .hl-wgrid > :nth-child(5){ grid-column:5/span 4; grid-row:auto }
  .hl-wgrid > :nth-child(6){ grid-column:9/span 4; grid-row:auto }
  .hl-revs__grid{ grid-template-columns:1fr 1fr; }
  .hl-tp{ grid-column:1/span 2; flex-direction:row; align-items:center; gap:var(--hl-s-8) }
  .hl-tp__score{ flex:1 } .hl-tp .hl-btn--dark{ margin:0 } .hl-tp__note{ max-width:22ch }
}

@media (max-width:1024px){
  :root{ --hl-nav-h:76px; --hl-logo-h:56px; }
  .hl-nav,.hl-header__actions{ display:none }
  .hl-burger{ display:flex }
  .hl-hero__shell{ grid-template-columns:1fr; gap:var(--hl-s-14) }
  .hl-hero__copy{ max-width:none }
  .hl-eco{ max-width:560px }
  .hl-shead--split{ grid-template-columns:1fr; align-items:start }
  .hl-shead__aside{ max-width:none }
  .hl-psys{ padding:var(--hl-s-8) var(--hl-s-6) 0 }
  .hl-psys__nodes{ grid-template-columns:repeat(4,1fr); gap:var(--hl-s-6) 0 }
  .hl-psys__rail{ display:none }
  .hl-pn{ padding-left:20px; padding-top:0 }
  .hl-pn__dot{ top:3px }
  .hl-psys__zones{ grid-template-columns:1fr 1fr 1fr }
  .hl-pz{ padding:18px 16px 20px }
  .hl-ppanel{ grid-template-columns:1fr; gap:var(--hl-s-8) }
  .hl-ppanel__viz{ order:-1 }
  .hl-hstage{ grid-template-columns:1fr }
  .hl-hstage__art{ min-height:300px; order:-1 }
  .hl-story__about{ grid-template-columns:1fr; gap:var(--hl-s-14) }
  .hl-ind__wrap{ grid-template-columns:1fr }
  .hl-ind__nav{ grid-column:1; grid-row:1; display:flex; overflow-x:auto; gap:6px; padding-bottom:6px;
    scrollbar-width:none }
  .hl-ind__nav::-webkit-scrollbar{ display:none }
  .hl-ind__nav li{ flex:none }
  .hl-itab{ border-left:0; border-bottom:2px solid var(--hl-line-dark); border-radius:var(--hl-r-sm);
    padding:14px 16px; white-space:nowrap }
  .hl-itab.is-active{ border-left:0; border-bottom-color:var(--hl-red-500) }
  .hl-itab__prog{ right:16px; bottom:2px }
  .hl-ind__stage{ grid-column:1; grid-row:2 }
  .hl-ind__aside{ grid-column:1; grid-row:3 }
  .hl-ipanel{ grid-template-columns:1fr; min-height:0 }
  .hl-ipanel__viz{ order:-1; min-height:280px }
  .hl-calcbox{ grid-template-columns:1fr }
  .hl-fund__wrap{ grid-template-columns:1fr; gap:var(--hl-s-12) }
  .hl-footer__top{ grid-template-columns:1fr }
}

@media (max-width:900px){
  .hl-hrow{ grid-template-columns:repeat(var(--hl-row-sm, 2), minmax(0,1fr)) }
  .hl-wprime{ grid-template-columns:1fr }
  .hl-wgrid > :nth-child(n){ grid-column:1/span 12; grid-row:auto }
  .hl-wtile--ind{ flex-direction:column }
  .hl-ncol{ grid-template-columns:1fr }
  .hl-revs__grid{ grid-template-columns:1fr }
  .hl-tp{ grid-column:auto; flex-direction:column; align-items:stretch }
  .hl-tp__note{ max-width:none }
  /* Hide the SUPPORTING METRIC, not the whole aside — the dismiss button lives
     in here too, and hiding its container took it with it. `getComputedStyle`
     still reported `width:26px` while the rect measured 0×0, which is why the
     control looked present and could not be used: at 390, 430 and 768 there was
     no way to close a bar taking 118px of an 844px viewport (audit CH-01). */
  /* `display:contents` rather than `flex`: the aside must stop taking a slot in
     the wrapping row (which added 24px to the bar) while the absolutely
     positioned close button inside it keeps its place. */
  .hl-announce__aside{ display:contents }
  .hl-announce__meta{ display:none }
  /* A 44px tap target here means a 44px reservation on the row as well. */
  .hl-announce{ --hl-announce-close:calc(44px + clamp(.35rem,1.5vw,1rem) + 10px) }
  .hl-announce__close{ min-width:44px; min-height:44px }
  .hl-announce__inner{ min-height:0 }
  .hl-announce__message{ gap:8px 10px; line-height:1.5 }
}

@media (max-width:640px){
  :root{ --hl-gutter:22px; --hl-sec-pad:clamp(60px,11vw,88px); --hl-sec-pad-sm:56px;
         --hl-flow-tight:var(--hl-s-5); --hl-flow:var(--hl-s-6); --hl-flow-loose:var(--hl-s-8); }
  /* The opening value is a deliberate mobile reduction and stays. The CLOSING
     value must not be a number: this rule predates the hero-air contract and
     went on hard-coding 80px below 640px, so on a phone the marketing hero
     closed on 80px while every service and product hero closed on the token's
     64px — GROUP C's "one relationship, several numbers" surviving underneath
     the fix that named it. Measured at 390px before this change: 80px on Home
     against 64px everywhere else. */
  .hl-hero__shell{ padding-block:var(--hl-s-8) var(--hl-hero-air) }
  .hl-hero__cta{ flex-direction:column; align-items:stretch }
  .hl-hero__cta .hl-btn{ width:100% }
  .hl-trust{ gap:10px 18px }
  .hl-rotator{ width:100%; padding:12px 14px }

  /* payment flow → stacked story */
  .hl-eco{ max-width:none; aspect-ratio:auto; height:auto; display:grid; gap:12px;
    grid-template-columns:1fr }
  .hl-eco__routes,.hl-eco__halo,.hl-report{ display:none }
  .hl-ecard{ position:static; width:auto; animation:none }
  .hl-stamp{ position:static; margin-top:12px; opacity:1; transform:none; align-self:flex-start }

  .hl-psys__nodes{ grid-template-columns:repeat(2,1fr) }
  .hl-psys__zones{ grid-template-columns:1fr; gap:0 }
  .hl-pz{ border-right:0; border-top:1px solid var(--hl-line-dark) }
  .hl-pz::before{ left:0; right:0 }
  .hl-pz b{ font-size:1.5rem }
  .hl-ppanel{ padding:var(--hl-s-6) }

  .hl-hstage{ padding:var(--hl-s-6) }
  .hl-hstage__art{ min-height:250px }
  .hl-hlabel{ font-size:var(--hl-fs-micro); padding:6px 10px }
  .hl-hlabel--2,.hl-hlabel--4{ display:none }
  .hl-pslot--xl .hl-dev{ --hl-k:1.1; transform:scale(1.1) }
  .hl-hrow{ grid-template-columns:1fr }
  .hl-hcard .hl-pslot{ min-height:150px }

  .hl-stack{ padding-left:34px }
  .hl-stack__slab--4{ margin-left:30px } .hl-stack__slab--3{ margin-left:20px }
  .hl-stack__slab--2{ margin-left:10px }
  .hl-wprime__viz{ max-width:290px }
  .hl-venn__c{ font-size:var(--hl-fs-micro) }

  .hl-ipanel__viz{ min-height:240px }
  .hl-pslot--lg .hl-dev{ --hl-k:1; transform:scale(1) }
  .hl-ipanel__foot{ flex-direction:column; align-items:flex-start; gap:var(--hl-s-4) }

  .hl-nstar{ min-height:320px; padding:var(--hl-s-6) }
  .hl-nstar__figure b{ font-size:clamp(3.6rem,20vw,5rem) }

  .hl-calcbox__inputs,.hl-calcbox__result{ padding:var(--hl-s-6) }
  .hl-modes{ grid-template-columns:1fr }
  .hl-bigsave__v{ font-size:clamp(2.6rem,14vw,3.4rem) }

  .hl-fchart{ padding:var(--hl-s-5) }
  .hl-fchart__axis{ grid-template-columns:1fr 1fr; gap:8px 12px }
  .hl-fchart__axis span:nth-child(2){ text-align:right }
  .hl-fchart__axis span:nth-child(3){ text-align:left }
  .hl-fund__cta{ flex-direction:column; align-items:stretch }
  .hl-fund__cta .hl-btn{ width:100% }
  .hl-fund__note{ text-align:center }
  .hl-frow{ padding:18px 14px; gap:14px }
  .hl-frow.is-active{ transform:none }

  .hl-final__cta{ flex-direction:column }
  .hl-final__cta .hl-btn{ width:100% }
  .hl-final__stack{ gap:8px }
  .hl-final__stack span,.hl-final__stack em{ font-size:.95rem; padding:9px 14px }
  .hl-final__chips{ flex-direction:column; align-items:center; gap:10px }

  .hl-footer__cols{ grid-template-columns:repeat(2,1fr) }
  .hl-footer__bar{ justify-content:center; text-align:center }
  .hl-dacc__body{ grid-template-columns:1fr }
  .hl-logo--foot{ --hl-logo-h:96px }
}

@media (max-width:400px){
  :root{ --hl-gutter:20px; --hl-ls-wider:.14em; }
  .hl-eyebrow{ font-size:.66rem }
  .hl-pn b{ font-size:var(--hl-fs-xs) }
  .hl-footer__cols{ grid-template-columns:1fr }
  .hl-wprime__viz{ max-width:250px }
}

/* ── 20 · PROMOTIONAL MODAL ─────────────────────────────────────────────── */
/* Uses the same surfaces as the dark chapters (ink gradient + infra field +
   seam accent) so the overlay reads as part of the page, not a bolted-on popup. */
.hl-promo-modal{
  position:fixed; inset:0; z-index:200;
  display:grid; place-items:center; padding:var(--hl-gutter);
}
.hl-promo-modal[hidden]{ display:none; }

.hl-promo-modal__scrim{
  position:absolute; inset:0; background:rgba(4,5,14,.66);
  -webkit-backdrop-filter:blur(7px); backdrop-filter:blur(7px);
  opacity:0; transition:opacity var(--hl-t-med) var(--hl-e-soft);
}
.hl-promo-modal.is-open .hl-promo-modal__scrim{ opacity:1; }

.hl-promo-modal__card{
  position:relative; z-index:1;
  display:grid; grid-template-columns:.82fr 1.18fr;
  width:min(920px,100%); max-height:min(88vh,760px);
  border-radius:var(--hl-r-2xl); overflow:hidden;
  background:linear-gradient(165deg,var(--hl-ink-750) 0%,var(--hl-ink-850) 58%,var(--hl-ink-950) 100%);
  border:1px solid var(--hl-line-dark-2); box-shadow:var(--hl-sh-xl), var(--hl-sh-glass);
  opacity:0; transform:translateY(20px) scale(.975);
  transition:opacity 420ms var(--hl-e-out), transform 480ms var(--hl-e-out);
}
.hl-promo-modal.is-open .hl-promo-modal__card{ opacity:1; transform:none; }
/* the seam family, reused as the card's top edge */
.hl-promo-modal__card::before{
  content:""; position:absolute; left:0; right:0; top:0; height:1px; z-index:4;
  background:linear-gradient(90deg, transparent, rgba(255,255,255,.14) 24%,
    rgba(207,41,39,.75) 50%, rgba(255,255,255,.14) 76%, transparent);
}

.hl-promo-modal__x{
  position:absolute; top:14px; right:14px; z-index:5;
  width:38px; height:38px; display:grid; place-items:center; border-radius:var(--hl-r-sm);
  color:var(--hl-text-light-3); background:rgba(255,255,255,.06);
  border:1px solid var(--hl-line-dark); -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px);
  transition:background var(--hl-t-fast), color var(--hl-t-fast), transform var(--hl-t-fast);
}
.hl-promo-modal__x:hover{ background:rgba(255,255,255,.13); color:#fff; transform:rotate(90deg); }
.hl-promo-modal__x svg{ width:14px; height:14px; stroke:currentColor; stroke-width:1.7; fill:none;
  stroke-linecap:round; }

/* media / image area */
.hl-promo-modal__media{
  position:relative; min-height:0; overflow:hidden; display:grid; place-items:center;
  padding:var(--hl-s-10) var(--hl-s-6);
  border-right:1px solid var(--hl-line-dark);
  background:linear-gradient(180deg,rgba(42,45,124,.20),rgba(4,5,14,.55) 84%);
}
.hl-infra__glow--modal{
  width:130%; aspect-ratio:1/1; left:-28%; top:-26%;
  background:rgba(42,45,124,.34); filter:blur(74px);
}
.hl-promo-modal__slot{ position:relative; z-index:2; max-width:230px; }
.hl-promo-modal__slot .hl-dev{ --hl-k:1; transform:scale(1); }
/* "Make the whole modal clickable" wraps the ARTWORK, not the card — a card
   link would nest the buttons and the close control inside an anchor. The link
   shrink-wraps the slot (the media area is a centred grid), so it adds no box
   of its own and the composition is unchanged when no destination is set. */
.hl-promo-modal__slotlink{ position:relative; z-index:2; display:block; text-decoration:none; color:inherit;
  border-radius:var(--hl-r-sm); }
.hl-promo-modal__slotlink:focus-visible{ outline:2px solid var(--hl-brand-red); outline-offset:6px; }
/* soft ground so the device reads as an object, not a floating outline */
.hl-promo-modal__media::after{
  content:""; position:absolute; z-index:1; left:50%; top:58%;
  width:56%; height:20px; transform:translateX(-50%); border-radius:50%;
  background:radial-gradient(ellipse, rgba(0,0,0,.5), transparent 70%); filter:blur(7px);
}
/* ── E7 · THE PROMOTIONAL MEDIA STAGE ──────────────────────────────────────
   The left half of the modal IS the media. It used to be a navy panel with a
   230px-capped picture centred in it, which read as an image pasted onto a
   background rather than as half of the composition — and when the upload
   carried a baked-in white background, as a white rectangle sitting on navy.

   CSS cannot remove pixels from an upload, and the administrator must not have
   to open Photoshop before using the Modals screen. So the panel is built to
   absorb whatever arrives, at any size, aspect or ground:

     LAYER 1  the same picture, `cover`, blurred and darkened, filling the panel
              edge to edge. Decorative only.
     LAYER 2  the same picture again, `contain`, centred, as large as the panel
              allows. Complete — never cropped.

   `contain` alone would put the picture back in the middle of empty space,
   which is the defect. `cover` alone would crop a promotional image, and on a
   promotion the whole picture is the point. The pair gives a filled panel AND a
   complete image, and it is indifferent to what was uploaded: a small file
   scales up, an 8000px file scales down, portrait and landscape both centre,
   and a white-background upload now sits on a blurred wash of its own white
   rather than against navy.

   One `src`, two elements: the second paints from cache, so the panel costs one
   request. */
.hl-promo-modal__media--photo{
  padding:clamp(16px,2vw,28px);
  /* the picture is the ground now */
  background:none;
}
/* The drawn infrastructure belongs to the CSS silhouette. Over a photograph it
   is two decorative systems competing in one panel. */
.hl-promo-modal__media--photo .hl-infra{ display:none; }
/* Likewise the soft ellipse: it is a ground for a cut-out device, and under a
   contained photograph it reads as a smudge. */
.hl-promo-modal__media--photo::after{ display:none; }

/* LAYER 1 — the ground, and it must actually paint.

   `background-image` rather than an `<img>`: the modal ships with `hidden` on
   it, and a lazy image inside a `display:none` subtree is never in the viewport,
   so the browser defers it forever. The first version of this layer measured
   `naturalWidth === 0` on the rendered page — correctly positioned, correctly
   filtered, painting nothing. A background is not fetched while the subtree is
   display:none either, so the saving is the same, but it cannot get stuck: the
   moment the modal is shown it loads and paints.

   The blur lives here rather than on the media box because a filter on the
   container would blur the foreground and the badge along with it. */
.hl-promo-modal__bg{
  position:absolute; inset:0; z-index:0; pointer-events:none;
  background-image:var(--hl-pm-bg);
  /* `100% 100%`, not `cover`.

     `cover` crops to fill, and on a portrait panel it kept only the horizontal
     middle of the source — which on a product shot is the product. The ground
     became a blur of the dark terminal while the foreground's own margin was
     white, so the two could not meet. Mapping the WHOLE source onto the panel
     instead puts the upload's light and dark regions where the picture's own
     are, and the foreground lands on a ground of roughly its own tone.

     The aspect distortion this implies is real and invisible: the layer is
     behind a 24px blur and exists only as colour. Nothing here is ever read as
     a picture — the foreground is the picture, and it stays `contain`. */
  background-size:100% 100%; background-position:center; background-repeat:no-repeat;
  /* A large blur radius samples past the element's own edge and leaves a soft
     band there; scaling up pushes that band outside the panel, which
     `overflow:hidden` on the media box then clips. */
  transform:scale(1.18);
  /* Barely darkened, and that is the point.

     The ground has to sit at roughly the SAME luminance as the foreground or
     the panel does not read as one composition. Darkened to 42%, then to 72%,
     then to 86%, the measured bands around the picture came out at rgb(30-73)
     against a 255 white foreground — the blurred image was painting, and a hard
     white rectangle still floated on a dark field, which was the original
     complaint. The blur is what integrates the two; the darkening was what kept
     them apart. Whatever is uploaded now sets the panel's own tone: a white
     product shot gives a soft light field, a dark photograph a dark one. */
  filter:blur(64px) saturate(1.1) brightness(1.02);
}
/* A VIGNETTE, NOT A FLAT WASH — and the two darkenings had to be balanced
   against each other.

   The first attempt darkened twice: `brightness(.42)` on the layer AND a flat
   52-74% black wash on top, which multiplies to roughly 15% of the original
   luminance. The blurred picture was then invisible, the panel was just navy
   again, and the upload's baked-in white rectangle sat on it exactly as
   before — the fix rendered as the defect.

   Graded instead: light at the centre where the picture sits, dark at the
   edges where the panel meets the card and the copy. The foreground lands in a
   pool of its own light rather than on a dark field, which is what makes a
   white-background upload read as a mounted product shot instead of a pasted
   rectangle — and the panel still ends dark, so the card does not split into a
   bright half and a dark half. */
.hl-promo-modal__media--photo::before{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:
    /* Two jobs only, and neither of them is "make the panel dark".
       1. Hand off to the copy column, so the card does not end at a hard line
          between two unrelated boxes — the wash is on the divider edge and
          nowhere else.
       2. Tie the panel to the brand with a navy breath, low enough that the
          uploaded imagery still sets the tone.
       The heavy centre vignette that used to be here is gone: it was darkening
       exactly the area the picture needed to blend into. */
    linear-gradient(90deg, transparent 56%, rgba(4,5,14,.26) 80%, rgba(4,5,14,.74) 100%),
    linear-gradient(160deg, rgba(42,45,124,.12), transparent 66%),
    radial-gradient(150% 120% at 50% 44%, transparent 62%, rgba(4,5,14,.26) 100%);
}

/* LAYER 2 — the complete picture, in a box that is ALWAYS the panel.

   The foreground is positioned rather than flowed, and that is load-bearing.
   `.hl-pslot` is a grid whose artwork row is `1fr`, so in normal flow its
   height is derived from its content — and a percentage height resolves
   against a parent's DEFINITE height or not at all. Given `height:100%` in
   flow, the image fell back to its intrinsic ratio at full width: the 600x1600
   portrait test rendered 344x917 inside a 230px panel, four times the height of
   the box it was supposed to fit.

   `inset` gives the box a definite width AND height taken from the panel, so
   `object-fit:contain` finally has something to contain against, and the
   scaling becomes automatic in both directions — a 24x18 upload scales up to
   the same box a 6000x4000 one scales down to. The inset is the panel's
   padding, which is why the panel itself no longer carries any. */
.hl-promo-modal__media--photo{ padding:0; }
.hl-promo-modal__media--photo > .hl-promo-modal__slot,
.hl-promo-modal__media--photo > .hl-promo-modal__slotlink{
  position:absolute; inset:clamp(16px,2vw,28px); z-index:2;
  width:auto; height:auto; max-width:none;
}
/* When a destination is set the link is the positioned box and the slot fills
   it, so the two never stack two insets on top of each other. */
.hl-promo-modal__media--photo > .hl-promo-modal__slotlink > .hl-promo-modal__slot{
  position:absolute; inset:0; width:100%; height:100%; max-width:none;
}
/* `minmax(0,1fr)`, not `1fr` — and `min-height:0` on the picture.

   A `1fr` track carries an implicit automatic minimum of its content, so the
   row refused to be shorter than the image's intrinsic height. On a wide
   viewport that never showed, because the panel was taller than the picture
   anyway; at 390 the 800x750 upload wanted 322px inside a 205px box and got it,
   overflowing the panel it had just been given a definite height for. Both
   halves are needed: the track has to be allowed to shrink, and the item has to
   stop demanding its own height. The same pairing is documented on the product
   lightbox for the same reason. */
.hl-promo-modal__media--photo .hl-promo-modal__slot{
  grid-template-rows:minmax(0,1fr);
  place-items:center;
}
/* THE BOX HAS TO HUG THE PICTURE, and the fit is computed, not guessed.

   With `width:100%;height:100%;object-fit:contain` the element box was the whole
   panel and the picture painted somewhere inside it — so anything applied to the
   ELEMENT (a mask, a radius, an outline) landed on the panel's edges rather than
   on the picture's, tens of pixels away from the thing it was meant to touch.

   `width:10000px` with both maxima looked like the answer and is not: the
   ratio-preserving path in the replaced-element rules only runs when width is
   `auto`, so when `max-height` was the binding constraint the height clamped and
   the width stayed — measured at 390px, a 800x750 upload came out 344x205 in a
   box whose contain fit is 219x205. It happened to be right at 1024 and 1440
   only because width was the limiting dimension there.

   The contain fit is `min(box width, box height x ratio)`, and container query
   units make that expressible: `100cqh` is the slot's own height, and the ratio
   arrives from the Media Library on the panel. Both dimensions then follow from
   one calculation, the box is the picture, and a 24x18 upload still scales up
   because nothing caps the result below the box.

   NO DROP SHADOW, and no border, radius or frame. `drop-shadow` follows the
   image's alpha, and these uploads mostly have none, so on a white-background
   asset it traced the white rectangle and drew a card shadow around it — the
   "shadowed white container" this panel exists to stop looking like. */
.hl-promo-modal__media--photo .hl-promo-modal__slot{ container-type:size; }
.hl-promo-modal__media--photo .hl-promo-modal__slot img{
  width:min(100%, calc(100cqh * var(--hl-pm-ar, 9999))); height:auto;
  max-width:100%; max-height:100%;
  min-width:0; min-height:0;
  object-fit:contain; object-position:center;

  /* The last few per cent of the picture dissolve into the ground.

     A promotional upload is usually an opaque rectangle, and an opaque
     rectangle laid on ANY ground that is not its own colour shows an edge —
     which is what "a white rectangle floating in the panel" is. Softening the
     outermost band lets the picture end in the ground instead of against it,
     and it works whatever was uploaded: a white margin dissolves into a light
     ground, a dark photograph into a dark one.

     This is a fade, not a crop: nothing is cut off and the image is complete.
     The falloff is deliberately tight — the outer ~5%, which on a promotional
     asset is its margin — so nothing that carries meaning is dimmed. */
  -webkit-mask-image:
    linear-gradient(to right,  transparent 0, #000 5%, #000 95%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 5%, #000 95%, transparent 100%);
          mask-image:
    linear-gradient(to right,  transparent 0, #000 5%, #000 95%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 5%, #000 95%, transparent 100%);
  -webkit-mask-composite:source-in;
          mask-composite:intersect;
}

.hl-promo-modal__badge{
  position:absolute; z-index:3; top:18px; left:18px;
  padding:5px 11px; border-radius:var(--hl-r-xs);
  background:rgba(207,41,39,.18); border:1px solid rgba(207,41,39,.42); color:var(--hl-red-300);
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide); text-transform:uppercase;
}
/* The tinted-red badge is legible on navy and can be anything on an arbitrary
   upload — a light photograph would leave light-red text on a light ground. Over
   the media stage it keeps its shape and takes a dark backing of its own, so its
   contrast is a property of the component rather than of what was uploaded. */
.hl-promo-modal__media--photo .hl-promo-modal__badge{
  background:rgba(4,5,14,.74); border-color:rgba(255,255,255,.26); color:#fff;
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px);
}

/* copy area */
/* min-height:0 is what lets the copy column scroll inside a capped-height card
   instead of overflowing it and being clipped. */
.hl-promo-modal__body{
  position:relative; min-height:0; overflow-y:auto; overscroll-behavior:contain;
  padding:clamp(24px,2.2vw,34px) clamp(24px,2.4vw,38px);
  display:flex; flex-direction:column;
}
.hl-promo-modal__body .hl-eyebrow{ margin-bottom:var(--hl-s-3); }
.hl-promo-modal__title{
  margin:0 0 var(--hl-s-3); color:#fff;
  font:800 clamp(1.42rem,2vw,1.82rem)/1.14 var(--hl-ff-display); letter-spacing:var(--hl-ls-tight);
}
.hl-promo-modal__title em{ font-style:normal; color:var(--hl-red-400); }
.hl-promo-modal__copy{ margin:0 0 var(--hl-s-4); font-size:var(--hl-fs-sm); line-height:1.58;
  color:var(--hl-text-light-2); }
.hl-promo-modal__pts{ display:grid; gap:1px; margin:0 0 var(--hl-s-5); }
.hl-promo-modal__pts li{ position:relative; padding:8px 0 8px 20px; border-top:1px solid var(--hl-line-dark);
  font-size:var(--hl-fs-xs); color:var(--hl-text-light-3); }
.hl-promo-modal__pts li:last-child{ border-bottom:1px solid var(--hl-line-dark); }
.hl-promo-modal__pts li::before{ content:""; position:absolute; left:0; top:14px; width:6px; height:6px;
  border-radius:2px; background:var(--hl-red-500); }

.hl-promo-modal__acts{ display:flex; align-items:center; flex-wrap:wrap; gap:var(--hl-s-5);
  margin-top:auto; }
.hl-promo-modal__alt{
  font-size:var(--hl-fs-sm); font-weight:600; color:var(--hl-text-light-2);
  border-bottom:1px solid rgba(255,255,255,.26); padding-bottom:2px;
  transition:color var(--hl-t-fast), border-color var(--hl-t-fast);
}
.hl-promo-modal__alt:hover{ color:#fff; border-color:var(--hl-red-400); }
.hl-promo-modal__fine{ margin:var(--hl-s-4) 0 0; padding-top:var(--hl-s-3);
  border-top:1px solid var(--hl-line-dark);
  font-size:var(--hl-fs-micro); line-height:1.55; color:var(--hl-text-light-4); }

/* Mobile: the media area becomes a short banner so the headline, CTA and the
   estimate disclaimer all stay above the fold on a phone-height viewport. */
@media (max-width:860px){
  .hl-promo-modal{ padding:12px; }
  .hl-promo-modal__card{
    grid-template-columns:1fr; grid-template-rows:auto 1fr;
    width:min(440px,100%); max-height:calc(100vh - 24px); overflow-y:auto;
    scrollbar-width:thin; scrollbar-color:rgba(255,255,255,.22) transparent;
  }
  .hl-promo-modal__card::-webkit-scrollbar{ width:6px; }
  .hl-promo-modal__card::-webkit-scrollbar-thumb{ background:rgba(255,255,255,.22); border-radius:3px; }
  .hl-promo-modal__media{
    height:116px; padding:0; border-right:0; border-bottom:1px solid var(--hl-line-dark);
    align-content:center;
  }
  .hl-promo-modal__media::after{ top:52%; width:34%; }
  /* transform-scaled devices still reserve full layout space, so the negative
     margin claws it back and keeps the banner at its declared height */
  .hl-promo-modal__slot{ max-width:130px; gap:7px; }
  .hl-promo-modal__slot .hl-dev{ --hl-k:.46; transform:scale(.46); margin-block:-44px; }

  /* 116px is the right strip for a 46%-scaled silhouette and far too short for
     a photograph. The stage gets a band of its own instead — an aspect ratio so
     it is proportionate to the card's width, and a viewport cap so a tall
     portrait upload can never push the heading, the CTA and the terms off the
     bottom of a phone. Between them the picture is always inside one screen. */
  .hl-promo-modal__media--photo{
    height:auto; aspect-ratio:16/10; min-height:148px; max-height:32vh;
    padding:0; align-content:stretch;
  }
  .hl-promo-modal__media--photo > .hl-promo-modal__slot,
  .hl-promo-modal__media--photo > .hl-promo-modal__slotlink{ inset:12px; }
  .hl-promo-modal__media--photo .hl-promo-modal__slot{ max-width:none; gap:0; }
  .hl-promo-modal__bg{ transform:scale(1.22); filter:blur(16px) saturate(1.08) brightness(.98); }

  .hl-promo-modal__body{ overflow:visible; padding:var(--hl-s-5) var(--hl-s-5) 18px; }
  .hl-promo-modal__body .hl-eyebrow{ margin-bottom:var(--hl-s-2); }
  .hl-promo-modal__title{ font-size:1.36rem; margin-bottom:var(--hl-s-2); }
  .hl-promo-modal__copy{ font-size:.815rem; line-height:1.52; margin-bottom:var(--hl-s-2); }
  /* points become chips: same three facts, two lines instead of five */
  .hl-promo-modal__pts{ display:flex; flex-wrap:wrap; gap:6px; margin-bottom:var(--hl-s-4); }
  .hl-promo-modal__pts li{ padding:5px 9px; border:1px solid var(--hl-line-dark-2); border-radius:var(--hl-r-xs);
    background:rgba(255,255,255,.045); font-size:var(--hl-fs-micro); color:var(--hl-text-light-2); }
  .hl-promo-modal__pts li:last-child{ border-bottom:1px solid var(--hl-line-dark-2); }
  .hl-promo-modal__pts li::before{ display:none; }

  .hl-promo-modal__acts{ flex-direction:column; align-items:stretch; gap:10px; }
  .hl-promo-modal__acts .hl-btn{ width:100%; justify-content:center; }
  .hl-promo-modal__alt{ text-align:center; align-self:center; }
  .hl-promo-modal__fine{ margin-top:var(--hl-s-3); padding-top:var(--hl-s-2); font-size:.655rem; }

  .hl-promo-modal__x{ top:10px; right:10px; width:34px; height:34px; }
  .hl-promo-modal__badge{ top:12px; left:12px; }
}
@media (max-width:400px){
  .hl-promo-modal{ padding:10px; }
  .hl-promo-modal__card{ max-height:calc(100vh - 20px); }
  .hl-promo-modal__title{ font-size:1.3rem; }
}


/* ── D · LOADER ───────────────────────────────────────────────────────────
   ONE loader. `partials/loader.php` + `modules/loader.js` remain the single
   implementation — this is the approved preloader's *treatment* applied to
   them, not a second system.

   The safety contract is unchanged and is what makes a stuck loader
   impossible: the overlay ships `hidden`, only loader.js reveals it, a hard
   failsafe timeout dismisses it whatever happens, `transitionend` AND a
   timeout both remove the node, and reduced motion skips it entirely. */
.hl-loader{
  position:fixed; inset:0; z-index:300; display:grid; place-items:center;
  background:linear-gradient(165deg,var(--hl-ink-750) 0%,var(--hl-ink-900) 48%,var(--hl-ink-950) 100%);
  transition:opacity 460ms var(--hl-e-out), visibility 460ms;
}
/* Must be explicit: a class-level `display:grid` outranks the UA `[hidden]`. */
.hl-loader[hidden]{ display:none; }
.hl-loader.is-leaving{ opacity:0; visibility:hidden; pointer-events:none; }

/* the seam family again, as the overlay's closing edge */
.hl-loader::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:1px; z-index:3;
  background:linear-gradient(90deg, transparent, rgba(255,255,255,.12) 26%,
    rgba(207,41,39,.6) 50%, rgba(255,255,255,.12) 74%, transparent);
  opacity:0; animation:hls-preSeam 900ms var(--hl-e-out) 260ms forwards;
}
@keyframes hls-preSeam{ to{ opacity:1 } }

.hl-infra__glow--pre{
  width:min(720px,86vw); aspect-ratio:1/1; left:50%; top:50%;
  transform:translate(-50%,-50%); background:rgba(42,45,124,.55); filter:blur(90px);
}

.hl-loader__inner{
  position:relative; z-index:2; display:grid; justify-items:center; gap:24px;
  transition:transform 460ms var(--hl-e-out), opacity 320ms var(--hl-e-out);
}
.hl-loader.is-leaving .hl-loader__inner{ transform:translateY(-10px) scale(.96); opacity:0; }

.hl-loader__mark{
  width:clamp(64px,7.6vw,98px); height:auto; overflow:visible;
  filter:drop-shadow(0 20px 44px rgba(0,0,0,.6));
}
/* The skyline builds left to right, then a brand-red signal sweeps up through
   it — the same "value travelling through the system" idea as the routes. */
.hl-loader__bar{
  fill:#fff; transform-box:fill-box; transform-origin:bottom;
  transform:scaleY(0); opacity:0;
  animation:hls-preRise 620ms var(--hl-e-out) forwards;
  animation-delay:calc(var(--hl-i,0) * 95ms);
}
@keyframes hls-preRise{ to{ transform:scaleY(1); opacity:1 } }

.hl-loader__fill-rect{
  fill:var(--hl-red-500); transform-box:fill-box; transform-origin:bottom;
  transform:scaleY(0);
  animation:hls-preFill 1.9s var(--hl-e-inout) 560ms infinite;
}
@keyframes hls-preFill{
  0%{ transform:scaleY(0); opacity:.95 }
  52%{ transform:scaleY(1); opacity:.95 }
  100%{ transform:scaleY(1); opacity:0 }
}

.hl-loader__label{
  margin:0; font:600 var(--hl-fs-micro)/1 var(--hl-ff-body);
  letter-spacing:var(--hl-ls-wider); text-transform:uppercase; color:var(--hl-text-light-4);
  opacity:0; animation:hls-preFade 520ms var(--hl-e-out) 380ms forwards;
}
@keyframes hls-preFade{ to{ opacity:1 } }

.hl-loader__track{
  position:relative; width:min(190px,44vw); height:2px; border-radius:2px;
  background:rgba(255,255,255,.09); overflow:hidden;
  opacity:0; animation:hls-preFade 520ms var(--hl-e-out) 440ms forwards;
}
.hl-loader__track i{
  position:absolute; left:0; top:0; bottom:0; width:0; border-radius:2px;
  background:linear-gradient(90deg, rgba(255,255,255,.28), var(--hl-red-500) 72%);
  animation:hls-preTrack 2.1s var(--hl-e-out) 460ms forwards;
}
@keyframes hls-preTrack{ 0%{ width:0 } 60%{ width:64% } 100%{ width:92% } }
/* the bar always completes on exit, however early the dismissal happens */
.hl-loader.is-leaving .hl-loader__track i{ animation:none; width:100%; transition:width 260ms var(--hl-e-out); }

@media (max-width:600px){
  .hl-loader__inner{ gap:20px; }
  .hl-loader__mark{ width:62px; }
}

/* ── E · PRODUCTION BRIDGE ────────────────────────────────────────────────
   Classes the renderer emits that the prototype had no equivalent for, plus
   aliases from the older component vocabulary onto the approved treatments.
   Everything here exists so ONE design system serves both the ported homepage
   compositions and the generic CMS blocks. */

/* E1 · the decoration layer emitted by section_decoration() ---------------- */
.hl-section{ position:relative; }
.hl-section > .hl-container,
.hl-section > .hl-shell{ position:relative; z-index:1; }

.hl-infra__media{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.hl-infra__overlay{ position:absolute; inset:0; }
.hl-infra__overlay--dark{ background:linear-gradient(180deg, rgba(4,5,14,.55), rgba(4,5,14,.82)); }
.hl-infra__overlay--light{ background:linear-gradient(180deg, rgba(255,255,255,.62), rgba(255,255,255,.86)); }
.hl-infra__overlay--brand{ background:linear-gradient(150deg, rgba(42,45,124,.72), rgba(4,5,14,.88)); }

/* Light chapters carry the same grid in brand navy rather than white. */
.hl-section--light .hl-infra__grid,
.hl-section--alt .hl-infra__grid{
  background-image:
    linear-gradient(to right, rgba(42,45,124,.055) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(42,45,124,.055) 1px, transparent 1px);
  background-size:72px 72px;
}
.hl-section--light .hl-infra__glow,
.hl-section--alt .hl-infra__glow{ opacity:.5; }

/* `.hl-route` / `.hl-signal` are what section_decoration() emits; they are the
   route family under the names the renderer uses. pathLength="300" in the
   markup normalises every path, so one dash setting fits any shape. */
.hl-route{ stroke:rgba(255,255,255,.10); stroke-width:1.2; fill:none; }
.hl-route--dim{ stroke:rgba(255,255,255,.06); stroke-dasharray:3 6; }
.hl-section--light .hl-route,
.hl-section--alt .hl-route{ stroke:rgba(42,45,124,.14); }

.hl-signal{
  stroke:rgba(144,150,228,.75); stroke-width:1.6; fill:none; stroke-linecap:round;
  stroke-dasharray:26 300; stroke-dashoffset:326;
  animation:hls-signalFlow 4.6s var(--hl-e-inout) infinite;
  animation-delay:var(--hl-signal-delay, 0s);
}
.hl-signal--slow{ animation-duration:9s; stroke-dasharray:40 300; stroke-dashoffset:340; }
.hl-section--light .hl-signal,
.hl-section--alt .hl-signal{ stroke:rgba(42,45,124,.55); }
@keyframes hls-signalFlow{ 0%{ stroke-dashoffset:326 } 62%,100%{ stroke-dashoffset:0 } }

/* E2 · product slots on light chapters ------------------------------------ */
.hl-section--light .hl-pslot__ph,
.hl-section--alt .hl-pslot__ph{ --hl-ph-name:var(--hl-text-dark); --hl-ph-note:var(--hl-text-muted); }

/* E3 · button vocabulary --------------------------------------------------
   The older blocks call the accent button `--accent` and the outlined one
   `--outline`. Rather than rewrite every view, they alias onto the approved
   treatments, so one button design serves the whole site. */
.hl-btn--accent{
  color:#fff; background:linear-gradient(170deg,var(--hl-red-400),var(--hl-red-600));
  box-shadow:var(--hl-sh-red), inset 0 1px 0 rgba(255,255,255,.28);
}
.hl-btn--accent:hover{ box-shadow:0 16px 38px -10px rgba(207,41,39,.65), inset 0 1px 0 rgba(255,255,255,.3); transform:translateY(-2px); }
.hl-btn--outline{
  color:#fff; border:1px solid var(--hl-line-dark-2); background:rgba(255,255,255,.03);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
}
.hl-btn--outline:hover{ background:rgba(255,255,255,.09); border-color:rgba(255,255,255,.3); transform:translateY(-2px); }
/* On a light chapter the outlined button needs the opposite treatment. */
.hl-section--light .hl-btn--outline,
.hl-section--alt .hl-btn--outline{ color:var(--hl-text-dark); border-color:var(--hl-line-2); background:#fff; }
.hl-section--light .hl-btn--outline:hover,
.hl-section--alt .hl-btn--outline:hover{ background:var(--hl-paper); border-color:var(--hl-brand-navy); }
.hl-btn--secondary{ color:var(--hl-ink-800); background:#fff; box-shadow:0 10px 24px -12px rgba(0,0,0,.6); }

/* E4 · responsive visibility, emitted by PageRenderer only when a block is
   genuinely hidden at one breakpoint. */
@media (max-width:767px){ .hl-hide-mobile{ display:none !important; } }
@media (min-width:768px){ .hl-hide-desktop{ display:none !important; } }

/* E5 · a dark opening hero sits UNDER the transparent header -------------- */
/* Without this the transparent header renders as a white bar containing a
   white logo. The header's height is ADDED to the section's own top spacing
   rather than replacing it, or the eyebrow ends up pinned under the nav. */
.hl-heroblock--under-header{
  margin-top:calc(var(--hl-header-height, 4.5rem) * -1);
  padding-top:calc(var(--hl-header-height, 4.5rem) + var(--hl-space-xl, 3rem));
}

/* E6 · reduced motion -----------------------------------------------------
   The environment stays; only the movement stops. A visitor who asks for less
   motion still gets the designed page, not a stripped one. */
@media (prefers-reduced-motion:reduce){
  .hl-loader{ display:none !important; }
  html{ scroll-behavior:auto; }
  .hl-signal, .hl-rte__amb, .hl-rte__flow{ animation:none !important; stroke-dashoffset:0; opacity:.55; }
  .hl-stamp{ opacity:1; transform:none; }
  .hl-promo-modal.is-open .hl-promo-modal__card{ opacity:1; transform:none; }
  .hl-marquee__track{ animation:none; }
}

/* E7 · production markup the prototype did not have ----------------------- */
/* The CMS header renders its mega panel inside the nav item (that is where the
   accessibility relationship lives), while the approved panel is full-width.
   Making the mega item static resolves the panel against the header instead of
   against the list item — same markup, approved geometry. */
.hl-nav__item--mega{ position:static; }
.hl-mega__grid{ grid-template-columns:repeat(var(--hl-mega-cols,4), minmax(0,1fr)); }
.hl-mega__shell--full{ grid-template-columns:minmax(0,1fr); }

/* A header that is NOT over a hero still carries the approved dark bar, so the
   white lockup and white links stay legible on any page. */
.hl-header:not(.hl-header--over-hero){
  background:rgba(7,9,25,.96);
  border-bottom-color:var(--hl-line-dark);
}

/* The drawer accordion is a real button (the prototype used <details>), so it
   takes the summary treatment. */
.hl-dacc > .hl-mobile-nav__toggle{
  display:flex; align-items:center; justify-content:space-between; width:100%;
  padding:18px 0; font:600 1.05rem/1 var(--hl-ff-display); color:#fff;
  letter-spacing:-.015em; text-align:left;
}
.hl-dacc > .hl-mobile-nav__toggle[aria-expanded="true"] .hl-caret{ transform:rotate(-135deg) translateY(-1px); }
.hl-dacc__body[hidden]{ display:none; }

/* About and Why are separate CMS blocks in production — each can be reordered,
   disabled or dropped on its own — so the padding that joined them in the
   prototype moves onto the sections instead of the inner wrappers. */
.hl-hero--highline{ padding-bottom:0; }
.hl-story{ padding-block:var(--hl-sec-pad-sm); background:linear-gradient(180deg,var(--hl-paper) 0%,#fff 55%,#fff 100%); }
.hl-story__about{ padding-bottom:0; }
.hl-story__cta{ margin-top:var(--hl-s-8); }
.hl-why-sec{
  position:relative; overflow:hidden; padding-block:0 var(--hl-sec-pad);
  background:linear-gradient(180deg,#fff 0%,#fff 60%,var(--hl-paper) 100%);
}
.hl-why{ border-top:1px solid var(--hl-line); padding-top:var(--hl-sec-pad-sm); }

/* Funding carries its own disclaimer; it is content, not decoration. */
.hl-fund__disclaimer{
  margin:var(--hl-s-6) 0 0; font-size:var(--hl-fs-micro); line-height:1.6;
  color:var(--hl-text-light-4); max-width:60ch;
}

/* The partner rail's speed is a CMS setting, so the duration is a variable. */
.hl-marquee__track{ animation-duration:var(--hl-marquee-speed,38s); }
.hl-marquee--static{ mask-image:none; -webkit-mask-image:none; justify-content:center; flex-wrap:wrap; }
.hl-marquee--static .hl-marquee__track{ animation:none; flex-wrap:wrap; justify-content:center; }
.hl-plogo__img{ max-height:34px; width:auto; opacity:.72; filter:grayscale(1); flex:none; }
.hl-marquee:hover .hl-plogo__img{ opacity:1; filter:none; }

/* Reviews are real quotes in production; the prototype only had reserved slots. */
.hl-rev__text{
  margin:var(--hl-s-5) 0 auto; padding:0; border:0; font-size:var(--hl-fs-body);
  line-height:1.65; color:var(--hl-text-body);
}
.hl-rev__stars{ display:flex; gap:4px; }
.hl-rev__stars b{
  width:16px; height:16px; background:var(--hl-brand-red);
  -webkit-mask:var(--hl-star) center/contain no-repeat; mask:var(--hl-star) center/contain no-repeat;
}
.hl-final__lede{
  max-width:56ch; margin:0 auto var(--hl-s-10); font-size:var(--hl-fs-lede);
  color:var(--hl-text-light-2);
}

/* Screen-reader-only text inside the approved burger. */
.hl-burger .hl-sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

/* E8 · grid columns that cannot be forced open ---------------------------
   A `1fr` track floors at min-content, so a wide child (the hardware lead's
   button + financing note sitting on one row) can push a column past the
   viewport, where the section's own overflow:hidden silently clips it. The
   fix is minmax(0,1fr) plus min-width:0 on the children — the same defect and
   the same fix as the industry prototype's stacked panels. */
.hl-shead--split{ grid-template-columns:minmax(0,1.12fr) minmax(0,.88fr); }
.hl-hw .hl-shead--split{ grid-template-columns:minmax(0,1fr) minmax(0,1fr); }
.hl-shead--split > *{ min-width:0; }
.hl-hw__lead, .hl-hw__leadcta{ min-width:0; }
.hl-finnote{ max-width:100%; }

@media (max-width:1024px){
  .hl-shead--split,
  .hl-hw .hl-shead--split{ grid-template-columns:minmax(0,1fr); }
}
@media (max-width:640px){
  /* On a phone the button and the note stack rather than competing for a row. */
  .hl-hw__leadcta{ flex-direction:column; align-items:stretch; }
  .hl-hw__leadcta .hl-btn{ width:100%; }
  .hl-finnote{ max-width:none; }
}

/* E9 · the mega panel is a full-bleed band, not a floating card -----------
   The approved panel spans the viewport under the header. Production's
   `.hl-header__inner` is `position: relative` (it used to be the panel's
   positioning context), which cropped the band to the 1280px shell and
   inset it by the gutter. The header itself is the context now — it is
   `position: sticky`, so it already establishes one. */
.hl-header__inner{ position:static; }

/* The open-item marker moves from the ITEM to the LINK.

   The approved design draws a red bar under the open nav item. In the
   prototype that pseudo-element sits on the item, which is `position:
   relative`; here the item must be `position: static` so the panel can span
   the header, which would stretch the bar across the whole viewport. The link
   carries it instead — same geometry, because the bar is inset by exactly the
   link's horizontal padding — and the older accent underline is replaced
   rather than left to compete with it. */
.hl-nav__item.is-open::after{ content:none; }
.hl-nav__link{ position:relative; }
.hl-nav__link::after{
  content:""; position:absolute; left:0; right:0; bottom:-6px; height:2px;
  border-radius:2px; background:var(--hl-red-500); opacity:0; transform:none;
  transition:opacity var(--hl-t-med) var(--hl-e-out);
}
.hl-nav__item.is-open > .hl-nav__link::after{ opacity:1; }

/* A link-style button is text with a rule under it — production's base button
   would otherwise give it a filled surface. */
.hl-btn--link,
.hl-btn--link:hover{
  background:none; border:0; box-shadow:none;
  --hl-btn-bg:transparent; --hl-btn-border:transparent;
}

/* ── F · SERVICE LAYER (inner pages) ──────────────────────────────────────
   SOURCE OF TRUTH: public/prototype/service/service.css (approved).
   Ported by the same rules as section C — `.foo` → `.hl-foo`, `--foo` →
   `--hl-foo`, `@keyframes foo` → `hls-foo`, `is-*`/`has-*` unchanged — with
   four families renamed onto the production component that already does the
   job, so there is one component rather than two:

     prototype `.hcard` (hardware insert) → `.hl-hcard`      (section 09's card)
     prototype `.fitem`                   → `.hl-faq__item`   (a <details>)
     prototype `.fitem__q button`         → `.hl-faq__question` (a <summary>)
     prototype `.fitem__a`                → `.hl-faq__answer`

   The prototype loads homepage/styles.css first and adds only what an inner
   page needs; the same holds here — everything above this line still applies,
   and nothing is duplicated.

     F0 · route family (short-path variant)
     F1 · wayfinding (breadcrumb, current-branch)
     F2 · service hero + acceptance diagram
     F3 · page rail
     F4 · inner section head
     F5 · acceptance switchboard
     F6 · process track
     F7 · compact industries
     F8 · hardware insert
     F9 · steps chapter
     F10 · why — feature panel + rows
     F11 · FAQ chapter
     F12 · responsive
     F13 · reduced motion                                                    */

:root{ --hl-rail-h:58px; }

/* The sticky rail sits under the sticky header, so an anchor jump has to clear
   both. Only on a page that actually has a rail — :has() keeps the default
   (header only) everywhere else instead of reserving space for nothing. */
html:has(.hl-rail){ scroll-padding-top:calc(var(--hl-nav-h) + var(--hl-rail-h) + 20px); }

/* Off-screen holder for the gradient defs a page's diagrams share. */
.hl-svgdefs{ position:absolute; width:0; height:0; overflow:hidden; }

/* ── F0 · ROUTE FAMILY (short-path variant) ─────────────────────────────── */
/* `.hl-rte__amb` / `.hl-rte__flow` dash values are tuned for very long ambient
   section routes and read as almost empty on a short diagram path. Diagram
   routes get their own pair — same colours, same idea, different arithmetic.
   Every path carries pathLength="300", so one dash setting fits every shape
   and all signals travel at the same speed regardless of the path's length. */
.hl-sroute{ stroke:rgba(255,255,255,.14); stroke-width:1.4; fill:none; }
.hl-sroute--dim{ stroke:rgba(255,255,255,.07); stroke-dasharray:3 5; }
.hl-infra--light .hl-sroute,
.hl-acc .hl-sroute, .hl-binds .hl-sroute, .hl-why2 .hl-sroute{ stroke:rgba(42,45,124,.16); }

.hl-spulse{
  stroke:url(#hl-sgrad); stroke-width:2.4; fill:none; stroke-linecap:round;
  stroke-dasharray:26 300; stroke-dashoffset:326;
  animation:hls-spulse 4.4s var(--hl-e-inout) infinite; animation-delay:var(--hl-d,0s);
  filter:drop-shadow(0 0 6px rgba(122,130,255,.6));
}
.hl-why2 .hl-spulse{ stroke:url(#hl-sgradl); filter:none; }
@keyframes hls-spulse{ 0%{ stroke-dashoffset:326 } 62%,100%{ stroke-dashoffset:0 } }
@keyframes hls-spulseSlow{ 0%{ stroke-dashoffset:340 } 62%,100%{ stroke-dashoffset:0 } }
.hl-spulse--slow{ animation-name:hls-spulseSlow; animation-duration:7s;
  stroke-dasharray:40 300; stroke-dashoffset:340; }

/* ── F1 · WAYFINDING ────────────────────────────────────────────────────── */
.hl-crumb{ margin-bottom:var(--hl-s-6); }
.hl-crumb ol{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin:0; padding:0;
  list-style:none; font:500 var(--hl-fs-micro)/1 var(--hl-ff-body);
  letter-spacing:.1em; text-transform:uppercase; }
.hl-crumb li{ display:flex; align-items:center; gap:8px; color:var(--hl-text-light-4); }
.hl-crumb li + li::before{ content:""; width:4px; height:4px; border-radius:50%;
  background:currentColor; opacity:.5; }
.hl-crumb a{ color:var(--hl-text-light-3); transition:color var(--hl-t-fast); }
.hl-crumb a:hover{ color:#fff; }
.hl-crumb [aria-current="page"]{ color:var(--hl-red-300); }

/* Current-branch markers. An inner page should always say where it sits.
   Production carries `is-current` on the nav LINK (bridge E9), so the marker
   hangs off the link rather than off the item. */
.hl-nav__link.is-current{ color:#fff; }
.hl-nav__item:not(.is-open) > .hl-nav__link.is-current::after{
  opacity:1; background:linear-gradient(90deg,var(--hl-red-500),rgba(207,41,39,0));
}
.hl-mega__card.is-current{ border-color:rgba(207,41,39,.45); background:rgba(207,41,39,.07); }
.hl-footer a[aria-current="page"],
.hl-dacc__body a[aria-current="page"]{ color:#fff; }

/* ── F2 · SERVICE HERO ──────────────────────────────────────────────────── */
/* Pulled up under the sticky header exactly like the homepage hero, so the
   transparent nav sits on the dark chapter instead of on white. Not optional
   on any dark-hero page. */
.hl-shero{
  position:relative; isolation:isolate; overflow:hidden;
  background:
    radial-gradient(1100px 640px at 82% 4%, #1B2166 0%, transparent 62%),
    radial-gradient(820px 560px at 4% 92%, #191E58 0%, transparent 60%),
    linear-gradient(168deg,#0B0E28 0%,#080A1D 55%,#05060F 100%);
  margin-top:calc(var(--hl-nav-h) * -1); padding-top:var(--hl-nav-h);
}
.hl-shero__shell{
  position:relative; z-index:1;
  display:grid; grid-template-columns:minmax(0,1.02fr) minmax(0,.98fr); align-items:center;
  gap:clamp(36px,4vw,72px);
  padding-block:clamp(48px,5vw,84px) var(--hl-hero-air);
}
.hl-shero__copy{ max-width:600px; min-width:0; }
/* The token is the whole closing distance, so the last group in a hero column
   stands its own trailing margin down. Without this a hero that happens to end
   in a chip list adds the list's 24px on top and the contract becomes a floor
   instead of a value — which is how 86px became 110px on six pages. */
.hl-hero__shell > * > :last-child,
.hl-shero__shell > * > :last-child{ margin-bottom:0; }
/* ── HEADING LINE BREAKS ───────────────────────────────────────────────────
   `text-wrap:balance` evens the lines of a short display heading instead of
   filling greedily and leaving an orphan. The Cash Discount hero broke as
   "One Posted / Price, and a / Discount for Cash." — a four-word middle line
   splitting a noun phrase (audit M-03). Balancing is the fix that does not
   require authoring a break per heading per width.

   `hyphens:manual` is the other half. The Pay-at-Pump product H1 broke on its
   OWN hyphen — "Pay-at- / Pump Terminal" — because a hyphen is a break
   opportunity by default. The product name is one token and now stays one
   (audit M-02 / PD-09).

   Both degrade to today's behaviour where unsupported; neither changes a
   heading that already fits. */
:where(.hl-hero__h1, .hl-shero__h1, .hl-heroblock__title, .hl-ihead__title,
       .hl-price__title, .hl-h2, .hl-ioffer__title){
  text-wrap:balance; hyphens:manual;
}

.hl-shero__h1{
  font:800 clamp(2.3rem,4.2vw,3.6rem)/1.05 var(--hl-ff-display);
  color:#fff; letter-spacing:-.035em; margin-bottom:var(--hl-s-6);
}
/* the italic overhang eats the following word space — give it back */
.hl-shero__h1 em{ font-style:italic; font-weight:700; color:var(--hl-navy-300); margin-right:.08em; }
.hl-shero__lede{ font-size:var(--hl-fs-lede); line-height:1.68; color:var(--hl-text-light-2);
  max-width:52ch; margin-bottom:var(--hl-s-8); }
.hl-shero__cta{ display:flex; flex-wrap:wrap; gap:14px; }
.hl-shero__chips{ margin-bottom:0; }
.hl-shero__chips li{ font-size:var(--hl-fs-micro); letter-spacing:.05em; text-transform:uppercase; }
.hl-shero__viz{ min-width:0; }

/* Acceptance diagram: channels converging on one system, then out to
   authorization and settlement. The stage holds a fixed aspect ratio so the
   SVG wires and the CSS-positioned nodes can never drift apart at any width. */
.hl-accv{
  position:relative; padding:20px 20px 16px; border-radius:var(--hl-r-2xl);
  background:linear-gradient(160deg,rgba(42,45,124,.34),rgba(10,12,34,.72));
  border:1px solid var(--hl-line-dark-2); box-shadow:var(--hl-sh-glass);
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
}
.hl-accv__head{ display:flex; justify-content:space-between; align-items:center; margin-bottom:12px; }
.hl-accv__label{ font:600 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wider);
  text-transform:uppercase; color:var(--hl-text-light-4); }
.hl-accv__live{ display:inline-flex; align-items:center; gap:7px; padding:5px 10px;
  border-radius:var(--hl-r-pill); background:rgba(47,214,163,.10); border:1px solid rgba(47,214,163,.28);
  font:500 var(--hl-fs-micro)/1 var(--hl-ff-mono); letter-spacing:.06em; color:var(--hl-ok); }
.hl-accv__live i{ width:5px; height:5px; border-radius:50%; background:var(--hl-ok);
  box-shadow:0 0 8px var(--hl-ok); animation:hls-blip 2.2s var(--hl-e-inout) infinite; }
@keyframes hls-blip{ 0%,100%{ opacity:1 } 50%{ opacity:.28 } }

.hl-accv__stage{ position:relative; width:100%; aspect-ratio:460/340; }
.hl-accv__routes{ position:absolute; inset:0; width:100%; height:100%; }

.hl-accv__in{
  position:absolute; left:0; top:5.6%; width:32.2%; height:60.6%;
  display:grid; grid-template-rows:repeat(var(--hl-accv-rows,4),1fr);
  margin:0; padding:0; list-style:none;
}
/* grid, not flex: the icon spans both rows so the label sits above the caption */
.hl-cnode{
  display:grid; grid-template-columns:auto minmax(0,1fr); align-items:center;
  column-gap:9px; margin:3px 0; padding:0 11px;
  border-radius:var(--hl-r-sm); background:rgba(255,255,255,.05);
  border:1px solid var(--hl-line-dark); min-width:0;
  animation:hls-cnodeLit 4.4s var(--hl-e-inout) infinite; animation-delay:calc(var(--hl-i,0) * .55s);
}
@keyframes hls-cnodeLit{
  0%,88%,100%{ background:rgba(255,255,255,.05); border-color:rgba(255,255,255,.09) }
  6%,20%{ background:rgba(90,97,204,.22); border-color:rgba(144,150,228,.5) }
}
.hl-cnode__ico{ grid-row:1/span 2; width:16px; height:16px; color:var(--hl-navy-300); }
.hl-cnode b{ grid-column:2; font:600 var(--hl-fs-xs)/1.15 var(--hl-ff-display); color:#fff;
  letter-spacing:-.015em; white-space:nowrap; }
.hl-cnode i{ grid-column:2; margin-top:2px; font-size:var(--hl-fs-micro); color:var(--hl-text-light-4);
  line-height:1.25; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.hl-accv .hl-sroute{ stroke:rgba(255,255,255,.2); }

.hl-accv__out{ position:absolute; left:56.1%; right:0; top:0; bottom:0; }
.hl-corenode{
  position:absolute; left:0; right:0; top:22.4%; height:29.4%;
  display:flex; flex-direction:column; justify-content:center; padding:0 14px;
  border-radius:var(--hl-r-md);
  background:linear-gradient(150deg,rgba(207,41,39,.16),rgba(42,45,124,.5));
  border:1px solid rgba(229,84,78,.34);
  box-shadow:0 18px 40px -20px rgba(0,0,0,.9), inset 0 1px 0 rgba(255,255,255,.14);
}
.hl-corenode__tag{ font:700 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-red-300); }
.hl-corenode b{ margin-top:5px; font:700 var(--hl-fs-sm)/1.2 var(--hl-ff-display); color:#fff;
  letter-spacing:-.02em; }
.hl-corenode__rows{ display:flex; gap:12px; margin-top:9px; flex-wrap:wrap; }
.hl-corenode__rows li{ display:inline-flex; align-items:center; gap:5px;
  font:400 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:var(--hl-text-light-3); }
.hl-corenode__rows i{ width:5px; height:5px; border-radius:1.5px; background:var(--hl-text-light-4);
  transition:background var(--hl-t-med), box-shadow var(--hl-t-med); }
.hl-corenode__rows li.is-on i{ background:var(--hl-ok); box-shadow:0 0 8px rgba(47,214,163,.8); }
.hl-corenode__rows li.is-on{ color:#fff; }

.hl-onode{
  position:absolute; left:0; right:0; height:11.76%;
  display:flex; align-items:center; justify-content:space-between; gap:10px; padding:0 13px;
  border-radius:var(--hl-r-sm); background:rgba(255,255,255,.045);
  border:1px solid var(--hl-line-dark); min-width:0;
}
.hl-onode--0{ top:63.5%; }
.hl-onode--1{ top:84.1%; }
.hl-onode__k{ font:600 var(--hl-fs-xs)/1 var(--hl-ff-display); color:#fff; white-space:nowrap; }
.hl-onode__v{ font:400 var(--hl-fs-micro)/1 var(--hl-ff-mono); color:var(--hl-text-light-4);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.hl-onode--ok{ background:rgba(47,214,163,.09); border-color:rgba(47,214,163,.3); }
.hl-onode--ok .hl-onode__v{ color:var(--hl-ok); }

.hl-accv__foot{ margin:12px 0 0; padding-top:11px; border-top:1px solid var(--hl-line-dark);
  font-size:var(--hl-fs-micro); color:var(--hl-text-light-4); }

/* ── F3 · PAGE RAIL ─────────────────────────────────────────────────────── */
/* The main structural difference between an inner page and the homepage: the
   whole page is visible at a glance and the reader always knows where they are. */
.hl-rail{
  position:sticky; top:var(--hl-nav-h); z-index:40;
  background:rgba(7,9,25,.92); -webkit-backdrop-filter:blur(16px) saturate(140%);
  backdrop-filter:blur(16px) saturate(140%);
  border-bottom:1px solid var(--hl-line-dark);
}
.hl-rail__shell{ display:flex; align-items:center; gap:var(--hl-s-6); height:var(--hl-rail-h); }
.hl-rail__title{
  display:inline-flex; align-items:center; gap:9px; flex:none;
  font:700 var(--hl-fs-xs)/1 var(--hl-ff-display); color:#fff; letter-spacing:-.01em;
  padding-right:var(--hl-s-6); border-right:1px solid var(--hl-line-dark);
}
.hl-rail__title::before{ content:""; width:6px; height:6px; border-radius:2px; background:var(--hl-red-500);
  box-shadow:0 0 10px rgba(207,41,39,.8); }
.hl-rail__list{ display:flex; align-items:center; gap:2px; min-width:0; flex:1;
  overflow-x:auto; scrollbar-width:none; margin:0; padding:0; list-style:none; }
.hl-rail__list::-webkit-scrollbar{ display:none; }

/* ── GROUP H · A HIDDEN SCROLLER IS NOT A NAVIGATION ───────────────────────
   `overflow-x:auto` with the scrollbar suppressed is invisible. On `/terms` at
   1536 the rail's content is 1,563px inside an 865px viewport — 698px and 8 of
   14 chapters unreachable unless the reader guesses that the strip drags — and
   the item at the boundary is cut mid-word against the CTA (audit LG-02). The
   same pattern hides 719px of the switchboard's channels at 768 (CH-10).

   `.hl-scrollcue` is the shared answer: the scroller is masked so its content
   fades out at whichever edge still has content beyond it. Without JavaScript
   the right-hand fade is always on, which is the honest default for a strip
   that is nearly always longer than its box; `highline.js` then adds
   `is-cue-start` / `is-cue-end` so the fade disappears at a real end and
   appears on the left once the reader has scrolled. Nothing is hidden that was
   not hidden before — the point is that the reader can now SEE that it moves. */
.hl-scrollcue{
  --hl-cue-l:0px; --hl-cue-r:44px;
  -webkit-mask-image:linear-gradient(90deg, transparent 0, #000 var(--hl-cue-l),
                     #000 calc(100% - var(--hl-cue-r)), transparent 100%);
          mask-image:linear-gradient(90deg, transparent 0, #000 var(--hl-cue-l),
                     #000 calc(100% - var(--hl-cue-r)), transparent 100%);
}
.hl-scrollcue.is-cue-start{ --hl-cue-l:44px; }
.hl-scrollcue.is-cue-end{ --hl-cue-r:0px; }
/* A scroller that fits needs no cue at all. */
.hl-scrollcue.is-cue-none{ --hl-cue-l:0px; --hl-cue-r:0px; }
.hl-rail__list a{
  position:relative; display:block; padding:9px 13px; border-radius:var(--hl-r-sm); white-space:nowrap;
  font:500 var(--hl-fs-xs)/1 var(--hl-ff-display); color:var(--hl-text-light-3);
  transition:color var(--hl-t-fast), background var(--hl-t-fast);
}
.hl-rail__list a:hover{ color:#fff; background:rgba(255,255,255,.06); }
.hl-rail__list a.is-active{ color:#fff; }
.hl-rail__list a.is-active::after{
  content:""; position:absolute; left:13px; right:13px; bottom:3px; height:2px; border-radius:2px;
  background:var(--hl-red-500);
}
.hl-rail__cta{ flex:none; }

/* ── F4 · INNER SECTION HEAD — THE CHAPTER SPINE ────────────────────────── */
/* Outlined numerals give a long inner page a spine and read as documentation
   rather than marketing. The figure is derived by the renderer from the page's
   own rail order, so it can never disagree with the navigation.

   ── ONE SPINE, AND WHY IT IS THIS ONE ─────────────────────────────────────
   This head used to put the numeral in a grid column BESIDE the eyebrow, while
   six other compositions — `content · steps`, `why · compact`, `faq · chapter`,
   `cash_discount`, `products · insert` and `promotion · offer` — drew the same
   numeral as a free-standing block ABOVE it. Both were defensible on their own
   and the site mixed them, so a reader going down one page met the numeral in
   the margin, then above the eyebrow, then centred inside a card.

   Measured before the change (`docs/SITE-WIDE-VISUAL-AUDIT.md` GROUP A): the
   numeral's offset from its eyebrow was −10px in the grid head and −61 to −72px
   in the stacked one, and — the larger consequence — the chapter HEADINGS on a
   single page started at up to six different left edges, spanning 210px on an
   industry page and 88–90px on a service page.

   The spine is now the flush one. The numeral is a block above the eyebrow at
   every width, so every chapter heading on a page starts at the same left edge
   as the chapter body underneath it. Two reasons for choosing this direction
   over insetting everything into a numeral gutter:

     1. `/savings-calculator` already used one treatment throughout and was the
        only page in the audit with a 0px spread — the flush spine is the one
        the site already proves reads correctly.
     2. Below 900px `.hl-ihead` has ALWAYS collapsed to exactly this. The change
        extends the mobile behaviour upward rather than inventing a third
        arrangement, which is why the markup did not have to move.

   `--inline` is kept as a no-op alias: six views still emit it, it now means
   the same thing the base rule means, and removing it from those views would
   be churn with no rendered difference. */
.hl-ihead{
  display:grid; grid-template-columns:minmax(0,1fr); gap:0;
  margin-bottom:var(--hl-s-14); max-width:1020px;
}
.hl-ihead > *{ min-width:0; }

/* The numeral. `display:block` and a fixed line box are what keep the spine
   straight: a block-level numeral cannot push the heading sideways, and
   `tabular-nums` stops "01" and "04" reserving different widths — the 12px
   heading drift the audit measured on product pages (PD-08). */
.hl-ihead__n,
.hl-ihead__n--inline{
  display:block; margin:0 0 var(--hl-s-6); font-variant-numeric:tabular-nums;
  font:800 clamp(2rem,3.2vw,3rem)/.9 var(--hl-ff-display); letter-spacing:-.05em;
  color:var(--hl-cn-fill, transparent); -webkit-text-stroke:1.6px var(--hl-cn-ink, var(--hl-numeral-ink));
}
/* Legibility, not decoration. The outline used to be 1.4px of `--hl-line-2`
   (#D3DBEA) on white, which on the light and alt bands read as a smudge rather
   than a number (audit HR-02). `--hl-numeral-ink` is a touch darker and the
   stroke a touch heavier; it is still an outline, still quiet, and it is now
   legible on every band the design system paints. */
:root{ --hl-numeral-ink:#B9C4DB; }
.hl-ihead--light .hl-ihead__n,
.hl-ihead__n--light{ -webkit-text-stroke-color:var(--hl-cn-ink, rgba(255,255,255,.30)); }

/* The numeral-to-eyebrow gap has to be the SAME on every chapter, and left to
   itself it is not: an eyebrow is `inline-flex`, so it sits in a line box whose
   height comes from the PARENT's strut. In a block copy column that added ~11px
   of half-leading above it (measured gap 31px); inside `.hl-rwhy__lead`, which
   is a flex column, the eyebrow is blockified and there is none (20px). Same
   markup, same intent, two values.

   Blockifying `.hl-eyebrow` globally would move ~200 eyebrows the site does not
   want moved, so this is scoped to exactly the two shapes a chapter head takes:
   the eyebrow as the numeral's next sibling (the six copy-column compositions),
   and the eyebrow opening the wrapper that follows the numeral (the grid head).
   Both now measure the numeral's own margin and nothing else. */
.hl-ihead__n + .hl-eyebrow,
.hl-ihead__n + * > .hl-eyebrow:first-child{ display:flex; width:fit-content; }
.hl-ihead__title{ font-size:var(--hl-fs-h2); color:var(--hl-hd-ink, inherit); }
.hl-ihead--light .hl-ihead__title{ color:var(--hl-hd-ink, #fff); }
.hl-ihead__lede{ margin:var(--hl-s-5) 0 0; font-size:var(--hl-fs-lede); line-height:1.7;
  color:var(--hl-text-muted); max-width:62ch; }
.hl-ihead--light .hl-ihead__lede{ color:var(--hl-text-light-2); }

/* ── The split head: a chapter head that carries an action on the right ────
   `align-items:end` used to put that action on the bottom of the whole head
   block. With a one-line heading that looked nearly right; with a two-line
   heading plus a lede it landed 101–119px below the heading and about a
   thousand pixels to its right, attached to nothing (audit GROUP G). And
   because "the bottom of the block" moves with the type scale, the same
   one-line relationship measured 5px at 1024, 18px at 1280 and 26px at 1440.

   The action now belongs to the HEADING's row and nothing else is allowed into
   it. The numeral takes a full-width row above; the lede takes a full-width row
   below (`funding-strip.php` had it inside the heading wrapper, which is what
   dragged the action down — it is now a sibling). What is left in the middle
   row is the eyebrow-plus-heading block and the action, bottom-aligned to each
   other, which is the relationship the variant was drawn for. A two-line
   heading now lands the action on its second line instead of 119px below the
   whole composition.

   The rows are placed EXPLICITLY. Auto-placement will not do it: the lede
   spans both columns, so the cursor moves past the heading row and the action
   lands in a row of its own underneath — which is the bug, one row lower. */
.hl-ihead--split{ grid-template-columns:minmax(0,1fr) auto; align-items:end; max-width:none; }
.hl-ihead--split > .hl-ihead__n{ grid-row:1; grid-column:1 / -1; align-self:start; }
.hl-ihead--split > :not(.hl-ihead__n):not(.hl-ihead__action):not(.hl-ihead__lede){ grid-row:2; grid-column:1; }
.hl-ihead--split > .hl-ihead__action{ grid-row:2; grid-column:2; justify-self:end; }
.hl-ihead--split > .hl-ihead__lede{ grid-row:3; grid-column:1 / -1; align-self:start; margin-top:0; }
.hl-ihead__action{ margin-left:var(--hl-s-8); white-space:nowrap; }

/* On a phone the action cannot sit beside anything, so it stacks under the
   heading at the flow contract's distance rather than wherever the grid left
   it. */
@media (max-width:768px){
  .hl-ihead--split{ grid-template-columns:minmax(0,1fr); }
  .hl-ihead--split > .hl-ihead__lede{ grid-row:3; }
  .hl-ihead--split > .hl-ihead__action{ grid-row:4; grid-column:1; justify-self:start;
    margin:var(--hl-flow) 0 0; }
}

/* The `why` chapter's action, at the foot of its lead column. `margin-top:auto`
   pins it to the bottom of the column whatever the copy does, so two `why`
   chapters on one page agree with each other. */
.hl-rwhy__cta{ margin-top:var(--hl-s-6); align-self:flex-start; }
.hl-rwhy__lead{ display:flex; flex-direction:column; }

/* ── F5 · ACCEPTANCE SWITCHBOARD ────────────────────────────────────────── */
/* Not six cards: one switchboard. The rail on the left is the system, the panel
   on the right is the detail, and the active row physically connects to it. */
.hl-acc{ position:relative; overflow:hidden; padding-block:var(--hl-sec-pad);
  background:linear-gradient(180deg,#fff,var(--hl-paper) 78%); }
.hl-acc .hl-shell{ position:relative; z-index:1; }

.hl-switch{
  display:grid; grid-template-columns:minmax(0,.86fr) minmax(0,1.14fr);
  gap:clamp(20px,2.4vw,36px);
}
/* The rail's spine is drawn on the rail's own box, and the rail is a grid item
   stretched to the row height — which on `/funding` (four channels beside a
   tall panel) left the line running ~210px past the last row into nothing
   (audit GROUP E). Standing the rail down to its content ties the spine to the
   rows that justify it. */
.hl-switch__rail{ display:grid; align-content:start; align-self:start; gap:8px; position:relative; }
/* the rail is the system: one continuous line behind the rows */
.hl-switch__rail::before{
  content:""; position:absolute; left:26px; top:22px; bottom:22px; width:1px;
  background:linear-gradient(180deg,transparent,var(--hl-line-2) 12%,var(--hl-line-2) 88%,transparent);
}
.hl-srow{
  position:relative; z-index:1; display:grid; grid-template-columns:auto minmax(0,1fr) auto;
  align-items:center; gap:14px; text-align:left; padding:15px 16px;
  border-radius:var(--hl-r-lg); border:1px solid transparent; background:transparent;
  transition:background var(--hl-t-med) var(--hl-e-soft), border-color var(--hl-t-med),
             box-shadow var(--hl-t-med), transform var(--hl-t-med) var(--hl-e-out);
}
.hl-srow__ico{ width:20px; height:20px; color:var(--hl-text-muted); flex:none;
  transition:color var(--hl-t-med); }
.hl-srow__txt{ min-width:0; }
.hl-srow__txt b{ display:block; font:600 var(--hl-fs-body)/1.25 var(--hl-ff-display);
  color:var(--hl-text-dark); letter-spacing:-.015em; }
.hl-srow__txt i{ display:block; margin-top:3px; font-size:var(--hl-fs-xs); color:var(--hl-text-muted); }
.hl-srow__arrow{
  width:8px; height:8px; flex:none; opacity:0;
  border-right:1.6px solid var(--hl-brand-red); border-top:1.6px solid var(--hl-brand-red);
  transform:rotate(45deg) translateX(-4px);
  transition:opacity var(--hl-t-med), transform var(--hl-t-med) var(--hl-e-out);
}
.hl-srow:hover{ background:#fff; border-color:var(--hl-line); box-shadow:var(--hl-sh-sm); }
.hl-srow.is-active{ background:#fff; border-color:var(--hl-line); box-shadow:var(--hl-sh-md); }
.hl-srow.is-active .hl-srow__ico{ color:var(--hl-brand-red); }
.hl-srow.is-active .hl-srow__arrow{ opacity:1; transform:rotate(45deg) translateX(0); }
/* the active row physically connects to the panel */
.hl-srow.is-active::after{
  content:""; position:absolute; right:-1px; top:50%; width:calc(clamp(20px,2.4vw,36px) + 2px);
  height:1px; background:var(--hl-brand-red); opacity:.5;
}

.hl-switch__panels{ position:relative; }
.hl-spanel{
  --hl-spanel-pad:clamp(24px,2.6vw,38px);
  display:grid; grid-template-columns:minmax(0,1fr) auto; gap:clamp(20px,2.4vw,34px);
  align-items:center; height:100%; padding:var(--hl-spanel-pad);
  border-radius:var(--hl-r-2xl); background:#fff; border:1px solid var(--hl-line);
  box-shadow:var(--hl-sh-lg); overflow:hidden;
}
.hl-spanel[hidden]{ display:none; }
.hl-spanel.is-active{ animation:hls-spanelIn 460ms var(--hl-e-out) both; }
@keyframes hls-spanelIn{ from{ opacity:0; transform:translateY(10px) } to{ opacity:1; transform:none } }
.hl-spanel__body{ min-width:0; }
.hl-spanel__body h3{ font-size:var(--hl-fs-h3); margin-bottom:var(--hl-s-4); }
.hl-spanel__body p{ font-size:var(--hl-fs-sm); line-height:1.72; color:var(--hl-text-body);
  margin-bottom:var(--hl-s-6); max-width:52ch; }
.hl-slist{ display:grid; gap:1px; margin:0; padding:0; list-style:none; }
.hl-slist li{ display:grid; grid-template-columns:118px minmax(0,1fr); gap:16px; align-items:baseline;
  padding:12px 0; border-top:1px solid var(--hl-line); }
.hl-slist li:last-child{ border-bottom:1px solid var(--hl-line); }
.hl-slist b{ font:600 var(--hl-fs-micro)/1.5 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-text-muted); }
.hl-slist span{ font-size:var(--hl-fs-xs); line-height:1.6; color:var(--hl-text-dark); }
/* The row's optional destination. Only the Services index sets one; on a
   service page the channels are parts of one page and nothing renders here. */
.hl-spanel__go{ margin-top:var(--hl-s-6); }

/* ── The channel's media ───────────────────────────────────────────────────
   One fixed 210px frame used to hold both a photograph and a CSS silhouette.
   For the silhouette that frame is right — illustrative artwork wants a stage
   and a controlled size. For a photograph it was wrong twice over: the picture
   rendered at 188×141 inside a 659×660 panel (6.1% of it), and the frame's own
   white card sat on the panel's white card, so the photograph read as a
   thumbnail taped to an empty panel rather than as the panel's content
   (audit PP-02 / GROUP E).

   Two treatments now, chosen by whether the channel actually has a photograph
   — `blocks/switchboard.php` sets the modifier. */
.hl-spanel__art{
  position:relative; display:grid; grid-template-rows:1fr auto; justify-items:center;
  align-items:center; gap:14px; flex:none;
}
/* Illustrative device art: the framed stage, kept. */
.hl-spanel--art{
  width:210px; padding:22px 10px; border-radius:var(--hl-r-xl);
  background:linear-gradient(170deg,var(--hl-paper),#fff);
  border:1px solid var(--hl-line);
}
/* Real photography: roughly the right half of the panel, bled to the panel's
   own edges so it is part of the card, with the panel's radius carried on the
   outer corners and a white-to-transparent fade on the inside edge so the
   picture hands off to the copy instead of butting against it. */
.hl-spanel--haspic{ grid-template-columns:minmax(0,1fr) clamp(220px,34%,400px); gap:0; }
.hl-spanel--photo{
  width:auto; align-self:stretch; gap:0; display:block;
  margin:calc(var(--hl-spanel-pad) * -1) calc(var(--hl-spanel-pad) * -1) calc(var(--hl-spanel-pad) * -1) 0;
  border-radius:0 var(--hl-r-2xl) var(--hl-r-2xl) 0; overflow:hidden;
  background:var(--hl-paper);
}
/* The picture is taken out of flow so it can fill the panel without ever
   DRIVING its height: a percentage height on an <img> inside an auto-height
   grid item resolves against the image's intrinsic size, and the panel grew to
   2,132px the first time this was written with `height:100%`. */
.hl-spanel--photo .hl-pslot{ position:absolute; inset:0; display:block; height:auto; }
.hl-spanel--photo .hl-pslot img{
  position:absolute; inset:0; width:100%; height:100%; max-width:none; max-height:none;
  object-fit:cover; object-position:center; padding:0; margin:0;
}
.hl-spanel--photo::after{
  content:""; position:absolute; inset:0 auto 0 0; width:clamp(40px, 22%, 96px);
  background:linear-gradient(90deg, #fff, rgba(255,255,255,0));
  pointer-events:none;
}
/* The banner treatment begins where the PANEL goes single-column, which is
   1120px (below), not 900px. While these two disagreed there was a 220px band —
   901 to 1120, and 1024 sits in it — where the panel had already stacked but
   the photograph was still being laid out as a side column. It kept
   `align-self:stretch` in a row whose height was auto, and its `.hl-pslot` is
   `position:absolute`, so nothing inside it contributed any height at all: the
   picture collapsed to a 53px strip in a 530px panel (5.6% of it — worse than
   the 6.1% letterbox this whole treatment was written to replace). Measured on
   `/services/payment-processing` at 1024: Online Payments 280x53, Mobile
   Payments 280x80. */
@media (max-width:1120px){
  /* Stacked: the photograph becomes a banner across the top of the panel and
     the negative margins flip with it. */
  .hl-spanel--photo{
    /* `order:-1` is load-bearing and belongs HERE rather than being inherited
       from the device-stage rule below: the media is the panel's last child in
       the markup, and this treatment is a banner across the TOP — negative top
       margin, top-only radius, and a fade rising from its bottom edge. Without
       it the photograph renders at the foot of the panel with the top of a
       banner drawn on it, upside down at the wrong end. */
    order:-1;
    width:auto; height:200px; grid-template-rows:1fr;
    margin:calc(var(--hl-spanel-pad) * -1) calc(var(--hl-spanel-pad) * -1) 0;
    border-radius:var(--hl-r-2xl) var(--hl-r-2xl) 0 0;
  }
  .hl-spanel--photo::after{ inset:auto 0 0 0; width:auto; height:56px;
    background:linear-gradient(0deg, #fff, rgba(255,255,255,0)); }
}
.hl-spanel__art .hl-pslot{ height:100%; }
.hl-spanel__art .hl-dev{ --hl-k:.86; transform:scale(.86); margin-block:-14px;
  animation:hls-hover 7s var(--hl-e-inout) infinite; }
.hl-spanel__art .hl-dev--smart{ --hl-k:.8; transform:scale(.8); margin-block:-21px; }
.hl-spanel__art .hl-dev--counter{ --hl-k:.86; transform:scale(.86); margin-block:-9px; }
.hl-spanel__art .hl-dev--invoice{ --hl-k:.9; transform:scale(.9); margin-block:-7px; }
.hl-spanel__art .hl-pslot__ph{ --hl-ph-name:var(--hl-text-dark); --hl-ph-note:var(--hl-text-muted); }

/* ── The panel with no image at all ────────────────────────────────────────
   `Show image` off in Admin, or a channel that has neither an upload nor a
   device silhouette to stand in for one. Either way the artwork element is not
   in the markup — `blocks/switchboard.php` does not render it — and this rule
   removes what the markup alone cannot.

   Both declarations are load-bearing, and the second is the one that is easy to
   miss. `grid-template-columns` still declares a second track, and an empty
   declared track is still a track: the `clamp(20px,2.4vw,34px)` column gap is
   laid out beside it whether or not anything ever lands there. Measured on
   `/funding`, whose four channels have never had artwork, the body was 549px
   inside a 584px content box — 34px of reserved gutter with nothing on the far
   side of it. That is the "empty reserved column" this state exists to not
   have, so the TRACK goes, not just the item.

   The copy keeps `.hl-spanel__body p{max-width:52ch}`, which is the measure the
   `/funding` panels already read at: the point of the extra width is that the
   detail rows and the heading get it, not that the lede runs to 90 characters.
   This is deliberately the same composition — a text-only panel here and a
   text-only panel there should not be two designs. */
.hl-spanel--textonly{ grid-template-columns:minmax(0,1fr); gap:0; }

/* ── F6 · PROCESS TRACK ─────────────────────────────────────────────────── */
/* Always-visible stops, not a stepper: the reader should understand the journey
   without clicking. The lit stage advances on its own so it reads as a journey,
   and any hover or focus takes over and stops the rotation. */
.hl-flow{ position:relative; overflow:hidden; padding-block:var(--hl-sec-pad);
  background:linear-gradient(178deg,var(--hl-ink-900),var(--hl-ink-850) 55%,var(--hl-ink-900)); }
.hl-flow .hl-shell{ position:relative; z-index:1; }

.hl-track{ position:relative; }
.hl-track__line{ position:absolute; left:0; right:0; top:52px; height:40px; z-index:0; }
.hl-track__stops{
  position:relative; z-index:1; margin:0; padding:0; list-style:none;
  display:grid; grid-template-columns:repeat(var(--hl-track-cols,6),minmax(0,1fr));
  gap:clamp(10px,1.1vw,16px);
}
.hl-stop{
  position:relative; padding:22px 16px 20px; border-radius:var(--hl-r-lg);
  background:rgba(255,255,255,.035); border:1px solid var(--hl-line-dark);
  transition:background var(--hl-t-med), border-color var(--hl-t-med), transform var(--hl-t-med) var(--hl-e-out);
}
.hl-stop::before{
  content:""; position:absolute; left:16px; top:-5px; width:9px; height:9px; border-radius:50%;
  background:var(--hl-ink-800); border:1.5px solid var(--hl-line-dark-2);
  transition:background var(--hl-t-med), border-color var(--hl-t-med), box-shadow var(--hl-t-med);
}
.hl-stop__n{ display:block; margin-bottom:12px;
  font:700 var(--hl-fs-micro)/1 var(--hl-ff-mono); letter-spacing:.14em; color:var(--hl-text-light-4); }
.hl-stop__t{ font:700 var(--hl-fs-h4)/1.2 var(--hl-ff-display); color:#fff; letter-spacing:-.02em;
  margin-bottom:9px; }
.hl-stop p{ font-size:var(--hl-fs-xs); line-height:1.62; color:var(--hl-text-light-3); margin:0; }
.hl-stop:hover,.hl-stop:focus-within,.hl-stop.is-lit{
  background:rgba(90,97,204,.12); border-color:rgba(144,150,228,.34); transform:translateY(-4px);
}
.hl-stop:hover::before,.hl-stop:focus-within::before,.hl-stop.is-lit::before{
  background:var(--hl-red-500); border-color:var(--hl-red-400);
  box-shadow:0 0 0 4px rgba(207,41,39,.18), 0 0 14px rgba(207,41,39,.7);
}
.hl-stop--end{ background:rgba(47,214,163,.06); border-color:rgba(47,214,163,.22); }
.hl-stop--end .hl-stop__n{ color:var(--hl-ok); }

/*
 * The qualification under the track.
 *
 * It is a CALLOUT, not body copy — one sentence that belongs with the sequence
 * above it — so it is measured by its panel rather than by a reading measure.
 * `max-width:82ch` used to cap the paragraph at 724px inside a panel 1192px
 * wide, which wrapped a line that had 420px of room left to two, and the extra
 * line took the panel from 54px to 90px. The panel is already bounded by the
 * shell; a second bound inside it was the whole defect.
 *
 * Padding is 14px rather than 20px for the same reason: 40px of vertical
 * padding around a single line reads as a block, and this is a footnote.
 * Nothing else moved — the accent rule, the ground, the type ramp and the
 * emphasis colour are the approved treatment.
 *
 * Narrower viewports wrap it naturally, which is correct: the sentence is not
 * shortened to fit and nothing is clipped.
 */
.hl-track__note{
  margin-top:var(--hl-s-10); padding:14px 22px; border-radius:var(--hl-r-lg);
  background:rgba(255,255,255,.04); border:1px solid var(--hl-line-dark);
  border-left:3px solid var(--hl-red-500);
}
.hl-track__note p{ margin:0; font-size:var(--hl-fs-sm); line-height:1.7; color:var(--hl-text-light-2); }
.hl-track__note b, .hl-track__note strong{ color:#fff; font-weight:600; }

/* ── F7 · COMPACT INDUSTRIES ────────────────────────────────────────────── */
/* Deliberately compact — one row of pills and one panel. This is supporting
   content; the homepage owns the full industries experience. */
.hl-binds{ position:relative; padding-block:var(--hl-sec-pad-sm); background:var(--hl-paper); }
.hl-binds__more{ align-self:end; padding-bottom:6px; }

.hl-binds__tabs{ display:flex; flex-wrap:wrap; gap:8px; margin-bottom:var(--hl-s-8); }
.hl-btab{
  display:inline-flex; align-items:center; gap:9px; padding:11px 17px; border-radius:var(--hl-r-pill);
  background:#fff; border:1px solid var(--hl-line);
  font:600 var(--hl-fs-sm)/1 var(--hl-ff-display); color:var(--hl-text-muted); letter-spacing:-.01em;
  transition:color var(--hl-t-med), border-color var(--hl-t-med), box-shadow var(--hl-t-med),
             background var(--hl-t-med), transform var(--hl-t-med) var(--hl-e-out);
}
.hl-btab [data-ico]{ width:16px; height:16px; }
.hl-btab:hover{ color:var(--hl-text-dark); border-color:var(--hl-line-2); transform:translateY(-2px); }
.hl-btab.is-active{
  color:#fff; background:linear-gradient(168deg,var(--hl-ink-750),var(--hl-ink-850));
  border-color:transparent; box-shadow:var(--hl-sh-navy);
}

.hl-bpanel{
  padding:clamp(24px,2.6vw,36px); border-radius:var(--hl-r-2xl);
  background:#fff; border:1px solid var(--hl-line); box-shadow:var(--hl-sh-sm);
}
.hl-bpanel[hidden]{ display:none; }
.hl-bpanel.is-active{ animation:hls-spanelIn 420ms var(--hl-e-out) both; }
.hl-bpanel__lead{ margin:0 0 var(--hl-s-6); font-size:var(--hl-fs-lede); line-height:1.55;
  color:var(--hl-text-dark); font-family:var(--hl-ff-display); font-weight:600;
  letter-spacing:-.02em; max-width:56ch; }
.hl-bpanel__cols{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:1px;
  background:var(--hl-line); border:1px solid var(--hl-line); border-radius:var(--hl-r-md);
  overflow:hidden; margin:0; }
.hl-bpanel__cols > div{ background:#fff; padding:18px 20px; }
.hl-bpanel__cols dt{ font:600 var(--hl-fs-micro)/1.5 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-brand-red); margin-bottom:7px; }
.hl-bpanel__cols dd{ margin:0; font-size:var(--hl-fs-xs); line-height:1.6; color:var(--hl-text-dark); }
.hl-bpanel__link{ margin-top:var(--hl-s-6); }

/* ── F8 · HARDWARE INSERT ───────────────────────────────────────────────── */
.hl-hw2{ position:relative; padding-block:var(--hl-sec-pad); background:#fff; }
.hl-hw2__shell{ display:grid; grid-template-columns:minmax(0,.82fr) minmax(0,1.18fr);
  gap:clamp(32px,3.6vw,64px); align-items:center; }
.hl-hw2__copy{ min-width:0; }
.hl-hw2__copy .hl-ihead__title{ margin-bottom:var(--hl-s-5); }
.hl-hw2__lede{ font-size:var(--hl-fs-sm); line-height:1.72; color:var(--hl-text-body); max-width:44ch; }
.hl-hw2__note{
  margin:var(--hl-s-5) 0 var(--hl-s-8); padding:14px 16px; border-radius:var(--hl-r-md);
  background:var(--hl-paper); border:1px solid var(--hl-line); border-left:3px solid var(--hl-brand-red);
  font-size:var(--hl-fs-xs); line-height:1.6; color:var(--hl-text-dark);
}
/*
 * `grid-auto-rows:1fr` — the same correction `.hl-pgrid` already carries, and
 * for the same reason. This grid is two columns and two rows at every width, and
 * auto rows size to their own tallest item, so the row holding the longest
 * description was 396px while the row under it was 376px. Nothing was wrong
 * with either card; the rows were simply independent, and the result was four
 * "View details" controls at four different heights down the page.
 *
 * In a grid whose own height is indefinite, `1fr` rows all resolve to the
 * tallest row's max-content height. No fixed height, no JavaScript, and the
 * spare height lands under the caption where `.hl-hcard__link{margin-top:auto}`
 * is waiting for it.
 */
.hl-hw2__grid{ display:grid; grid-template-columns:repeat(var(--hl-row-n, 2), minmax(0,1fr)); grid-auto-rows:1fr;
  gap:clamp(14px,1.4vw,20px); margin:0; padding:0; list-style:none; }
/* the route into the full catalog, under the chapter's own action rather than
   beside it — see `.hl-rhw__all` for why it is flex rather than inline-flex */
.hl-hw2__all{ display:flex; width:fit-content; margin-top:var(--hl-s-5); }
/* .hl-pslot__ph defaults to light-on-dark, and this section is white. */
.hl-hw2 .hl-pslot__ph{ --hl-ph-name:var(--hl-text-dark); --hl-ph-note:var(--hl-text-muted); }
.hl-hw2 .hl-hcard__meta b{ display:block; font:700 var(--hl-fs-h4)/1.2 var(--hl-ff-display);
  color:var(--hl-text-dark); letter-spacing:-.02em; margin-bottom:6px; }
.hl-hw2 .hl-hcard__meta i{ display:block; font-size:var(--hl-fs-xs); line-height:1.55;
  color:var(--hl-text-muted); margin-top:0; }
/* dev--smart has no .hl-hcard scale in the homepage system — give it one.
   A scaled device still reserves full layout height, so margin-block claws the
   difference back and keeps the four cards the same height. */
.hl-hw2 .hl-hcard .hl-dev--smart{ --hl-k:.72; transform:scale(.72); margin-block:-30px; }
.hl-hw2 .hl-hcard .hl-dev--counter{ --hl-k:.86; transform:scale(.86); margin-block:-9px; }
.hl-hw2 .hl-hcard .hl-dev--portable{ --hl-k:.86; transform:scale(.86); margin-block:-13px; }
/* Fixed slot height rather than flex:1 — otherwise a card with a shorter
   caption gives its spare height to the slot and the placeholders stop
   aligning across the row. */
.hl-hw2 .hl-hcard{ --hl-hcard-media:200px; }
/* The slot is fixed here, so the CAPTION is the child that grows — which is
   what gives `.hl-hcard__link{margin-top:auto}` something to push against and
   holds "View details" on the card's bottom edge whatever the description does. */
.hl-hw2 .hl-hcard__meta{ flex:1; }

/* ── F9 · STEPS CHAPTER ─────────────────────────────────────────────────── */
/* "Here is what it depends on, and here is the method" — a copy column beside
   numbered steps. On Payment Processing it carries pricing, and shows no rate:
   pricing is a statement-analysis outcome, not a number on a marketing page. */
.hl-price{ position:relative; overflow:hidden; padding-block:var(--hl-sec-pad);
  background:linear-gradient(172deg,var(--hl-ink-850),var(--hl-ink-950)); }
.hl-price__shell{ position:relative; z-index:1;
  display:grid; grid-template-columns:minmax(0,1.06fr) minmax(0,.94fr);
  gap:clamp(32px,3.6vw,68px); align-items:start; }
/* The copy column opens the chapter, so it stays pinned to the top — the
   numeral has to sit on the section's spine. The step cards are the shorter
   column (353 against 514 on Payment Processing, 475 against 789 on Cash
   Discount), and left at `start` they stopped 161–314px above the copy's
   last line. Centred, the difference is shared top and bottom and reads as a
   composition rather than as a column that ran out. */
.hl-price__steps{ align-self:center; }
.hl-price__copy{ min-width:0; }
.hl-price__title{ font:800 clamp(2rem,3.4vw,3rem)/1.06 var(--hl-ff-display); color:#fff;
  letter-spacing:-.04em; margin-bottom:var(--hl-s-4); }
.hl-price__lede{ font-size:var(--hl-fs-lede); color:#fff; font-weight:500; margin-bottom:var(--hl-s-5);
  max-width:44ch; }
.hl-price__body{ font-size:var(--hl-fs-sm); line-height:1.75; color:var(--hl-text-light-2); max-width:56ch;
  margin-bottom:var(--hl-s-8); }
.hl-price__body p{ margin:0 0 1em; }
.hl-price__body p:last-child{ margin-bottom:0; }
.hl-price__body strong{ color:#fff; }
.hl-price__cta{ display:flex; flex-wrap:wrap; gap:14px; }
.hl-price__disc{ margin:var(--hl-s-5) 0 0; padding-top:var(--hl-s-4); border-top:1px solid var(--hl-line-dark);
  font-size:var(--hl-fs-micro); color:var(--hl-text-light-4); max-width:52ch; }

.hl-price__steps{ display:grid; gap:12px; margin:0; padding:0; list-style:none; }
.hl-price__steps li{
  position:relative; display:grid; grid-template-columns:auto minmax(0,1fr); gap:6px 16px;
  padding:20px 22px; border-radius:var(--hl-r-lg);
  background:rgba(255,255,255,.04); border:1px solid var(--hl-line-dark);
  transition:background var(--hl-t-med), border-color var(--hl-t-med);
}
.hl-price__steps li:hover{ background:rgba(255,255,255,.07); border-color:var(--hl-line-dark-2); }
.hl-pstep__n{ grid-row:1/span 2;
  font:700 var(--hl-fs-micro)/1 var(--hl-ff-mono); letter-spacing:.12em; color:var(--hl-red-400);
  padding-top:3px; }
.hl-price__steps b{ font:700 var(--hl-fs-h4)/1.2 var(--hl-ff-display); color:#fff; letter-spacing:-.02em; }
.hl-price__steps span:last-child{ font-size:var(--hl-fs-xs); line-height:1.62; color:var(--hl-text-light-3); }

/* ── F10 · WHY — FEATURE PANEL + ROWS ───────────────────────────────────── */
/* One feature panel carries the argument; the rest are compact rows. Six equal
   cards would say nothing about what matters most. */
.hl-why2{ position:relative; padding-block:var(--hl-sec-pad-sm); background:var(--hl-paper); }
.hl-why2__grid{ display:grid; grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);
  gap:clamp(18px,2vw,30px); align-items:start; }

.hl-wfeat{
  position:relative; overflow:hidden; padding:clamp(26px,2.8vw,38px);
  border-radius:var(--hl-r-2xl);
  background:linear-gradient(162deg,var(--hl-ink-750),var(--hl-ink-900) 62%,var(--hl-ink-950));
  border:1px solid var(--hl-line-dark-2); box-shadow:var(--hl-sh-lg);
}
.hl-wfeat h3{ font-size:var(--hl-fs-h3); color:#fff; margin-bottom:var(--hl-s-4); }
.hl-wfeat p{ font-size:var(--hl-fs-sm); line-height:1.72; color:var(--hl-text-light-2);
  margin-bottom:var(--hl-s-8); }
.hl-wfeat__viz{ position:relative; height:74px; }
.hl-wfeat__viz svg{ position:absolute; inset:0; width:100%; height:100%; }
.hl-wfeat__viz .hl-sroute{ stroke:rgba(255,255,255,.16); }
.hl-wfeat__viz .hl-spulse{ stroke:url(#hl-sgrad); }
.hl-wfeat__node{
  position:absolute; top:50%; left:var(--hl-x); transform:translate(-50%,-50%);
  padding:7px 12px; border-radius:var(--hl-r-pill); white-space:nowrap;
  background:var(--hl-ink-800); border:1px solid var(--hl-line-dark-2);
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:.06em; text-transform:uppercase;
  color:#fff;
}
.hl-wfeat__node:last-child{ border-color:rgba(229,84,78,.45); background:rgba(207,41,39,.18); }

.hl-wlist{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:12px; align-content:start;
  margin:0; padding:0; list-style:none; }
.hl-wlist li{
  display:grid; grid-template-columns:auto minmax(0,1fr); gap:5px 14px; padding:20px 22px;
  border-radius:var(--hl-r-lg); background:#fff; border:1px solid var(--hl-line);
  transition:transform var(--hl-t-med) var(--hl-e-out), box-shadow var(--hl-t-med), border-color var(--hl-t-med);
}
.hl-wlist li:hover{ transform:translateY(-4px); box-shadow:var(--hl-sh-md); border-color:var(--hl-line-2); }
/* an odd number of rows: the last one spans, so the block ends square */
.hl-wlist li:last-child:nth-child(odd){ grid-column:1/-1; }
.hl-wlist__ico{ grid-row:1/span 2; width:20px; height:20px; color:var(--hl-brand-red); padding-top:2px; }
.hl-wlist b{ font:700 var(--hl-fs-h4)/1.25 var(--hl-ff-display); color:var(--hl-text-dark); letter-spacing:-.02em; }
.hl-wlist span:last-child{ font-size:var(--hl-fs-xs); line-height:1.6; color:var(--hl-text-muted); }

/* ── F11 · FAQ CHAPTER ──────────────────────────────────────────────────── */
/* The approved treatment applied to the production FAQ block, which is
   <details>/<summary>: every answer is real crawlable text, it opens and closes
   with no JavaScript at all, and keyboard and screen-reader semantics come from
   the elements rather than from ARIA that has to be kept in step by hand. */
.hl-faq-sec{ position:relative; padding-block:var(--hl-sec-pad); background:#fff; }
.hl-faq-sec .hl-shell{ display:grid; grid-template-columns:minmax(0,.78fr) minmax(0,1.22fr);
  gap:clamp(32px,3.6vw,72px); align-items:start; }
/* ── TWO-COLUMN BALANCE ────────────────────────────────────────────────────
   `--hl-sticky-top` is the offset a travelling column needs to clear the
   sticky header AND the sticky page rail. `.hl-faq__lead` invented it inline
   and it works — measured on `/services/ach-echeck`, the lead pins at 186px
   and holds there through 450px of scrolling — so the FAQ chapter's "void" is
   a screenshot artefact rather than dead space a reader ever sees.

   The token is named here so the other short columns can use the same
   behaviour instead of each inventing a number. See the balance decisions
   recorded beside `.hl-price__steps`, `.hl-check` and `.hl-formsec__aside`. */
:root{ --hl-sticky-top: calc(var(--hl-nav-h) + var(--hl-rail-h) + 28px); }
.hl-faq__lead{ position:sticky; top:var(--hl-sticky-top); min-width:0; }
html:not(:has(.hl-rail)) .hl-faq__lead{ top:calc(var(--hl-nav-h) + 28px); }
.hl-faq__copy{ margin:var(--hl-s-5) 0 var(--hl-s-8); font-size:var(--hl-fs-sm); line-height:1.7;
  color:var(--hl-text-muted); max-width:38ch; }

.hl-faq-sec .hl-faq{ border-top:1px solid var(--hl-line); min-width:0; }
.hl-faq-sec .hl-faq__item{ border-bottom:1px solid var(--hl-line); }
.hl-faq-sec .hl-faq__question{
  display:flex; align-items:center; justify-content:space-between; gap:20px;
  width:100%; text-align:left; padding:22px 0; cursor:pointer; list-style:none;
  font:700 clamp(1rem,1.25vw,1.18rem)/1.4 var(--hl-ff-display); color:var(--hl-text-dark);
  letter-spacing:-.02em; transition:color var(--hl-t-fast);
}
.hl-faq-sec .hl-faq__question::-webkit-details-marker{ display:none; }
.hl-faq-sec .hl-faq__question:hover{ color:var(--hl-brand-red); }
/* Plus / minus drawn from two rules so it can rotate into a minus. */
.hl-faq-sec .hl-faq__icon{ position:relative; width:20px; height:20px; flex:none; }
.hl-faq-sec .hl-faq__icon::before,
.hl-faq-sec .hl-faq__icon::after{
  content:""; position:absolute; left:50%; top:50%; width:13px; height:1.8px; border-radius:2px;
  background:var(--hl-brand-red); transform:translate(-50%,-50%);
  transition:transform var(--hl-t-med) var(--hl-e-out), opacity var(--hl-t-med);
}
.hl-faq-sec .hl-faq__icon::after{ transform:translate(-50%,-50%) rotate(90deg); }
.hl-faq-sec .hl-faq__item[open] .hl-faq__icon::after{ transform:translate(-50%,-50%) rotate(0deg); opacity:0; }
.hl-faq-sec .hl-faq__answer{ overflow:hidden; }
.hl-faq-sec .hl-faq__answer .hl-rich{ padding:0 60px 24px 0; font-size:var(--hl-fs-sm); line-height:1.75;
  color:var(--hl-text-body); max-width:70ch; }
.hl-faq-sec .hl-faq__answer .hl-rich p{ margin:0 0 1em; }
.hl-faq-sec .hl-faq__answer .hl-rich p:last-child{ margin-bottom:0; }

/* ── F12 · RESPONSIVE ───────────────────────────────────────────────────── */
@media (max-width:1280px){
  .hl-track__stops{ grid-template-columns:repeat(3,minmax(0,1fr)); gap:14px; }
  .hl-track__line{ display:none; }
  .hl-stop::before{ display:none; }
}

@media (max-width:1120px){
  .hl-switch{ grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr); }
  .hl-spanel{ grid-template-columns:minmax(0,1fr); }
  /* `--art` and not `__art`: this centres a 280px device stage above the copy,
     which is right for illustrative artwork and wrong for a photograph that is
     meant to bleed to the panel's edges. Both variants carry `__art`, so the
     unscoped selector was capping the photo at 280px too. */
  .hl-spanel--art{ width:100%; max-width:280px; margin-inline:auto; order:-1; }
  .hl-why2__grid{ grid-template-columns:minmax(0,1fr); }
}

@media (max-width:1024px){
  :root{ --hl-rail-h:52px; }
  .hl-shero__shell{ grid-template-columns:minmax(0,1fr); gap:var(--hl-s-12); }
  .hl-shero__copy{ max-width:none; }
  .hl-shero__viz{ max-width:560px; }
  .hl-accv__stage{ aspect-ratio:460/320; }
  .hl-hw2__shell{ grid-template-columns:minmax(0,1fr); gap:var(--hl-s-12); }
  .hl-hw2__lede{ max-width:none; }
  .hl-price__shell{ grid-template-columns:minmax(0,1fr); gap:var(--hl-s-10); }
  .hl-faq-sec .hl-shell{ grid-template-columns:minmax(0,1fr); gap:var(--hl-s-10); }
  .hl-faq__lead{ position:static; }
  .hl-faq__copy{ max-width:none; }
  .hl-rail__title{ display:none; }
}

@media (max-width:900px){
  .hl-switch{ grid-template-columns:minmax(0,1fr); }
  .hl-switch__rail::before{ display:none; }
  .hl-switch__rail{ display:flex; overflow-x:auto; gap:8px; padding-bottom:6px; scrollbar-width:none; }
  .hl-switch__rail::-webkit-scrollbar{ display:none; }
  .hl-srow{ flex:none; width:232px; background:#fff; border-color:var(--hl-line);
    grid-template-columns:auto minmax(0,1fr); }
  .hl-srow__arrow{ display:none; }
  .hl-srow.is-active::after{ display:none; }
  .hl-srow.is-active{ border-color:var(--hl-brand-red); box-shadow:0 0 0 3px rgba(207,41,39,.1), var(--hl-sh-sm); }
  /* The head is a single column at every width now (§F4), so the only thing
     left to do here is step the numeral down with the rest of the type. The
     `grid-template-columns` overrides that used to live here would have
     reintroduced a second gap on top of the numeral's own margin. */
  .hl-ihead__n{ font-size:2rem; }
  .hl-binds__more{ align-self:start; }
  .hl-bpanel__cols{ grid-template-columns:minmax(0,1fr); }
  .hl-wlist{ grid-template-columns:minmax(0,1fr); }
}

@media (max-width:768px){
  .hl-track__stops{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .hl-hw2__grid{ grid-template-columns:repeat(var(--hl-row-sm, 2), minmax(0,1fr)); }
}

@media (max-width:640px){
  /* Mobile hero diagram: the same story told as a vertical spine. The absolute
     positioning and the SVG wires are dropped rather than squeezed. */
  .hl-accv{ padding:16px 16px 14px; }
  .hl-accv__stage{ aspect-ratio:auto; display:block; }
  .hl-accv__routes{ display:none; }
  /* grid-template-rows must be reset too, or the desktop rows keep stretching
     and leave a dead band under the channels */
  .hl-accv__in{ position:static; width:auto; height:auto;
    display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); grid-template-rows:auto; gap:8px; }
  .hl-cnode{ margin:0; padding:10px; border-radius:var(--hl-r-sm); }
  .hl-cnode i{ display:none; }
  .hl-accv__out{ position:static; margin-top:14px; padding-top:16px;
    display:grid; gap:10px; border-top:1px dashed var(--hl-line-dark-2); }
  .hl-corenode,.hl-onode{ position:static; height:auto; }
  .hl-corenode{ padding:14px; }
  .hl-onode{ padding:12px 14px; }

  .hl-shero__h1{ font-size:clamp(2rem,8.4vw,2.6rem); }
  .hl-shero__cta .hl-btn{ flex:1 1 auto; justify-content:center; }
  .hl-shero__chips li{ font-size:.62rem; padding:6px 10px; }

  .hl-rail__shell{ gap:var(--hl-s-4); }
  .hl-rail__cta{ display:none; }
  .hl-rail__list{ margin-inline:calc(var(--hl-gutter) * -1); padding-inline:var(--hl-gutter); }

  .hl-track__stops{ grid-template-columns:minmax(0,1fr); gap:10px; }
  .hl-stop{ padding:18px; }
  .hl-track__note{ padding:12px 16px; }

  .hl-spanel{ padding:20px; }
  .hl-slist li{ grid-template-columns:minmax(0,1fr); gap:4px; }
  .hl-spanel__art{ max-width:220px; padding:16px 10px; }

  .hl-hw2__grid{ grid-template-columns:repeat(var(--hl-row-sm, 2), minmax(0,1fr)); gap:10px; }
  .hl-hw2 .hl-hcard{ padding:16px 12px; }
  .hl-hw2 .hl-hcard{ --hl-hcard-media:172px; }
  .hl-hw2 .hl-hcard .hl-pslot{ margin-bottom:12px; }
  .hl-hw2 .hl-hcard .hl-dev--smart{ --hl-k:.56; transform:scale(.56); margin-block:-47px; }
  .hl-hw2 .hl-hcard .hl-dev--counter{ --hl-k:.7; transform:scale(.7); margin-block:-20px; }
  .hl-hw2 .hl-hcard .hl-dev--portable{ --hl-k:.72; transform:scale(.72); margin-block:-27px; }
  .hl-hw2 .hl-hcard .hl-dev--reader{ --hl-k:.9; transform:scale(.9); margin-block:-6px; }
  .hl-hw2 .hl-hcard__meta b{ font-size:.92rem; }
  .hl-hw2 .hl-hcard__meta i{ font-size:.72rem; }

  /* three pills will not sit on one route at phone width — drop the wire and
     let them wrap as a plain row */
  .hl-wfeat__viz{ height:auto; display:flex; flex-wrap:wrap; gap:8px;
    align-items:center; justify-content:center; }
  .hl-wfeat__viz svg{ display:none; }
  .hl-wfeat__node{ position:static; transform:none; }

  .hl-price__cta .hl-btn{ flex:1 1 auto; justify-content:center; }
  .hl-price__steps li{ padding:16px 18px; }
  .hl-faq-sec .hl-faq__question{ padding:18px 0; gap:14px; }
  .hl-faq-sec .hl-faq__answer .hl-rich{ padding-right:0; padding-bottom:20px; }
}

@media (max-width:430px){
  .hl-btab{ padding:10px 14px; font-size:var(--hl-fs-xs); }
  .hl-srow{ width:214px; padding:13px 14px; }
  .hl-crumb ol{ font-size:.62rem; gap:6px; }
}

@media (max-width:400px){
  .hl-accv__in{ grid-template-columns:minmax(0,1fr); }
  .hl-cnode i{ display:block; }
  /* the device cards stay 2-up even at 360 — one column would double the
     section height for no gain in legibility */
  .hl-hw2__grid{ gap:8px; }
  .hl-hw2 .hl-hcard{ padding:14px 10px; }
  .hl-hw2 .hl-hcard{ --hl-hcard-media:166px; }
  .hl-ihead__n{ font-size:1.75rem; }
}

/* ── F13 · REDUCED MOTION ───────────────────────────────────────────────── */
@media (prefers-reduced-motion:reduce){
  .hl-spulse,.hl-cnode,.hl-accv__live i,.hl-spanel__art .hl-dev{ animation:none !important; }
  .hl-spulse{ stroke-dashoffset:0; opacity:.55; }
  .hl-cnode{ background:rgba(255,255,255,.05); border-color:rgba(255,255,255,.09); }
  .hl-spanel.is-active,.hl-bpanel.is-active{ animation:none !important; }
}

/* ── G · INDUSTRY LAYER (industry pages) ──────────────────────────────────
   SOURCE OF TRUTH: public/prototype/industry/industry.css (approved).

   Layer 3 of 3. Ported by exactly the rules sections C and F already follow —
   `.foo` → `.hl-foo`, `--foo` → `--hl-foo`, `@keyframes foo` → `hls-foo`,
   `is-*`/`has-*` unchanged. Nothing above this line is redefined: the tokens,
   the reset, the primitives, the infrastructure language, the device kit and
   product slots, the nav/mega/drawer, the footer, the closing CTA and the
   preloader all come from section C, and the page rail, the breadcrumb, the
   chapter numerals, the short-path route family and the FAQ chapter all come
   from section F.

   Two deliberate deviations from a literal rename, both because production
   already owns the name:

     prototype `.offer`  → `.hl-ioffer`   `.hl-offer` is already the offer pill
                                          inside the homepage industry panel
                                          (section 11) and means something else.
     prototype `@keyframes hover` / `bob` → reused as `hls-hover` / `hls-bob`,
                                          which section C already defines with
                                          identical values.

   And one family renamed onto the component that already does the job, the
   same way the service layer reused `.hl-hcard`:

     prototype `.hcard` (hardware row)    → `.hl-hcard` (section 09's card)

   An industry page differs from a service page in one way that matters: it
   sells an operating environment rather than a capability list. So the
   centrepiece is the venue drawn as a payment system, and the supporting
   chapters carry more texture.

     G0 · industry hero + product stage
     G1 · the floor (venue map)
     G2 · hardware showcase
     G3 · benefits bento
     G4 · promotional offer band
     G5 · cash discount + check visual
     G6 · funding strip
     G7 · why (compact)
     G8 · responsive
     G9 · reduced motion                                                     */

/* ── G0 · INDUSTRY HERO ─────────────────────────────────────────────────── */
/* `.hl-shero` already supplies the nav pull-up and the dark chapter; only the
   mood and the artwork column change. */
.hl-ihero{
  background:
    radial-gradient(1150px 660px at 84% 2%, #221C4E 0%, transparent 60%),
    radial-gradient(880px 600px at 2% 96%, #16194C 0%, transparent 58%),
    linear-gradient(168deg,#0C0F2A 0%,#080A1E 55%,#05060F 100%);
}
.hl-ihero .hl-shero__shell{ grid-template-columns:1.04fr .96fr; align-items:center; }

/* An industry hero with NO stage device.
   `hero-industry.php` renders no artwork column when the product slot produces
   nothing — no media, no device key — so the two-column shell above would leave
   its whole right half empty and squeeze the copy into 600px beside it. One
   column, and the copy is allowed to use it; the measures below keep the
   headline and lede readable rather than letting them run the full 1280px.
   This applies to any page built on this hero without a stage device, not only
   to the equipment catalog. */
.hl-ihero--nostage .hl-shero__shell{ grid-template-columns:minmax(0,1fr); }
.hl-ihero--nostage .hl-shero__copy{ max-width:none; }
.hl-ihero--nostage .hl-shero__h1{ max-width:24ch; }
.hl-ihero--nostage .hl-shero__lede{ max-width:62ch; }

/* Offer flag — the promotional claim restated inline, linking to the offer
   chapter. Rendered only when the destination actually resolves. */
.hl-oflag{
  display:inline-flex; align-items:center; gap:12px; margin-top:var(--hl-s-8);
  padding:11px 16px 11px 12px; border-radius:var(--hl-r-pill);
  background:rgba(207,41,39,.12); border:1px solid rgba(229,84,78,.34);
  font-size:var(--hl-fs-xs); color:var(--hl-text-light-2);
  transition:background var(--hl-t-med), border-color var(--hl-t-med),
             transform var(--hl-t-med) var(--hl-e-out);
}
.hl-oflag:hover{ background:rgba(207,41,39,.2); border-color:rgba(229,84,78,.6);
  transform:translateY(-2px); }
.hl-oflag__tag{ padding:4px 9px; border-radius:var(--hl-r-xs); background:rgba(207,41,39,.3);
  color:#fff; font:700 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; }
.hl-oflag__txt em{ color:#fff; font-weight:700; font-style:normal; }
.hl-oflag .hl-arrow{ color:var(--hl-red-300); transition:transform var(--hl-t-med) var(--hl-e-out); }
.hl-oflag:hover .hl-arrow{ transform:translateX(3px); }

/* Product stage: the hero device with floating capability labels. This is the
   industry equivalent of the service hero's abstract acceptance diagram — it
   shows the thing rather than the flow. Kept darker than the device silhouette
   on purpose: the devices paint in the same navy family and a navy card would
   swallow them. */
.hl-rstage{
  position:relative; padding:26px 22px 16px; border-radius:var(--hl-r-2xl); overflow:hidden;
  background:linear-gradient(158deg,rgba(30,34,92,.5),rgba(4,5,14,.9) 72%);
  border:1px solid var(--hl-line-dark-2); box-shadow:var(--hl-sh-glass);
  backdrop-filter:blur(10px);
}
.hl-rstage__glow{
  position:absolute; left:50%; top:46%; width:74%; aspect-ratio:1; transform:translate(-50%,-50%);
  border-radius:50%; background:radial-gradient(circle, rgba(207,41,39,.2), transparent 62%);
  filter:blur(34px); pointer-events:none;
}
.hl-rstage__routes{ position:absolute; inset:0; width:100%; height:100%; }

.hl-rstage__slot{ position:relative; z-index:2; min-height:250px; }
/* transform-scaled devices reserve full layout height; margin-block claws it back */
.hl-rstage__slot .hl-dev{ --hl-k:1.16; transform:scale(1.16);
  margin-block:14px; animation:hls-hover 7s var(--hl-e-inout) infinite; }
.hl-rstage__slot::before{
  content:""; position:absolute; left:50%; bottom:34px; width:52%; height:16px;
  transform:translateX(-50%); border-radius:50%;
  background:radial-gradient(ellipse, rgba(0,0,0,.55), transparent 70%); filter:blur(6px);
}

.hl-rlabel{
  position:absolute; z-index:3; padding:7px 12px; border-radius:var(--hl-r-sm); white-space:nowrap;
  background:rgba(10,12,34,.84); border:1px solid var(--hl-line-dark-2);
  backdrop-filter:blur(10px); box-shadow:0 14px 30px -14px rgba(0,0,0,.85);
  font:500 var(--hl-fs-xs)/1 var(--hl-ff-body); color:#fff;
  animation:hls-bob 7s var(--hl-e-inout) infinite;
}
.hl-rlabel::before{
  content:""; position:absolute; top:50%; width:11px; height:1px; background:rgba(229,84,78,.7);
}
.hl-rlabel--1{ top:16%;  left:2%;  animation-delay:-.4s; }
.hl-rlabel--1::before{ right:-11px; }
.hl-rlabel--2{ top:30%;  right:1%; animation-delay:-2.1s; }
.hl-rlabel--2::before{ left:-11px; }
.hl-rlabel--3{ bottom:30%; left:1%; animation-delay:-3.8s; }
.hl-rlabel--3::before{ right:-11px; }
.hl-rlabel--4{ bottom:19%; right:2%; animation-delay:-5.4s; }
.hl-rlabel--4::before{ left:-11px; }

.hl-rstage__foot{
  position:relative; z-index:3; margin:10px 0 0; padding-top:11px;
  border-top:1px solid var(--hl-line-dark); text-align:center;
  font-size:var(--hl-fs-micro); color:var(--hl-text-light-4);
}

/* ── G1 · THE FLOOR ─────────────────────────────────────────────────────── */
/* The venue as a payment system. Same fixed-aspect-stage technique as the
   service hero diagram: the SVG coordinate space is 720×420 and every hotspot
   is placed with percentages derived from it, so the wires and the CSS boxes
   cannot drift apart at any width. The renderer owns those coordinates — they
   come from an approved plan chosen by station count, never from admin input. */
.hl-floor{ position:relative; overflow:hidden; padding-block:var(--hl-sec-pad);
  background:linear-gradient(178deg,var(--hl-ink-900),var(--hl-ink-850) 55%,var(--hl-ink-900)); }
.hl-floor .hl-shell{ position:relative; z-index:1; }

/* minmax(0,…) on every track and min-width:0 on both children: a plain `1fr`
   is minmax(auto,1fr), and the auto minimum would size the column to the widest
   STACKED panel instead of the container. The section clips overflow, so that
   failure is silent — the card just truncates. Bridge rule E8. */
.hl-floor__wrap{
  display:grid; grid-template-columns:minmax(0,1.18fr) minmax(0,.82fr);
  gap:clamp(20px,2.4vw,36px); align-items:start;
}
.hl-floor__stage,.hl-floor__panels{ min-width:0; }

/* `.hl-floor__map` is the fixed-aspect positioning context; `.hl-floor__stage`
   is a plain block so the caption below the plan stays in normal flow. */
.hl-floor__stage{ position:relative; width:100%; }
.hl-floor__map{ position:relative; width:100%; aspect-ratio:720/460; }
.hl-floor__plan{ position:absolute; inset:0; width:100%; height:100%; }
.hl-floor__room{ stroke:rgba(255,255,255,.16); stroke-width:1.4; fill:rgba(255,255,255,.018); }
.hl-floor__div{ stroke:rgba(255,255,255,.07); stroke-width:1; stroke-dasharray:4 7; }
.hl-floor .hl-sroute{ stroke:rgba(255,255,255,.13); }

.hl-floor__roomtag{
  position:absolute; left:4.2%; top:7.1%; transform:translateY(-140%);
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-mono); letter-spacing:.14em; text-transform:uppercase;
  color:var(--hl-text-light-4);
}

.hl-floor__spots{ position:absolute; inset:0; }
.hl-spot{
  position:absolute; left:var(--hl-x); top:var(--hl-y); transform:translate(-50%,-50%);
  display:inline-flex; align-items:center; gap:9px; padding:9px 14px 9px 11px;
  border-radius:var(--hl-r-pill); white-space:nowrap;
  background:rgba(12,15,42,.9); border:1px solid var(--hl-line-dark-2);
  backdrop-filter:blur(8px);
  font:600 var(--hl-fs-xs)/1 var(--hl-ff-display); color:var(--hl-text-light-2); letter-spacing:-.01em;
  transition:color var(--hl-t-med), background var(--hl-t-med), border-color var(--hl-t-med),
             box-shadow var(--hl-t-med), transform var(--hl-t-med) var(--hl-e-out);
}
.hl-spot i{
  width:8px; height:8px; border-radius:50%; flex:none;
  background:var(--hl-text-light-4); transition:background var(--hl-t-med), box-shadow var(--hl-t-med);
}
.hl-spot:hover{ color:#fff; border-color:rgba(255,255,255,.3);
  transform:translate(-50%,-50%) translateY(-2px); }
.hl-spot.is-active{
  color:#fff; background:linear-gradient(160deg,rgba(207,41,39,.34),rgba(42,45,124,.7));
  border-color:rgba(229,84,78,.55);
  box-shadow:0 0 0 4px rgba(207,41,39,.14), 0 18px 36px -18px rgba(0,0,0,.9);
}
.hl-spot.is-active i{ background:var(--hl-red-400); box-shadow:0 0 12px rgba(229,84,78,.9); }
/* the destination node reads as the account, not as another station */
.hl-spot--end{ background:rgba(47,214,163,.09); border-color:rgba(47,214,163,.28); }
.hl-spot--end i{ background:var(--hl-ok); }
.hl-spot--end.is-active{ background:linear-gradient(160deg,rgba(47,214,163,.28),rgba(42,45,124,.68));
  border-color:rgba(47,214,163,.6); box-shadow:0 0 0 4px rgba(47,214,163,.12),
  0 18px 36px -18px rgba(0,0,0,.9); }
.hl-spot--end.is-active i{ background:var(--hl-ok); box-shadow:0 0 12px rgba(47,214,163,.9); }

/* The thesis line, under the plan. */
.hl-floor__foot{ margin:22px 0 0; display:flex; flex-wrap:wrap; gap:10px; padding:0; list-style:none; }
.hl-floor__foot span{
  padding:9px 15px; border-radius:var(--hl-r-pill);
  background:rgba(255,255,255,.05); border:1px solid var(--hl-line-dark);
  font:500 var(--hl-fs-xs)/1 var(--hl-ff-body); color:var(--hl-text-light-2);
}

/* Detail panel — dark glass, so the chapter stays dark. All panels stack in one
   grid cell and hide with `visibility` rather than `display`, so the container
   is always the height of the tallest station and switching never moves the
   page. That matters more here than anywhere else: the switcher IS the
   chapter. */
.hl-floor__panels{ display:grid; grid-template-columns:minmax(0,1fr); min-width:0; }
.hl-fpanel{
  grid-area:1/1; min-width:0;
  display:grid; grid-template-rows:auto auto; gap:var(--hl-s-6); align-content:start;
  padding:clamp(22px,2.4vw,32px); border-radius:var(--hl-r-2xl);
  background:linear-gradient(160deg,rgba(42,45,124,.3),rgba(10,12,34,.72));
  border:1px solid var(--hl-line-dark-2); box-shadow:var(--hl-sh-glass);
  backdrop-filter:blur(10px);
  visibility:hidden; opacity:0; pointer-events:none; transform:translateY(9px);
  transition:opacity 320ms var(--hl-e-out), transform 420ms var(--hl-e-out), visibility 320ms;
}
.hl-fpanel.is-active{ visibility:visible; opacity:1; pointer-events:auto; transform:none; }
.hl-fpanel__k{ display:block; margin-bottom:var(--hl-s-3);
  font:700 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wider);
  text-transform:uppercase; color:var(--hl-red-300); }
.hl-fpanel__body h3{ font-size:var(--hl-fs-h3); color:#fff; margin-bottom:var(--hl-s-4); }
.hl-fpanel__body p{ margin-bottom:var(--hl-s-6); font-size:var(--hl-fs-sm); line-height:1.72;
  color:var(--hl-text-light-2); }
.hl-fspec{ display:grid; gap:1px; margin:0; padding:0; list-style:none; }
.hl-fspec li{ display:grid; grid-template-columns:78px minmax(0,1fr); gap:14px; align-items:baseline;
  padding:11px 0; border-top:1px solid var(--hl-line-dark); }
.hl-fspec li:last-child{ border-bottom:1px solid var(--hl-line-dark); }
.hl-fspec b{ font:600 var(--hl-fs-micro)/1.5 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-text-light-4); }
.hl-fspec span{ font-size:var(--hl-fs-xs); line-height:1.6; color:#fff; }

/* The panel's device slot. `.hl-pslot` is a grid in section C; `display:contents`
   lets the art frame own the two rows so artwork and caption keep the approved
   vertical rhythm whether the slot renders a silhouette or a photograph. */
.hl-fpanel__art{
  position:relative; display:grid; grid-template-rows:1fr auto; justify-items:center;
  align-items:center; gap:12px; height:180px;
  border-radius:var(--hl-r-xl); background:rgba(255,255,255,.03);
  border:1px solid var(--hl-line-dark);
}
.hl-fpanel__art .hl-pslot{ display:contents; }
.hl-fpanel__art .hl-dev{ --hl-k:.8; transform:scale(.8); animation:hls-hover 7s var(--hl-e-inout) infinite; }
.hl-fpanel__art .hl-dev--rest{ --hl-k:.72; transform:scale(.72); margin-block:-23px; }
.hl-fpanel__art .hl-dev--counter{ --hl-k:.78; transform:scale(.78); margin-block:-15px; }
.hl-fpanel__art .hl-dev--portable{ --hl-k:.72; transform:scale(.72); margin-block:-27px; }
.hl-fpanel__art .hl-dev--reader{ --hl-k:.94; transform:scale(.94); margin-block:-4px; }
.hl-fpanel__art .hl-dev--invoice{ --hl-k:.74; transform:scale(.74); margin-block:-19px; }
.hl-fpanel__art .hl-dev--smart{ --hl-k:.6; transform:scale(.6); margin-block:-40px; }
.hl-fpanel__art .hl-dev--pump{ --hl-k:.6; transform:scale(.6); margin-block:-42px; }
.hl-fpanel__art img{ max-height:128px; width:auto; object-fit:contain; }

/* The station with no image at all — `Show image` off, or nothing to draw. The
   same rule as `.hl-spanel--textonly` and for the same reason: the panel's
   second track and the `--hl-s-6` gap beside it are laid out even when nothing
   occupies them, so the track is removed rather than the item hidden. Declared
   once here and re-declared in each responsive block below, because those
   blocks re-state `grid-template-columns` on `.hl-fpanel` itself. */
.hl-fpanel--textonly{ grid-template-rows:auto; grid-template-columns:minmax(0,1fr); gap:0; }

/* ── G2 · HARDWARE SHOWCASE ─────────────────────────────────────────────── */
.hl-rhw{ position:relative; padding-block:var(--hl-sec-pad);
  background:linear-gradient(180deg,#fff,var(--hl-paper) 82%); }
.hl-rhw__more{ align-self:end; padding-bottom:6px; }

.hl-rhw__feature{
  display:grid; grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);
  gap:clamp(24px,3vw,54px); align-items:center;
  padding:clamp(24px,2.6vw,40px); margin-bottom:clamp(14px,1.4vw,20px);
  border-radius:var(--hl-r-2xl); background:#fff; border:1px solid var(--hl-line);
  box-shadow:var(--hl-sh-lg);
}
.hl-rhw__art{
  position:relative; display:grid; place-items:center; min-height:280px;
  border-radius:var(--hl-r-xl);
  background:radial-gradient(ellipse 70% 60% at 50% 42%, var(--hl-paper-2), var(--hl-paper) 70%);
  border:1px solid var(--hl-line);
}
.hl-rhw__art::before{
  content:""; position:absolute; left:50%; bottom:44px; width:46%; height:18px;
  transform:translateX(-50%); border-radius:50%;
  background:radial-gradient(ellipse, rgba(10,14,36,.22), transparent 70%); filter:blur(5px);
}
.hl-rhw__art .hl-pslot{ position:relative; z-index:1; }
.hl-rhw__art .hl-dev{ animation:hls-hover 6.5s var(--hl-e-inout) infinite; }
.hl-rhw__meta{ min-width:0; }
.hl-rhw__meta h3{ font-size:var(--hl-fs-h3); margin-bottom:var(--hl-s-4); }
.hl-rhw__meta p{ font-size:var(--hl-fs-sm); line-height:1.7; color:var(--hl-text-muted);
  margin-bottom:var(--hl-s-6); max-width:46ch; }
.hl-rhw__meta .hl-hspec{ margin-bottom:var(--hl-s-8); }

/* Rows share one height for the same reason `.hl-hw2__grid` does — this grid is
   four columns at desktop and two below, so the moment it has more than one row
   the rows size independently and the cards' bottom edges stop agreeing. */
.hl-rhw__row{ display:grid; grid-template-columns:repeat(var(--hl-row-n, 4), minmax(0,1fr)); grid-auto-rows:1fr;
  gap:clamp(12px,1.3vw,18px); margin:0; padding:0; list-style:none; }
.hl-rhw__row > li{ min-width:0; }
.hl-rhw .hl-hcard__meta b{ display:block; margin-bottom:6px;
  font:700 var(--hl-fs-h4)/1.2 var(--hl-ff-display); color:var(--hl-text-dark);
  letter-spacing:-.02em; }
.hl-rhw .hl-hcard__meta i{ display:block; margin:0; font-size:var(--hl-fs-xs); line-height:1.55;
  color:var(--hl-text-muted); font-style:normal; }
/* `.hl-pslot__ph` defaults to light-on-dark; this chapter is white. */
.hl-rhw .hl-pslot__ph{ --hl-ph-name:var(--hl-text-dark); --hl-ph-note:var(--hl-text-muted); }
/* fixed slot height so the placeholders align across the row regardless of how
   many lines each caption takes */
.hl-rhw .hl-hcard .hl-pslot{ flex:none; height:190px; min-height:0; }
/* Fixed slot, growing caption — see `.hl-hw2 .hl-hcard__meta`. */
.hl-rhw .hl-hcard__meta{ flex:1; }
.hl-rhw .hl-hcard .hl-dev--smart{ --hl-k:.7; transform:scale(.7); margin-block:-32px; }
.hl-rhw .hl-hcard .hl-dev--counter{ --hl-k:.84; transform:scale(.84); margin-block:-11px; }
.hl-rhw .hl-hcard .hl-dev--portable{ --hl-k:.84; transform:scale(.84); margin-block:-15px; }
.hl-rhw .hl-hcard .hl-dev--reader{ --hl-k:1; transform:scale(1); }
.hl-rhw .hl-hcard .hl-dev--rest{ --hl-k:.7; transform:scale(.7); margin-block:-34px; }
.hl-rhw .hl-hcard .hl-dev--pump{ --hl-k:.7; transform:scale(.7); margin-block:-34px; }
.hl-rhw .hl-hcard .hl-dev--invoice{ --hl-k:.8; transform:scale(.8); margin-block:-16px; }

.hl-rhw__note{
  margin:clamp(16px,1.6vw,22px) 0 0; padding:15px 18px; border-radius:var(--hl-r-md);
  background:#fff; border:1px solid var(--hl-line); border-left:3px solid var(--hl-brand-red);
  font-size:var(--hl-fs-xs); line-height:1.6; color:var(--hl-text-dark);
}
/* the route into the full catalog, after the range. `display:flex` rather than
   the button's inline-flex so it takes its own line; `width:fit-content` so it
   still hugs its text and `.hl-btn--link`'s underline stays the width of the
   words rather than the column. */
.hl-rhw__all{ display:flex; width:fit-content; margin-top:clamp(16px,1.6vw,22px); }

/* ── G3 · BENEFITS BENTO ────────────────────────────────────────────────── */
.hl-ben{ position:relative; padding-block:var(--hl-sec-pad-sm); background:var(--hl-paper); }
.hl-bento{ display:grid; grid-template-columns:repeat(6,minmax(0,1fr)); gap:clamp(12px,1.3vw,18px);
  margin:0; padding:0; list-style:none; }
.hl-btile{
  position:relative; min-width:0; padding:clamp(20px,2.2vw,30px); border-radius:var(--hl-r-2xl);
  background:#fff; border:1px solid var(--hl-line);
  transition:transform var(--hl-t-med) var(--hl-e-out), box-shadow var(--hl-t-med),
             border-color var(--hl-t-med);
}
.hl-btile:hover{ transform:translateY(-5px); box-shadow:var(--hl-sh-md); border-color:var(--hl-line-2); }
.hl-btile__n{
  display:block; margin-bottom:var(--hl-s-4);
  font:700 var(--hl-fs-micro)/1 var(--hl-ff-mono); letter-spacing:.14em; color:var(--hl-brand-red);
}
.hl-btile h3{ font-size:var(--hl-fs-h4); margin-bottom:var(--hl-s-3); }
.hl-btile p{ margin:0; font-size:var(--hl-fs-xs); line-height:1.65; color:var(--hl-text-muted); }
.hl-btile--lead{ grid-column:span 4; }
.hl-btile--lead h3{ font-size:var(--hl-fs-h3); }
.hl-btile--lead p{ font-size:var(--hl-fs-sm); line-height:1.72; max-width:56ch; }
.hl-btile--dark{
  grid-column:span 2; color:#fff;
  background:linear-gradient(162deg,var(--hl-ink-750),var(--hl-ink-900) 62%,var(--hl-ink-950));
  border-color:var(--hl-line-dark-2);
}
.hl-btile--dark h3{ color:#fff; }
.hl-btile--dark p{ color:var(--hl-text-light-2); }
.hl-btile--dark .hl-btile__n{ color:var(--hl-red-400); }
.hl-btile__chips{ display:flex; flex-wrap:wrap; gap:6px; margin:var(--hl-s-5) 0 0; padding:0;
  list-style:none; }
.hl-btile__chips li{
  padding:5px 10px; border-radius:var(--hl-r-xs); background:rgba(255,255,255,.06);
  border:1px solid var(--hl-line-dark); font-size:var(--hl-fs-micro); color:var(--hl-text-light-2);
}
.hl-bento > .hl-btile:not(.hl-btile--lead):not(.hl-btile--dark){ grid-column:span 2; }

/* The comparison visual on the lead tile — a COUNT, deliberately not a timing
   claim, which is why its caption is rendered with it rather than optional. */
.hl-turn{ margin-top:var(--hl-s-6); padding-top:var(--hl-s-5); border-top:1px solid var(--hl-line); }
.hl-turn__row{ display:grid; grid-template-columns:130px minmax(0,1fr); gap:14px; align-items:center;
  margin-bottom:10px; }
.hl-turn__k{ font:600 var(--hl-fs-micro)/1.4 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-text-muted); }
.hl-turn__bar{ display:flex; gap:6px; }
.hl-turn__bar i{ height:10px; border-radius:5px; flex:0 0 46px;
  background:linear-gradient(90deg,var(--hl-navy-600),var(--hl-navy-400)); }
.hl-turn__bar--fast i{ background:linear-gradient(90deg,var(--hl-red-600),var(--hl-red-400)); }
.hl-turn__note{ margin:12px 0 0 !important; font-size:var(--hl-fs-micro) !important;
  color:var(--hl-text-muted); opacity:.8; }

/* ── G4 · PROMOTIONAL OFFER BAND ────────────────────────────────────────── */
/* `.hl-offer` is taken (the homepage industry panel's offer pill), so the
   approved band is `.hl-ioffer`. */
.hl-ioffer{ position:relative; overflow:hidden; padding-block:var(--hl-sec-pad);
  background:linear-gradient(172deg,var(--hl-ink-850),var(--hl-ink-950)); }
.hl-ioffer__shell{ position:relative; z-index:1; }
/* The offer chapter's numeral sits on the page spine, left-aligned with every
   other chapter head, above the centred card rather than inside it. See the
   note in `blocks/promotion-offer.php`. */
.hl-ioffer__n{ margin-bottom:var(--hl-s-8); text-align:left; }
.hl-ioffer__card{
  max-width:860px; margin-inline:auto; text-align:center;
  padding:clamp(30px,3.4vw,54px) clamp(24px,3vw,58px); border-radius:var(--hl-r-3xl);
  background:linear-gradient(158deg,rgba(207,41,39,.14),rgba(42,45,124,.32) 52%,rgba(10,12,34,.6));
  border:1px solid rgba(229,84,78,.3);
  box-shadow:var(--hl-sh-xl), inset 0 1px 0 rgba(255,255,255,.12);
  backdrop-filter:blur(12px);
}
.hl-ioffer__tag{
  display:inline-block; margin-bottom:var(--hl-s-6); padding:6px 13px; border-radius:var(--hl-r-pill);
  background:rgba(207,41,39,.26); border:1px solid rgba(229,84,78,.5); color:#fff;
  font:700 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase;
}
.hl-ioffer__amt{ display:flex; align-items:baseline; justify-content:center; gap:14px;
  margin:0 0 var(--hl-s-5); }
.hl-ioffer__amt span{ font:600 var(--hl-fs-sm)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-text-light-3); }
.hl-ioffer__amt b{
  font:800 clamp(3rem,6vw,5rem)/.9 var(--hl-ff-display); color:#fff; letter-spacing:-.05em;
  font-variant-numeric:tabular-nums; text-shadow:0 22px 54px rgba(0,0,0,.6);
}
.hl-ioffer__title{ font:700 clamp(1.3rem,2vw,1.8rem)/1.3 var(--hl-ff-display); color:#fff;
  letter-spacing:-.025em; margin-bottom:var(--hl-s-4); }
.hl-ioffer__copy{ max-width:58ch; margin-inline:auto; font-size:var(--hl-fs-sm); line-height:1.72;
  color:var(--hl-text-light-2); margin-bottom:var(--hl-s-8); }

.hl-ioffer__pts{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:1px;
  text-align:left; margin:0 0 var(--hl-s-8); padding:0; list-style:none;
  background:var(--hl-line-dark); border:1px solid var(--hl-line-dark);
  border-radius:var(--hl-r-md); overflow:hidden; }
.hl-ioffer__pts li{ padding:16px 18px; background:rgba(10,12,34,.42); min-width:0; }
.hl-ioffer__pts b{ display:block; margin-bottom:6px;
  font:600 var(--hl-fs-micro)/1.5 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-red-300); }
.hl-ioffer__pts span{ font-size:var(--hl-fs-xs); line-height:1.6; color:#fff; }

.hl-ioffer__cta{ display:flex; flex-wrap:wrap; justify-content:center; gap:14px; }
.hl-ioffer__disc{ margin:var(--hl-s-8) 0 0; padding-top:var(--hl-s-5);
  border-top:1px solid var(--hl-line-dark);
  font-size:var(--hl-fs-micro); line-height:1.6; color:var(--hl-text-light-4); }

/* ── G5 · CASH DISCOUNT ─────────────────────────────────────────────────── */
/* No rate, no percentage and no worked figures. A cash-vs-card pair with real
   numbers publishes an effective rate, which is exactly what this site must
   never do — so the amount cells are a fixed token and no field can hold a
   number. */
.hl-cd{ position:relative; padding-block:var(--hl-sec-pad); background:#fff; }
.hl-cd__shell{ display:grid; grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr);
  gap:clamp(30px,3.6vw,66px); align-items:start; }
.hl-cd__copy{ min-width:0; }
.hl-cd__lede{ font-size:var(--hl-fs-lede); line-height:1.65; color:var(--hl-text-dark);
  margin:var(--hl-s-5) 0 var(--hl-s-8); max-width:52ch; }
.hl-cdlist{ display:grid; gap:1px; margin:0 0 var(--hl-s-8); padding:0; list-style:none; }
.hl-cdlist li{ padding:16px 0; border-top:1px solid var(--hl-line); }
.hl-cdlist li:last-child{ border-bottom:1px solid var(--hl-line); }
.hl-cdlist b{ display:block; margin-bottom:5px; font:700 var(--hl-fs-h4)/1.3 var(--hl-ff-display);
  color:var(--hl-text-dark); letter-spacing:-.02em; }
.hl-cdlist span{ font-size:var(--hl-fs-xs); line-height:1.65; color:var(--hl-text-muted); }
.hl-cd__cta{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--hl-s-6); }

/* The receipt is what the copy beside it is describing, and the copy is more
   than twice as tall (893 against 334 on an industry page), so the receipt
   travels with the reader instead of stopping 559px short. Same behaviour,
   same offset token as the FAQ lead. */
.hl-check{
  position:sticky; top:var(--hl-sticky-top); padding:24px 24px 20px; border-radius:var(--hl-r-lg);
  background:#fff; border:1px solid var(--hl-line); box-shadow:var(--hl-sh-lg);
  max-width:400px; margin-inline:auto; width:100%;
}
.hl-check::after{
  content:""; position:absolute; left:0; right:0; bottom:-9px; height:10px;
  background:repeating-linear-gradient(135deg,#fff 0 9px,transparent 9px 18px);
  filter:drop-shadow(0 2px 1px rgba(10,14,36,.08));
}
.hl-check__head{ display:flex; justify-content:space-between; align-items:baseline;
  padding-bottom:14px; border-bottom:1px dashed var(--hl-line-2);
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-body); letter-spacing:var(--hl-ls-wide);
  text-transform:uppercase; color:var(--hl-text-muted); }
.hl-check__mono{ font-family:var(--hl-ff-mono); letter-spacing:.08em; }
.hl-check__items{ display:grid; gap:14px; padding:18px 0; margin:0; list-style:none; }
.hl-check__items li{ display:flex; align-items:center; justify-content:space-between; gap:16px; }
.hl-check__items i{ height:8px; width:var(--hl-w); border-radius:4px; background:var(--hl-paper-2); }
.hl-check__items em{ font:400 var(--hl-fs-xs)/1 var(--hl-ff-mono); color:var(--hl-text-muted);
  font-style:normal; }
.hl-check__rule{ height:1px; background:var(--hl-line); margin-bottom:4px; }
.hl-check__price{ display:flex; justify-content:space-between; align-items:baseline;
  padding:12px 0; border-bottom:1px solid var(--hl-line); }
.hl-check__price span{ font:600 var(--hl-fs-sm)/1 var(--hl-ff-display); color:var(--hl-text-dark); }
.hl-check__price b{ font:700 1.1rem/1 var(--hl-ff-mono); color:var(--hl-text-muted); }
.hl-check__price--card{ border-bottom:0; }
.hl-check__price--card span,.hl-check__price--card b{ color:var(--hl-brand-red); }
.hl-check__foot{ margin-top:14px; padding-top:13px; border-top:1px dashed var(--hl-line-2);
  font-size:var(--hl-fs-micro); line-height:1.55; color:var(--hl-text-muted); }

/* ── G6 · FUNDING STRIP ─────────────────────────────────────────────────── */
.hl-rfund{ position:relative; overflow:hidden; padding-block:var(--hl-sec-pad-sm);
  background:linear-gradient(178deg,var(--hl-ink-850),var(--hl-ink-950) 70%); }
.hl-rfund .hl-shell{ position:relative; z-index:1; }
.hl-rfund__more{ align-self:end; padding-bottom:6px; }
.hl-rfund__grid{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(12px,1.3vw,18px); margin:0; padding:0; list-style:none; }
.hl-rfund__grid li{
  min-width:0; display:grid; grid-template-columns:auto minmax(0,1fr); gap:6px 14px;
  padding:22px 22px 24px; border-radius:var(--hl-r-lg);
  background:rgba(255,255,255,.04); border:1px solid var(--hl-line-dark);
  transition:background var(--hl-t-med), border-color var(--hl-t-med),
             transform var(--hl-t-med) var(--hl-e-out);
}
.hl-rfund__grid li:hover{ background:rgba(255,255,255,.075); border-color:var(--hl-line-dark-2);
  transform:translateY(-4px); }
.hl-rfund__ico{ grid-row:1/span 2; width:20px; height:20px; color:var(--hl-red-400); padding-top:2px; }
.hl-rfund__grid b{ font:700 var(--hl-fs-h4)/1.25 var(--hl-ff-display); color:#fff;
  letter-spacing:-.02em; }
.hl-rfund__grid span:last-child{ font-size:var(--hl-fs-xs); line-height:1.6;
  color:var(--hl-text-light-3); }
.hl-rfund__note{ margin:var(--hl-s-8) 0 0; padding-top:var(--hl-s-5);
  border-top:1px solid var(--hl-line-dark);
  font-size:var(--hl-fs-micro); line-height:1.6; color:var(--hl-text-light-4); max-width:78ch; }

/* ── G7 · WHY (compact) ─────────────────────────────────────────────────── */
/* A hairline definition list rather than another card grid — this chapter sits
   between two heavier ones and should read quickly. */
.hl-rwhy{ position:relative; padding-block:var(--hl-sec-pad-sm); background:var(--hl-paper); }
.hl-rwhy__shell{ display:grid; grid-template-columns:minmax(0,.8fr) minmax(0,1.2fr);
  gap:clamp(28px,3.4vw,64px); align-items:start; }
.hl-rwhy__lead{ min-width:0; }
.hl-rwhy__copy{ margin:var(--hl-s-5) 0 0; font-size:var(--hl-fs-sm); line-height:1.7;
  color:var(--hl-text-muted); max-width:40ch; }
.hl-rwhy__list{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:0 clamp(24px,2.6vw,44px); margin:0; }
.hl-rwhy__list > div{ min-width:0; padding:20px 0; border-top:1px solid var(--hl-line-2); }
.hl-rwhy__list dt{
  display:flex; align-items:baseline; gap:10px; margin-bottom:8px;
  font:700 var(--hl-fs-h4)/1.3 var(--hl-ff-display); color:var(--hl-text-dark);
  letter-spacing:-.02em;
}
.hl-rwhy__list dt::before{
  content:""; width:6px; height:6px; border-radius:2px; flex:none;
  background:var(--hl-brand-red); transform:translateY(-2px);
}
.hl-rwhy__list dd{ margin:0; padding-left:16px; font-size:var(--hl-fs-xs); line-height:1.65;
  color:var(--hl-text-muted); }

/* ── G8 · RESPONSIVE ────────────────────────────────────────────────────── */
@media (max-width:1280px){
  .hl-rhw__row{ grid-template-columns:repeat(var(--hl-row-sm, 2), minmax(0,1fr)); }
}

@media (max-width:1120px){
  .hl-floor__wrap{ grid-template-columns:minmax(0,1fr); gap:var(--hl-s-8); }
  .hl-fpanel{ grid-template-columns:minmax(0,1fr) 220px; grid-template-rows:auto;
    align-items:center; align-content:center; }
  .hl-fpanel--textonly{ grid-template-columns:minmax(0,1fr); }
  .hl-fpanel__art{ height:100%; min-height:180px; }
  .hl-bento{ grid-template-columns:repeat(4,minmax(0,1fr)); }
  .hl-btile--lead{ grid-column:span 4; }
  .hl-btile--dark{ grid-column:span 4; }
  .hl-bento > .hl-btile:not(.hl-btile--lead):not(.hl-btile--dark){ grid-column:span 2; }
  .hl-bento > .hl-btile:last-child{ grid-column:span 4; }
  .hl-rwhy__shell{ grid-template-columns:minmax(0,1fr); }
  .hl-rwhy__copy{ max-width:none; }
}

@media (max-width:1024px){
  .hl-ihero .hl-shero__shell{ grid-template-columns:minmax(0,1fr); }
  .hl-shero__viz.hl-ihero__viz{ max-width:560px; }
  .hl-rhw__feature{ grid-template-columns:minmax(0,1fr); }
  .hl-rhw__art{ min-height:250px; order:-1; }
  .hl-cd__shell{ grid-template-columns:minmax(0,1fr); gap:var(--hl-s-10); }
  .hl-cd__lede{ max-width:none; }
  .hl-rfund__grid{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}

@media (max-width:900px){
  .hl-ioffer__pts{ grid-template-columns:minmax(0,1fr); }
  .hl-rwhy__list{ grid-template-columns:minmax(0,1fr); }
  .hl-bento{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .hl-btile--lead,.hl-btile--dark{ grid-column:span 2; }
  .hl-bento > .hl-btile:not(.hl-btile--lead):not(.hl-btile--dark){ grid-column:span 2; }
}

@media (max-width:768px){
  .hl-rhw__row{ grid-template-columns:repeat(var(--hl-row-sm, 2), minmax(0,1fr)); }
}

@media (max-width:640px){
  /* Mobile floor: the plan becomes a spine of stations. The room outline and
     the wires are dropped rather than squeezed into an unreadable box. */
  .hl-floor__map{ aspect-ratio:auto; }
  .hl-floor__plan,.hl-floor__roomtag{ display:none; }
  .hl-floor__spots{ position:static; display:flex; gap:8px; overflow-x:auto;
    padding-bottom:6px; scrollbar-width:none; }
  .hl-floor__spots::-webkit-scrollbar{ display:none; }
  .hl-spot{ position:static; transform:none; flex:none; }
  .hl-spot:hover{ transform:none; }
  /* On mobile the foot sits between the station strip and the panel, so it
     stops being three pills and becomes a caption that explains the strip. */
  .hl-floor__foot{
    display:block; margin:var(--hl-s-4) 0 0;
    padding-top:12px; border-top:1px solid var(--hl-line-dark);
    font-size:var(--hl-fs-micro); line-height:1.5; color:var(--hl-text-light-4);
  }
  .hl-floor__foot span{ padding:0; background:none; border:0; font-size:inherit; color:inherit; }
  .hl-floor__foot span + span::before{ content:" · "; opacity:.6; }
  .hl-fpanel{ grid-template-columns:minmax(0,1fr); grid-template-rows:auto auto; }
  .hl-fpanel--textonly{ grid-template-rows:auto; }
  .hl-fpanel__art{ order:-1; height:170px; }

  .hl-oflag{ width:100%; }
  .hl-oflag__txt{ line-height:1.4; white-space:normal; }
  .hl-rstage{ padding:18px 16px 12px; }
  .hl-rstage__slot{ min-height:190px; }
  .hl-rstage__slot .hl-dev{ --hl-k:.86; transform:scale(.86); margin-block:-6px; }
  .hl-rstage__slot::before{ bottom:26px; }
  /* four floating labels do not fit around a phone-width device */
  .hl-rlabel--2,.hl-rlabel--3{ display:none; }
  .hl-rlabel{ font-size:.68rem; padding:6px 10px; }
  .hl-rlabel--1{ top:8%; left:0; }
  .hl-rlabel--4{ bottom:12%; right:0; }
  .hl-ihero .hl-shero__cta .hl-btn{ flex:1 1 auto; justify-content:center; }

  .hl-bento{ grid-template-columns:minmax(0,1fr); }
  /* Matching the SPAN rule's specificity on purpose. The prototype's plain
     `.btile{grid-column:auto}` is outranked by
     `.bento > .btile:not(--lead):not(--dark){grid-column:span 2}` from the 900
     block, so a one-track grid still gets asked for two columns and browsers
     add an implicit one. The tiles render full width either way — measured on
     both — but a phantom track is the kind of thing that becomes a real bug the
     next time this grid is touched, so the override is written to actually
     win. */
  .hl-bento > .hl-btile:not(.hl-btile--lead):not(.hl-btile--dark),
  .hl-bento > .hl-btile--lead,
  .hl-bento > .hl-btile--dark{ grid-column:auto; }
  .hl-turn__row{ grid-template-columns:minmax(0,1fr); gap:6px; }
  .hl-turn__bar i{ flex:1 1 auto; }

  .hl-ioffer__card{ padding:26px 20px; border-radius:var(--hl-r-2xl); }
  .hl-ioffer__amt{ gap:10px; }
  .hl-ioffer__cta .hl-btn{ flex:1 1 auto; justify-content:center; }

  .hl-rfund__grid{ grid-template-columns:minmax(0,1fr); }
  .hl-rhw__feature{ padding:18px; }
  .hl-rhw__row{ grid-template-columns:repeat(var(--hl-row-sm, 2), minmax(0,1fr)); gap:10px; }
  .hl-rhw .hl-hcard{ padding:16px 12px; }
  .hl-rhw .hl-hcard{ --hl-hcard-media:168px; }
  .hl-rhw .hl-hcard .hl-pslot{ margin-bottom:12px; }
  .hl-rhw .hl-hcard .hl-dev--smart{ --hl-k:.54; transform:scale(.54); margin-block:-49px; }
  .hl-rhw .hl-hcard .hl-dev--counter{ --hl-k:.68; transform:scale(.68); margin-block:-21px; }
  .hl-rhw .hl-hcard .hl-dev--portable{ --hl-k:.7; transform:scale(.7); margin-block:-29px; }
  .hl-rhw .hl-hcard .hl-dev--reader{ --hl-k:.88; transform:scale(.88); margin-block:-7px; }
  .hl-rhw .hl-hcard__meta b{ font-size:.92rem; }
  .hl-rhw .hl-hcard__meta i{ font-size:.72rem; }

  .hl-check{ padding:20px 18px 16px; }
  .hl-cd__cta{ gap:var(--hl-s-4); }
  .hl-cd__cta .hl-btn--lg{ width:100%; justify-content:center; }
}

@media (max-width:430px){
  .hl-spot{ padding:8px 12px 8px 10px; font-size:.72rem; }
  .hl-fspec li{ grid-template-columns:minmax(0,1fr); gap:3px; }
  .hl-rwhy__list dd{ padding-left:0; }
}

@media (max-width:400px){
  .hl-rhw__row{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:8px; }
  .hl-rhw .hl-hcard{ padding:14px 10px; }
  .hl-rhw .hl-hcard{ --hl-hcard-media:158px; }
  .hl-ioffer__amt b{ font-size:2.7rem; }
  .hl-rstage__slot .hl-dev{ --hl-k:.76; transform:scale(.76); margin-block:-19px; }
}

/* ── G9 · REDUCED MOTION ────────────────────────────────────────────────── */
@media (prefers-reduced-motion:reduce){
  .hl-rlabel,.hl-rstage__slot .hl-dev,.hl-fpanel__art .hl-dev,.hl-rhw__art .hl-dev{
    animation:none !important; }
  .hl-fpanel.is-active{ animation:none !important; }
  .hl-spot,.hl-btile,.hl-rfund__grid li{ transition:none !important; }
}

/* ===========================================================================
   H · FORM LAYER
   ===========================================================================

   The one part of the site the approved prototypes could not hand over, because
   none of the three had a form on it. So this is written FROM the approved
   system rather than imported into it: the same ink ramp, the same radii, the
   same hairline rules, the same 4px spacing scale, the same red used only for
   signal. A form is the moment a visitor commits, and a stock admin-template
   input in the middle of a designed page is exactly where that confidence
   leaks away.

   Three decisions worth stating:

     * Labels sit ABOVE their input, always. Floating and placeholder-as-label
       both lose the label at the moment it is needed — while typing — and both
       read badly after an autofill.
     * The invalid state is a red rule AND a message, never colour alone: the
       message is what a colour-blind visitor and a screen-reader user both get.
     * Focus is a visible ring on every control, and it is the same navy ring
       the rest of the site uses. Removing an outline is how a keyboard becomes
       unusable.
   =========================================================================== */

.hl-formsec{ position:relative; padding-block:var(--hl-sec-pad-sm); background:var(--hl-white); }
.hl-formsec.hl-section--alt{ background:var(--hl-paper); }
.hl-formsec.hl-section--dark{ background:var(--hl-ink-850); }

.hl-formsec__grid{ display:grid; grid-template-columns:minmax(0,1fr); gap:clamp(28px,3.4vw,56px); }
/* Every track minmax(0,.) with min-width:0 on the children — bridge rule E8.
   A long unbroken email address in the aside must not widen the form column. */
.hl-formsec--split .hl-formsec__grid{ grid-template-columns:minmax(0,1.35fr) minmax(0,.85fr); align-items:start; }
/* "Other ways to reach us" answers questions a visitor has WHILE filling the
   form, and the form is roughly twice its height, so it stayed beside the
   fields rather than stopping 540px above them. */
@media (min-width:901px){
  .hl-formsec--split .hl-formsec__aside{ position:sticky; top:var(--hl-sticky-top); }
}
.hl-formsec__main, .hl-formsec__aside{ min-width:0; }

.hl-formsec__head{ margin-bottom:var(--hl-s-8); }
.hl-formsec__head .hl-h2{ margin:var(--hl-s-4) 0 0; }
.hl-formsec__head .hl-lead{ margin:var(--hl-s-4) 0 0; max-width:60ch; }

/* -- H1 . THE FORM ------------------------------------------------------- */

.hl-form{ display:block; }
.hl-form__grid{
  display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--hl-s-5) var(--hl-s-5);
}

.hl-ff{ min-width:0; display:flex; flex-direction:column; }
.hl-ff--full{ grid-column:1 / -1; }
.hl-ff--half{ grid-column:span 1; }

.hl-ff__label{
  display:flex; align-items:baseline; gap:8px; margin-bottom:8px;
  font:600 var(--hl-fs-sm)/1.3 var(--hl-ff-display);
  color:var(--hl-text-dark); letter-spacing:-.01em;
}
.hl-ff__opt{ font:400 var(--hl-fs-micro)/1 var(--hl-ff-body); color:var(--hl-text-muted);
  letter-spacing:0; text-transform:none; }

.hl-ff__input{
  width:100%; min-width:0; padding:13px 15px;
  font:400 var(--hl-fs-body)/1.5 var(--hl-ff-body); color:var(--hl-text-dark);
  background:var(--hl-white); border:1px solid var(--hl-line-2);
  border-radius:var(--hl-r-sm);
  transition:border-color var(--hl-t-fast) var(--hl-e-soft),
             box-shadow var(--hl-t-fast) var(--hl-e-soft);
  appearance:none;
}
.hl-ff__input::placeholder{ color:var(--hl-text-muted); }
.hl-ff__input:hover{ border-color:var(--hl-navy-300); }
.hl-ff__input:focus{
  outline:none; border-color:var(--hl-navy-500);
  box-shadow:0 0 0 3px rgba(58,63,163,.16);
}
/* The keyboard ring is kept as a real outline as well as the glow, so it
   survives a forced-colours mode where box-shadow does not paint. */
.hl-ff__input:focus-visible{ outline:2px solid var(--hl-navy-500); outline-offset:2px; }

.hl-ff__input--area{ resize:vertical; min-height:140px; line-height:1.62; }

.hl-ff__input--select{
  padding-right:40px; cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23767E96' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 15px center; background-size:12px 8px;
}

.hl-ff.is-invalid .hl-ff__input{ border-color:var(--hl-red-500); }
.hl-ff.is-invalid .hl-ff__input:focus{ box-shadow:0 0 0 3px rgba(207,41,39,.16); }

.hl-ff__err{
  display:flex; align-items:flex-start; gap:6px; margin:7px 0 0;
  font-size:var(--hl-fs-xs); line-height:1.5; color:var(--hl-red-600); font-weight:500;
}
.hl-ff__err::before{
  content:""; flex:none; width:5px; height:5px; margin-top:7px; border-radius:50%;
  background:var(--hl-red-500);
}
.hl-ff__help{ margin:7px 0 0; font-size:var(--hl-fs-xs); line-height:1.5; color:var(--hl-text-muted); }

/* -- H2 . CONSENT -------------------------------------------------------- */

.hl-ff--consent{ margin-top:var(--hl-s-6); }
.hl-consent{
  display:grid; grid-template-columns:auto minmax(0,1fr); gap:12px; align-items:start;
  cursor:pointer; font-size:var(--hl-fs-sm); line-height:1.6; color:var(--hl-text-body);
}
.hl-consent input[type="checkbox"]{
  width:19px; height:19px; margin:2px 0 0; flex:none;
  accent-color:var(--hl-navy-600); cursor:pointer;
}
.hl-consent input[type="checkbox"]:focus-visible{ outline:2px solid var(--hl-navy-500); outline-offset:2px; }
.hl-consent__links{ display:inline; }
.hl-consent__links a{
  color:var(--hl-navy-500); font-weight:600;
  text-decoration:underline; text-underline-offset:2px; text-decoration-thickness:1px;
}
.hl-consent__links a:hover{ color:var(--hl-red-500); }
.hl-ff--consent.is-invalid .hl-consent input[type="checkbox"]{ outline:2px solid var(--hl-red-500); outline-offset:2px; }

/* -- H3 . ACTIONS, NOTE AND STATUS --------------------------------------- */

.hl-form__actions{
  display:flex; flex-wrap:wrap; align-items:center; gap:var(--hl-s-5);
  margin-top:var(--hl-s-8);
}
.hl-form__note{ margin:0; flex:1 1 22ch; font-size:var(--hl-fs-xs); line-height:1.55;
  color:var(--hl-text-muted); }

/* The live region is present in every state and empty in most of them, so it
   must not reserve space or draw a box when it has nothing to say. */
.hl-form__status:empty{ display:none; }
.hl-form__alert{
  display:flex; gap:10px; margin:0 0 var(--hl-s-6); padding:14px 16px;
  border:1px solid rgba(207,41,39,.28); border-left:3px solid var(--hl-red-500);
  border-radius:var(--hl-r-sm); background:rgba(207,41,39,.05);
  font-size:var(--hl-fs-sm); line-height:1.55; color:var(--hl-red-700);
}

.hl-form__sent{
  padding:clamp(28px,3vw,40px);
  border:1px solid var(--hl-line); border-radius:var(--hl-r-lg);
  background:var(--hl-white); box-shadow:var(--hl-sh-md);
}
.hl-form__tick{
  display:grid; place-items:center; width:46px; height:46px; margin-bottom:var(--hl-s-5);
  border-radius:50%; background:rgba(47,214,163,.14); color:#127A5C;
}
.hl-form__tick svg{ width:24px; height:24px; }
.hl-form__sent .hl-h3{ margin:0 0 var(--hl-s-3); }
.hl-form__sent p{ margin:0; font-size:var(--hl-fs-sm); line-height:1.7;
  color:var(--hl-text-muted); max-width:56ch; }

/* -- H4 . THE HONEYPOT --------------------------------------------------- */
/* Hidden from sight, from the tab order (tabindex="-1" on the input) and from
   the accessibility tree (aria-hidden on the wrapper). display:none alone is
   avoided because some bots skip fields that are display:none — this is placed
   off screen instead, which they fill. */
.hl-form__pot{
  position:absolute !important; width:1px; height:1px; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap; pointer-events:none;
}

/* -- H5 . CONTACT PANEL -------------------------------------------------- */

.hl-cpanel{
  padding:clamp(22px,2.2vw,30px);
  border:1px solid var(--hl-line); border-radius:var(--hl-r-lg);
  background:var(--hl-paper);
}
.hl-section--alt .hl-cpanel{ background:var(--hl-white); }
.hl-cpanel__title{ margin:0; font:700 var(--hl-fs-h3)/1.2 var(--hl-ff-display);
  color:var(--hl-text-dark); letter-spacing:var(--hl-ls-tight); }
.hl-cpanel__note{ margin:var(--hl-s-4) 0 0; font-size:var(--hl-fs-sm); line-height:1.7;
  color:var(--hl-text-muted); }

.hl-cpanel__list{ margin:var(--hl-s-6) 0 0; }
.hl-cpanel__list > div{ padding:14px 0; border-top:1px solid var(--hl-line); }
.hl-cpanel__list > div:first-child{ border-top:0; padding-top:0; }
.hl-cpanel__list dt{
  margin-bottom:4px; font:600 var(--hl-fs-micro)/1 var(--hl-ff-mono);
  letter-spacing:var(--hl-ls-wide); text-transform:uppercase; color:var(--hl-text-muted);
}
.hl-cpanel__list dd{ margin:0; font-size:var(--hl-fs-sm); line-height:1.6;
  color:var(--hl-text-dark); overflow-wrap:anywhere; }
.hl-cpanel__list dd a{ color:var(--hl-navy-500); font-weight:600; }
.hl-cpanel__list dd a:hover{ color:var(--hl-red-500); }
.hl-cpanel__list dd em{ font-style:normal; color:var(--hl-text-muted); font-size:var(--hl-fs-xs); }
.hl-cpanel__list address{ font-style:normal; }

.hl-cpanel__points{ margin:var(--hl-s-6) 0 0; padding:var(--hl-s-5) 0 0;
  border-top:1px solid var(--hl-line); display:grid; gap:var(--hl-s-4); }
.hl-cpanel__points li{ display:grid; gap:3px; }
.hl-cpanel__points b{ font:700 var(--hl-fs-sm)/1.35 var(--hl-ff-display);
  color:var(--hl-text-dark); letter-spacing:-.01em; }
.hl-cpanel__points span{ font-size:var(--hl-fs-xs); line-height:1.6; color:var(--hl-text-muted); }

/* -- H6 . DARK CHAPTER --------------------------------------------------- */
/* A form is normally a light chapter, but the theme is an admin choice and the
   choice must not be able to produce unreadable type. */
.hl-formsec.hl-section--dark .hl-ff__label{ color:#fff; }
.hl-formsec.hl-section--dark .hl-ff__opt,
.hl-formsec.hl-section--dark .hl-ff__help{ color:var(--hl-text-light-3); }
.hl-formsec.hl-section--dark .hl-ff__input{
  color:#fff; background:rgba(255,255,255,.04); border-color:var(--hl-line-dark-2);
}
.hl-formsec.hl-section--dark .hl-ff__input:focus{ border-color:var(--hl-navy-300);
  box-shadow:0 0 0 3px rgba(144,150,228,.22); }
.hl-formsec.hl-section--dark .hl-consent{ color:var(--hl-text-light-2); }
.hl-formsec.hl-section--dark .hl-consent__links a{ color:var(--hl-navy-300); }
.hl-formsec.hl-section--dark .hl-cpanel{ background:rgba(255,255,255,.03);
  border-color:var(--hl-line-dark); }
.hl-formsec.hl-section--dark .hl-cpanel__title{ color:#fff; }
.hl-formsec.hl-section--dark .hl-cpanel__note,
.hl-formsec.hl-section--dark .hl-cpanel__points span{ color:var(--hl-text-light-3); }
.hl-formsec.hl-section--dark .hl-cpanel__list > div,
.hl-formsec.hl-section--dark .hl-cpanel__points{ border-color:var(--hl-line-dark); }
.hl-formsec.hl-section--dark .hl-cpanel__list dd,
.hl-formsec.hl-section--dark .hl-cpanel__points b{ color:#fff; }
.hl-formsec.hl-section--dark .hl-form__sent{ background:rgba(255,255,255,.04);
  border-color:var(--hl-line-dark); box-shadow:none; }
.hl-formsec.hl-section--dark .hl-form__sent p{ color:var(--hl-text-light-2); }

/* -- H7 . RESPONSIVE ----------------------------------------------------- */

@media (max-width:1024px){
  .hl-formsec--split .hl-formsec__grid{ grid-template-columns:minmax(0,1fr); }
  /* The panel follows the form on a narrow screen: the form is the reason the
     visitor is on the page, and the details beside it are supporting. */
  .hl-formsec__aside{ order:2; }
}

@media (max-width:640px){
  /* Two half-width fields side by side stop being two fields and start being
     two cramped ones somewhere around here. */
  .hl-form__grid{ grid-template-columns:minmax(0,1fr); }
  .hl-ff--half{ grid-column:1 / -1; }
  .hl-form__actions{ gap:var(--hl-s-4); }
  .hl-form__actions .hl-btn{ width:100%; justify-content:center; }
  .hl-form__note{ flex:1 1 100%; }
}

@media (max-width:430px){
  .hl-ff__input{ padding:12px 13px; }
}

/* -- H8 . REDUCED MOTION ------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  .hl-ff__input{ transition:none !important; }
}

/* ===========================================================================
   H9 · THE SYSTEM LAYOUT
   ===========================================================================

   Chrome for `layouts/system` — the standalone shell the maintenance page uses.
   Four rules and a footer, because the page's actual content is an ordinary
   approved hero block and needs nothing from here.

   The page is a single dark hero on a dark page, so the shell is dark too: a
   white bar above a dark hero would be a seam that exists for no reason.
   =========================================================================== */

body.hl-body--system{ background:var(--hl-ink-900); color:var(--hl-text-light-2); }

.hl-sysbar{ padding:clamp(20px,3vw,32px) 0; background:var(--hl-ink-900); }
.hl-sysbar__inner{ display:flex; align-items:center; justify-content:center; }
/* Not a link, by design — every destination is 503 while this page is up.
   Size comes from the existing `.hl-logo img` rule; only the variable changes,
   so the lockup's optical alignment is the same one the header uses. */
.hl-logo--sys{ --hl-logo-h:96px; }

.hl-sysempty{ padding-block:clamp(48px,6vw,96px); text-align:center; }
.hl-sysempty .hl-h2{ color:#fff; }
.hl-sysempty .hl-lead{ color:var(--hl-text-light-2); }

.hl-sysfoot{
  padding:clamp(24px,3vw,40px) 0; text-align:center;
  background:var(--hl-ink-950); border-top:1px solid var(--hl-line-dark);
}
.hl-sysfoot p{ margin:0; font-size:var(--hl-fs-xs); line-height:1.7; color:var(--hl-text-light-3); }
.hl-sysfoot__contact{ margin-bottom:8px !important; }
.hl-sysfoot__contact a{ color:var(--hl-navy-300); font-weight:600;
  text-decoration:underline; text-underline-offset:2px; }
.hl-sysfoot__contact a:hover{ color:#fff; }

@media (max-width:600px){
  .hl-logo--sys{ --hl-logo-h:68px; }
}

/* ===========================================================================
   I · CATALOG LAYER
   ===========================================================================

   The one part of this site the approved prototypes never drew, for the same
   reason section H had to be written from scratch: there was no catalog to
   draw. So this is built from the tokens above rather than invented beside
   them — the same radii, the same shadow ramp, the same red eyebrow, the same
   hover lift the hardware cards already use, and the same `.hl-ihead` chapter
   head every inner-page section opens with.

   The brief for it was: do not make it look like a generic storefront grid.
   Two decisions do most of that work.

     * The CARD is a device on its stage, not a photograph in a box. It reuses
       `.hl-pslot` and the approved silhouettes, so an unfilled slot reads as
       pending rather than as a missing image.
     * The FILTER is a rail of chips in the site's own language, not a sidebar
       of checkboxes. Underneath it is a radio group, so it is a real form.

   Every grid track here is `minmax(0,1fr)` or `minmax(min(100%,N),1fr)` and
   every card carries `min-width:0` — bridge rule E8. That is what stops a long
   product name pushing the grid wider than the viewport, which is the single
   most common way a card grid grows a horizontal scrollbar on a 360px phone.
   =========================================================================== */

/* ── I0 · THE CHAPTER'S OWN PADDING ──────────────────────────────────────────
   `.hl-cat` had no `padding-block` at all, and that is the whole of the
   catalog page's compression.

   The Spacing select on this block is set to "None — the composition sets its
   own", which is the correct choice and the one nearly every block on this
   site makes: `hl-section--none` is on every section of the home page too. The
   contract that preset creates is that the BLOCK supplies the padding —
   `.hl-sys`, `.hl-hw`, `.hl-ind`, `.hl-net-sec`, `.hl-calc` and `.hl-fund` all
   declare `padding-block:var(--hl-sec-pad)` for exactly this reason.

   `.hl-cat` never declared it. So the section computed to 0px top and 0px
   bottom, "THE CATALOG" began at the literal top edge of its own section with
   the hero directly above it, and the chapter ran straight into the closing
   band underneath.

   One declaration, the same token and the same value every other chapter on
   the site already resolves to — 113.66px at 1536px, and it scales with the
   viewport because the token is a clamp. The head-to-content gap inside the
   chapter is NOT touched: it measures 56px here, and 56px on
   `/pos-terminals #types` and `/industries/retail #floor`, so it is already
   the site rhythm and moving it would make this page the odd one out. */
.hl-cat{ padding-block:var(--hl-sec-pad); }

/* ── I1 · THE FILTER RAIL ────────────────────────────────────────────────── */
.hl-catfilter{
  display:grid; gap:clamp(16px,2vw,24px); margin-bottom:clamp(28px,3vw,44px);
  padding:clamp(18px,2vw,26px); border-radius:var(--hl-r-xl);
  background:#fff; border:1px solid var(--hl-line); box-shadow:var(--hl-sh-sm);
}
.hl-section--dark .hl-catfilter{
  background:rgba(255,255,255,.04); border-color:var(--hl-line-dark); box-shadow:none;
}

.hl-catfilter__label{
  display:block; margin-bottom:10px; padding:0;
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-body);
  letter-spacing:var(--hl-ls-wider); text-transform:uppercase; color:var(--hl-text-muted);
}
.hl-section--dark .hl-catfilter__label{ color:var(--hl-text-light-3); }

.hl-catfilter__group{ border:0; padding:0; margin:0; min-width:0; }

.hl-catfilter__field{ display:flex; gap:8px; align-items:stretch; }
.hl-catfilter__input{
  flex:1 1 auto; min-width:0; width:100%;
  padding:11px 14px; border-radius:var(--hl-r-sm);
  border:1px solid var(--hl-line-2); background:#fff;
  font:400 var(--hl-fs-sm)/1.4 var(--hl-ff-body); color:var(--hl-text-dark);
  transition:border-color var(--hl-t-fast) var(--hl-e-out), box-shadow var(--hl-t-fast) var(--hl-e-out);
}
.hl-catfilter__input:focus{
  outline:none; border-color:var(--hl-navy-500); box-shadow:0 0 0 3px rgba(58,63,163,.14);
}
.hl-section--dark .hl-catfilter__input{
  background:rgba(255,255,255,.06); border-color:var(--hl-line-dark-2); color:#fff;
}
.hl-section--dark .hl-catfilter__input:focus{ border-color:var(--hl-navy-300); }

/* The chips. A wrapping row rather than a horizontal scroller: a filter you
   have to scroll to discover is a filter most people never find. */
.hl-catchips{ display:flex; flex-wrap:wrap; gap:8px; }

.hl-catchip{
  position:relative; display:inline-flex; align-items:center; gap:8px;
  padding:9px 14px; border-radius:var(--hl-r-pill); cursor:pointer;
  border:1px solid var(--hl-line-2); background:var(--hl-paper);
  font:600 var(--hl-fs-sm)/1 var(--hl-ff-body); color:var(--hl-text-body);
  transition:background var(--hl-t-fast) var(--hl-e-out), border-color var(--hl-t-fast) var(--hl-e-out),
             color var(--hl-t-fast) var(--hl-e-out);
}
.hl-catchip input{
  /* Visually replaced by the chip, NOT removed. `display:none` would take the
     radio out of the tab order and out of the accessibility tree, which would
     make the whole filter unreachable from a keyboard. */
  position:absolute; inset:0; width:100%; height:100%; margin:0; opacity:0; cursor:pointer;
}
.hl-catchip b{
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-mono);
  padding:3px 7px; border-radius:var(--hl-r-pill);
  background:rgba(10,14,36,.06); color:var(--hl-text-muted);
}
/* The mask itself comes from `[data-ico]` above — the one icon system on this
   site. These rules only size it and let it inherit the chip's colour, so a
   selected chip's icon turns white with the rest of the chip. */
.hl-catchip__ico{ width:15px; height:15px; }
.hl-catchip:hover{ background:#fff; border-color:var(--hl-line); }
.hl-catchip:has(input:focus-visible){ outline:2px solid var(--hl-navy-500); outline-offset:3px; }
/* The same ring where `:has()` is not supported. The radio is a full-size
   transparent overlay, so an outline on the input itself traces the chip's own
   box — square rather than pill, and that is the entire difference. Scoped to
   @supports so the two never draw at once, because the alternative to a
   slightly different ring is no focus indicator at all on the filter. */
@supports not selector(:has(*)){
  .hl-catchip input:focus-visible{ outline:2px solid var(--hl-navy-500); outline-offset:3px; }
}
.hl-catchip:has(input:checked), .hl-catchip.is-active{
  background:var(--hl-brand-navy); border-color:var(--hl-brand-navy); color:#fff;
}
.hl-catchip:has(input:checked) b, .hl-catchip.is-active b{
  background:rgba(255,255,255,.18); color:#fff;
}
.hl-section--dark .hl-catchip{
  background:rgba(255,255,255,.05); border-color:var(--hl-line-dark-2); color:var(--hl-text-light-2);
}
.hl-section--dark .hl-catchip b{ background:rgba(255,255,255,.10); color:var(--hl-text-light-3); }

.hl-catfilter__acts{ display:flex; flex-wrap:wrap; align-items:center; gap:12px; }

.hl-catcheck{
  display:inline-flex; align-items:center; gap:9px; cursor:pointer;
  font:500 var(--hl-fs-sm)/1 var(--hl-ff-body); color:var(--hl-text-body);
}
.hl-catcheck input{ width:17px; height:17px; accent-color:var(--hl-brand-navy); cursor:pointer; }
.hl-catcheck input:focus-visible{ outline:2px solid var(--hl-navy-500); outline-offset:2px; }
.hl-section--dark .hl-catcheck{ color:var(--hl-text-light-2); }

.hl-catfilter__clear{ margin-inline-start:auto; }

.hl-catcount{
  margin-bottom:clamp(18px,2vw,26px);
  font:500 var(--hl-fs-sm)/1.5 var(--hl-ff-body); color:var(--hl-text-muted);
}
.hl-section--dark .hl-catcount{ color:var(--hl-text-light-3); }

/* ── I2 · THE GRID AND THE CARD ──────────────────────────────────────────── */
/*
 * `grid-auto-rows:1fr` is what makes "consistent card heights" true across the
 * whole grid rather than only within a row. Auto rows size to their own tallest
 * item, so one card wrapping one extra line takes its entire row with it: the
 * shipped catalog measured 416.6px in row 1 against 391.5px in row 2, purely
 * because "Smart Terminal" is the only product carrying a badge next to its
 * category chip and that pair wraps to two lines. Nothing was wrong with the
 * card; the rows were simply independent.
 *
 * In a grid whose own height is indefinite, `1fr` rows all resolve to the
 * tallest row's max-content height, which is exactly the wanted behaviour and
 * needs no JavaScript and no fixed height. The extra height lands as whitespace
 * above the footer, because `.hl-pcard__foot{margin:auto 0 0}` already holds the
 * price and the affordance against the bottom edge.
 */
.hl-pgrid{
  display:grid; grid-template-columns:repeat(auto-fill, minmax(min(100%, 260px), 1fr));
  grid-auto-rows:1fr;
  gap:clamp(14px,1.6vw,22px); list-style:none; margin:0; padding:0;
}
.hl-pgrid--rel{ grid-template-columns:repeat(auto-fill, minmax(min(100%, 280px), 1fr)); }
/* `auto-fill` lays four tracks whatever the row holds, so a product with only
   two siblings in its category rendered two cards and two empty tracks — half
   a row of nothing (audit PD-05). The renderer knows the count, so the grid
   uses it: the cards keep their size and the row simply ends, left-aligned on
   the same spine as the chapter head above it. */
@media (min-width:901px){
  .hl-pgrid--rel[data-count="1"]{ grid-template-columns:minmax(0,1fr); max-width:380px; }
  .hl-pgrid--rel[data-count="2"]{ grid-template-columns:repeat(2,minmax(0,1fr)); max-width:760px; }
  .hl-pgrid--rel[data-count="3"]{ grid-template-columns:repeat(3,minmax(0,1fr)); max-width:1040px; }
}

.hl-pcard{ min-width:0; display:flex; }
.hl-pcard__in{
  position:relative; display:flex; flex-direction:column; width:100%; min-width:0;
  padding:20px 18px 18px; border-radius:var(--hl-r-xl); overflow:hidden;
  background:#fff; border:1px solid var(--hl-line); box-shadow:var(--hl-sh-sm);
  color:inherit; text-decoration:none;
  transition:transform 420ms var(--hl-e-out), box-shadow 420ms var(--hl-e-out),
             border-color 420ms var(--hl-e-out);
}
.hl-pcard__in::after{
  content:""; position:absolute; inset:auto -30% -60% -30%; height:70%;
  background:radial-gradient(ellipse at 50% 0%, rgba(42,45,124,.09), transparent 68%);
  pointer-events:none;
}
a.hl-pcard__in:hover{ transform:translateY(-7px); box-shadow:var(--hl-sh-md); border-color:var(--hl-line-2); }
a.hl-pcard__in:focus-visible{ outline:2px solid var(--hl-brand-red); outline-offset:3px; }
.hl-section--dark .hl-pcard__in{
  background:rgba(255,255,255,.04); border-color:var(--hl-line-dark); box-shadow:none;
}

/*
 * The card's media frame. `--hl-pslot-h` is a fixed band rather than the
 * `min-height` this used to be, and that single change is what makes a grid of
 * cards line up: a `min-height` is a floor the artwork can push through, so the
 * tallest silhouette in the row decided where every title started.
 *
 * 158px is not arbitrary — it is the smallest band that contains the largest
 * PAINTED device. The silhouettes are scaled with `transform`, which does not
 * reserve layout space, so `.hl-dev--smart` is a 214px-tall box painted at
 * 154px and `.hl-dev--pump` a 242px box painted at 145px. Both fit; the layout
 * boxes overflow the band and are clipped by `.hl-pcard__in{overflow:hidden}`,
 * which is exactly what should happen to space nothing is drawn in.
 *
 * There is no `max-height` on the image any more. The 170px that used to be here
 * was larger than the frame, so a portrait upload inflated the band it was
 * supposed to fit inside — the 26px of card-height variation measured across
 * upload shapes was entirely this declaration. `max-height:100%` on
 * `.hl-pslot img` now resolves against a definite row instead.
 */
.hl-pcard__art{ display:flex; justify-content:center; margin-bottom:16px;
  --hl-pslot-h:158px; --hl-pslot-inset:8px; }
.hl-pcard__art .hl-pslot{ width:100%; justify-content:center; }
.hl-pcard__art .hl-dev{ --hl-k:.78; transform:scale(.78); }
.hl-pcard__art .hl-dev--smart{ --hl-k:.72; transform:scale(.72); }
.hl-pcard__art .hl-dev--rest{ --hl-k:.66; transform:scale(.66); }
.hl-pcard__art .hl-dev--pump{ --hl-k:.6; transform:scale(.6); }

.hl-pcard__body{ display:flex; flex-direction:column; gap:6px; min-width:0; flex:1; }
.hl-pcard__tags{ display:flex; flex-wrap:wrap; gap:6px; margin:0; }
.hl-pcard__cat, .hl-pcard__badge{
  font:600 var(--hl-fs-micro)/1 var(--hl-ff-body);
  letter-spacing:var(--hl-ls-wide); text-transform:uppercase;
  padding:4px 8px; border-radius:var(--hl-r-xs);
}
.hl-pcard__cat{ background:var(--hl-paper-2); color:var(--hl-text-muted); }
.hl-pcard__badge{ background:rgba(207,41,39,.10); color:var(--hl-brand-red); }
.hl-section--dark .hl-pcard__cat{ background:rgba(255,255,255,.08); color:var(--hl-text-light-3); }

.hl-pcard__title{
  margin:2px 0 0; font:700 var(--hl-fs-h4)/1.3 var(--hl-ff-display);
  letter-spacing:-.02em; color:var(--hl-text-dark); overflow-wrap:anywhere;
}
.hl-section--dark .hl-pcard__title{ color:#fff; }
.hl-pcard__maker{ margin:0; font:500 var(--hl-fs-xs)/1.4 var(--hl-ff-mono); color:var(--hl-text-muted); }
.hl-pcard__text{ margin:0; font-size:var(--hl-fs-sm); line-height:1.6; color:var(--hl-text-body); }
.hl-section--dark .hl-pcard__text{ color:var(--hl-text-light-2); }

/* One supporting line under the copy — the financing note, where a block passes
   one. Red would read as a warning and the body ramp would read as more prose,
   so it takes the navy the rest of the system uses for "this is a term". */
.hl-pcard__note{
  margin:2px 0 0; font:600 var(--hl-fs-xs)/1.5 var(--hl-ff-body); color:var(--hl-navy-600);
}
.hl-section--dark .hl-pcard__note{ color:var(--hl-navy-300); }

.hl-pcard__foot{
  display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between;
  gap:8px; margin:auto 0 0; padding-top:14px;
}
.hl-pcard__price{ display:inline-flex; align-items:baseline; gap:6px; min-width:0; }
.hl-pcard__price i{ font-style:normal; font-size:var(--hl-fs-xs); color:var(--hl-text-muted); }
.hl-pcard__price s{ font-size:var(--hl-fs-xs); color:var(--hl-text-muted); }
.hl-pcard__price b{ font:700 var(--hl-fs-body)/1 var(--hl-ff-display); color:var(--hl-text-dark); }
.hl-pcard__call{ font:600 var(--hl-fs-xs)/1.3 var(--hl-ff-body); color:var(--hl-text-muted); }
.hl-section--dark .hl-pcard__price b{ color:#fff; }

.hl-pcard__go{
  display:inline-flex; align-items:center; gap:6px; margin-inline-start:auto;
  font:600 var(--hl-fs-xs)/1 var(--hl-ff-body); color:var(--hl-brand-red);
}
.hl-pcard__go .hl-arrow{ transition:transform var(--hl-t-fast) var(--hl-e-out); }
a.hl-pcard__in:hover .hl-pcard__go .hl-arrow{ transform:translateX(3px); }

/* ── I3 · EMPTY RESULT, PAGINATION AND THE CHAPTER FOOT ──────────────────── */
.hl-catempty{
  padding:clamp(36px,5vw,64px) clamp(20px,3vw,40px); text-align:center;
  border-radius:var(--hl-r-xl); border:1px dashed var(--hl-line-2); background:var(--hl-paper);
}
.hl-section--dark .hl-catempty{ background:rgba(255,255,255,.03); border-color:var(--hl-line-dark-2); }
.hl-catempty__title{ margin:0 0 8px; font:700 var(--hl-fs-h3)/1.3 var(--hl-ff-display); color:var(--hl-text-dark); }
.hl-catempty__text{
  margin:0 auto var(--hl-s-6); max-width:46ch;
  font-size:var(--hl-fs-sm); color:var(--hl-text-muted);
}
.hl-section--dark .hl-catempty__title{ color:#fff; }
.hl-section--dark .hl-catempty__text{ color:var(--hl-text-light-3); }

.hl-catpages{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
  gap:10px; margin-top:clamp(28px,3vw,44px);
}
.hl-catpages__list{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; list-style:none; margin:0; padding:0; }
.hl-catpages a, .hl-catpages span.is-current, .hl-catpages__step{
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  min-width:40px; height:40px; padding-inline:12px; border-radius:var(--hl-r-sm);
  font:600 var(--hl-fs-sm)/1 var(--hl-ff-body); text-decoration:none;
  border:1px solid var(--hl-line-2); background:#fff; color:var(--hl-text-body);
  transition:background var(--hl-t-fast) var(--hl-e-out), border-color var(--hl-t-fast) var(--hl-e-out);
}
.hl-catpages a:hover{ border-color:var(--hl-navy-500); color:var(--hl-brand-navy); }
.hl-catpages a:focus-visible, .hl-catpages__step:focus-visible{ outline:2px solid var(--hl-brand-red); outline-offset:2px; }
.hl-catpages span.is-current{ background:var(--hl-brand-navy); border-color:var(--hl-brand-navy); color:#fff; }
.hl-catpages__gap{ padding-inline:4px; color:var(--hl-text-muted); }
.hl-section--dark .hl-catpages a, .hl-section--dark .hl-catpages__step{
  background:rgba(255,255,255,.05); border-color:var(--hl-line-dark-2); color:var(--hl-text-light-2);
}

/* ── THE NOTE AND ITS ACTION ARE ONE COMPOSITION ──────────────────────────
   `justify-content:space-between` across the full 1,192px content width pushed
   the financing note hard left and its CTA hard right, leaving a 469px gap
   between a sentence and the button that answers it — measured at every width
   from 1,280px up. Technically it fitted; it read as two unrelated things.

   The pair is now GROUPED rather than pushed apart: they sit together from the
   left with a gap wide enough to separate them and no wider.

   `max-width` on this element was the first attempt and it was wrong — the
   element carries the chapter's dividing rule, so capping it left a rule that
   stopped 232px short of the product grid it was dividing. One misalignment
   traded for another. The rule keeps the full content width; only the
   arrangement inside it changed.

   Below the breakpoint `flex-wrap` still stacks them, which was always
   correct. */
.hl-catfoot{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:flex-start;
  gap:clamp(20px,3vw,64px); margin-top:clamp(28px,3vw,44px);
  padding-top:clamp(20px,2.4vw,32px); border-top:1px solid var(--hl-line);
}
.hl-catfoot__note{ margin:0; max-width:64ch; font-size:var(--hl-fs-xs); line-height:1.7; color:var(--hl-text-muted); }
.hl-section--dark .hl-catfoot{ border-top-color:var(--hl-line-dark); }
.hl-section--dark .hl-catfoot__note{ color:var(--hl-text-light-3); }

/* ── I4 · THE PRODUCT DETAIL PAGE ────────────────────────────────────────── */
.hl-pdp__maker{
  margin:-6px 0 var(--hl-s-4); font:500 var(--hl-fs-sm)/1 var(--hl-ff-mono);
  color:var(--hl-text-light-3); letter-spacing:.02em;
}
.hl-pdp__price{ display:flex; flex-wrap:wrap; align-items:baseline; gap:10px; margin:0 0 var(--hl-s-6); }
.hl-pdp__price i{ font-style:normal; font-size:var(--hl-fs-sm); color:var(--hl-text-light-3); }
.hl-pdp__price s{ font-size:var(--hl-fs-body); color:var(--hl-text-light-4); }
.hl-pdp__price b{ font:800 clamp(1.5rem,2.4vw,2rem)/1 var(--hl-ff-display); color:#fff; letter-spacing:-.02em; }
.hl-pdp__price small{ flex:1 1 100%; font-size:var(--hl-fs-xs); color:var(--hl-text-light-3); }
.hl-pdp__call{ font:600 var(--hl-fs-body)/1 var(--hl-ff-body); color:var(--hl-navy-300); }

/* The gallery. Thumbnails under the stage — never a hover-only swap, which
   would put every image after the first out of reach on a touch device. */
.hl-pgal{ display:flex; flex-wrap:wrap; justify-content:center; gap:8px; margin-top:var(--hl-s-5); }
.hl-pgal__thumb{
  width:56px; height:56px; padding:5px; border-radius:var(--hl-r-sm); cursor:pointer;
  background:rgba(255,255,255,.06); border:1px solid var(--hl-line-dark-2);
  transition:border-color var(--hl-t-fast) var(--hl-e-out), background var(--hl-t-fast) var(--hl-e-out);
}
.hl-pgal__thumb img{ width:100%; height:100%; object-fit:contain; }
.hl-pgal__thumb:hover{ background:rgba(255,255,255,.12); }
.hl-pgal__thumb:focus-visible{ outline:2px solid var(--hl-red-400); outline-offset:2px; }
.hl-pgal__thumb.is-active{ border-color:var(--hl-red-400); background:rgba(207,41,39,.14); }

.hl-pdp__grid{
  display:grid; grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
  gap:clamp(28px,4vw,64px); align-items:start;
}
.hl-pdp__copy{ min-width:0; }

.hl-pfeat{ list-style:none; margin:0; padding:0; display:grid; gap:12px; min-width:0; }
.hl-pfeat__row{
  display:grid; grid-template-columns:auto minmax(0,1fr); gap:12px; align-items:start;
  padding:14px 16px; border-radius:var(--hl-r-md);
  background:var(--hl-paper); border:1px solid var(--hl-line);
}
.hl-pfeat__tick{
  position:relative; width:18px; height:18px; border-radius:50%; flex:none; margin-top:2px;
  background:var(--hl-brand-navy);
}
.hl-pfeat__tick::after{
  content:""; position:absolute; inset:0; margin:auto; width:8px; height:4px;
  border-left:2px solid #fff; border-bottom:2px solid #fff;
  transform:rotate(-45deg) translate(1px,-1px);
}
.hl-pfeat__txt b{ display:block; font:600 var(--hl-fs-body)/1.35 var(--hl-ff-display); color:var(--hl-text-dark); }
.hl-pfeat__txt i{
  display:block; margin-top:3px; font-style:normal;
  font-size:var(--hl-fs-xs); line-height:1.6; color:var(--hl-text-muted);
}

.hl-pdp__video{
  border-radius:var(--hl-r-xl); overflow:hidden;
  border:1px solid var(--hl-line); background:var(--hl-ink-900);
}
.hl-pdp__video video{ display:block; width:100%; height:auto; }

/* Specifications — one definition list per group, on the dark chapter. */
/* ── Specification groups FLOW; they do not line up in rows ────────────────
   A grid aligns rows, so a one-row group beside a six-row group left the
   difference blank: on the Valor VP800 that was ~140px under CAMERA, ~190px
   under COMPLIANCE, ~120px under ENVIRONMENT and ~140px under PRINTER — about
   600px of dead space in a 1,700px chapter (audit PD-01 / GROUP J).

   Multi-column layout has no rows to align. Each group is kept whole with
   `break-inside:avoid`, the browser balances the columns, and a chapter is now
   as tall as its content instead of as tall as its worst pairing. */
.hl-pspecs{
  columns:2; column-gap:clamp(24px,3vw,52px);
}
.hl-pspecs__group{
  min-width:0; break-inside:avoid; -webkit-column-break-inside:avoid;
  margin:0 0 clamp(20px,2.4vw,32px);
}
.hl-pspecs__group:last-child{ margin-bottom:0; }
@media (max-width:760px){ .hl-pspecs{ columns:1; } }
.hl-pspecs__title{
  margin:0 0 var(--hl-s-4); font:600 var(--hl-fs-micro)/1 var(--hl-ff-body);
  letter-spacing:var(--hl-ls-wider); text-transform:uppercase; color:var(--hl-navy-300);
}
.hl-pspecs__list{ margin:0; }
.hl-pspecs__row{
  display:grid; grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr); gap:14px;
  padding:11px 0; border-bottom:1px solid var(--hl-line-dark);
}
.hl-pspecs__row dt{ font-size:var(--hl-fs-sm); color:var(--hl-text-light-3); }
.hl-pspecs__row dd{ margin:0; font-size:var(--hl-fs-sm); color:#fff; overflow-wrap:anywhere; }

/* Where it fits. */
.hl-puse{
  display:grid; grid-template-columns:repeat(auto-fit, minmax(min(100%, 250px), 1fr));
  gap:clamp(14px,1.6vw,22px); list-style:none; margin:0; padding:0;
}
.hl-puse__card{
  min-width:0; padding:22px 20px; border-radius:var(--hl-r-xl);
  background:#fff; border:1px solid var(--hl-line); box-shadow:var(--hl-sh-sm);
}
.hl-puse__ico{ width:22px; height:22px; margin-bottom:14px; color:var(--hl-brand-red); }
.hl-puse__title{ margin:0 0 6px; font:700 var(--hl-fs-h4)/1.3 var(--hl-ff-display); color:var(--hl-text-dark); }
.hl-puse__text{ margin:0; font-size:var(--hl-fs-sm); line-height:1.65; color:var(--hl-text-muted); }

/* Financing strip and the closing band. */
.hl-pdpfin{
  display:grid; grid-template-columns:minmax(0,1fr) auto; gap:clamp(24px,3vw,48px);
  align-items:center; padding:clamp(26px,3vw,44px); border-radius:var(--hl-r-2xl);
  background:#fff; border:1px solid var(--hl-line); box-shadow:var(--hl-sh-sm);
}
.hl-pdpfin__title{ margin:0 0 var(--hl-s-4); font-size:var(--hl-fs-h3); letter-spacing:-.02em; }
.hl-pdpfin__note{ margin:0 0 var(--hl-s-3); font-size:var(--hl-fs-sm); line-height:1.7; color:var(--hl-text-body); }
.hl-pdpfin__disc{ margin:0; max-width:70ch; font-size:var(--hl-fs-xs); line-height:1.7; color:var(--hl-text-muted); }

.hl-pdpend{ max-width:640px; margin-inline:auto; text-align:center; }
.hl-pdpend__title{ margin:0 0 var(--hl-s-4); font-size:var(--hl-fs-h2); color:#fff; letter-spacing:-.02em; }
.hl-pdpend__text{ margin:0 0 var(--hl-s-8); font-size:var(--hl-fs-lede); color:var(--hl-text-light-2); }
.hl-pdpend__cta{ display:flex; flex-wrap:wrap; justify-content:center; gap:12px; }

/* ── I5 · RESPONSIVE ─────────────────────────────────────────────────────── */
@media (max-width:1024px){
  .hl-pdp__grid{ grid-template-columns:minmax(0,1fr); }
  .hl-pdpfin{ grid-template-columns:minmax(0,1fr); }
}

@media (max-width:760px){
  .hl-catfilter{ padding:16px; }
  .hl-catfilter__field{ flex-wrap:wrap; }
  .hl-catfilter__submit{ width:100%; }
  .hl-catfilter__clear{ margin-inline-start:0; }
  .hl-catfilter__acts{ justify-content:space-between; }
  /* The counts are the first thing to go when space runs out. The category
     name is the label; the count was only ever supporting information. */
  .hl-catchip b{ display:none; }
  .hl-pgrid{ grid-template-columns:repeat(auto-fill, minmax(min(100%, 200px), 1fr)); }
  /*
   * A shorter band on a phone, and the silhouettes scaled to match it. The band
   * and the scale factors have to move together: 140px of frame with the desktop
   * scales would paint a 154px device into it, which is how artwork ends up
   * sitting on top of its own caption. Every value below is (band - 4px) / the
   * device's layout height or less.
   */
  .hl-pcard__art{ --hl-pslot-h:140px; }
  .hl-pcard__art .hl-dev{ --hl-k:.69; transform:scale(.69); }
  .hl-pcard__art .hl-dev--smart{ --hl-k:.63; transform:scale(.63); }
  .hl-pcard__art .hl-dev--rest{ --hl-k:.6; transform:scale(.6); }
  .hl-pcard__art .hl-dev--pump{ --hl-k:.56; transform:scale(.56); }
  .hl-pspecs__row{ grid-template-columns:minmax(0,1fr); gap:2px; }
  .hl-pspecs__row dd{ font-weight:600; }
  .hl-catpages__step span{ display:none; }
}

@media (max-width:420px){
  .hl-pgrid{ grid-template-columns:minmax(0,1fr); }
  .hl-pcard__foot{ align-items:flex-start; }
}

@media (prefers-reduced-motion:reduce){
  .hl-pcard__in, .hl-pcard__go .hl-arrow{ transition:none; }
  a.hl-pcard__in:hover{ transform:none; }
}

/* ── I6 · THE SHOWCASE ROW — the `products` block's Carousel and Grid ──────
   The other four layouts of that block (hardware, showcase, insert, and the
   hardware chapter) are finished compositions with their own views and their own
   CSS above. These two were not: they carried a `.hl-product-card` vocabulary
   that had no rules anywhere, so selecting either in Admin rendered an unstyled
   bulleted list of names. They now render `partials/product-card` — the same
   card as the catalog grid and the related-equipment row — which leaves only the
   container to describe, and the container is the whole of this subsection.

   Nothing here is reachable by an existing page: no live section currently
   selects Carousel or Grid. It is the Admin-reachable hole behind that fact that
   is being closed. */
.hl-products{ position:relative; }

/* Grid: the list already carries `.hl-pgrid`, the catalog's own grid, so there
   is deliberately no rule for `.hl-products--grid`. Said out loud so the next
   reader does not go hunting for a declaration that should not exist. */

/*
 * Carousel: one scroll-snapping row that works with no JavaScript at all.
 * modules/carousel.js has always opened with "the server renders a plain
 * semantic <ul> that is already a usable, swipeable, scroll-snapping row via
 * CSS alone" — true of `.hl-reviews`, and until now not true of this one. The
 * arrows it wires drive `scrollBy` on exactly this element, and its step is the
 * first child's width plus the gap, so the row has to be the scroll container
 * and the cards have to be non-shrinking for the controls to page cleanly.
 *
 * `display:flex` overrides `.hl-pgrid`'s grid on the same element — two classes
 * to one, so no !important and no restructuring of the markup. The gap comes
 * from `.hl-pgrid` and applies unchanged in a flex row.
 */
.hl-products--carousel .hl-products__list{
  display:flex; flex-wrap:nowrap;
  overflow-x:auto; overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory; scroll-padding-inline-start:2px;
  /*
   * Making one axis scrollable makes the other a scroll container too, so the
   * card's 7px hover lift and its 3px focus ring would be clipped by the row
   * itself. The padding is reserved room for both, not decoration — remove it
   * and hovering a card in a carousel visibly shaves its top edge.
   */
  padding:10px 2px 16px;
  scrollbar-width:thin; scrollbar-color:var(--hl-line-2) transparent;
}
/* A card in a grid sizes itself from the column. In a row it has to be told, and
   it must not shrink — `flex:0 0` is what makes every snap position land on a
   card of the same width. */
.hl-products--carousel .hl-pcard{ flex:0 0 clamp(232px, 76vw, 300px); scroll-snap-align:start; }
@media (min-width:48rem){
  .hl-products--carousel .hl-pcard{ flex-basis:clamp(244px, 26vw, 304px); }
}
.hl-products--carousel .hl-products__list::-webkit-scrollbar{ height:8px; }
.hl-products--carousel .hl-products__list::-webkit-scrollbar-thumb{
  background:var(--hl-line-2); border-radius:999px;
}
/* The scrollbar is an affordance — it is the only standing signal that there is
   more row to the right — so it is thinned on dark bands, never hidden. */
.hl-section--dark .hl-products--carousel .hl-products__list,
.hl-section--brand .hl-products--carousel .hl-products__list{
  scrollbar-color:rgba(255,255,255,.22) transparent;
}
.hl-section--dark .hl-products--carousel .hl-products__list::-webkit-scrollbar-thumb,
.hl-section--brand .hl-products--carousel .hl-products__list::-webkit-scrollbar-thumb{
  background:rgba(255,255,255,.22);
}

/* The hand-off line under either layout: "View all equipment →". Centred, since
   both layouts above it are centred; the link's own colour and its hover come
   from the J4 button layer, which is where the contrast rules live. */
.hl-section__more{ margin:var(--hl-s-8) 0 0; text-align:center; }


/* ===========================================================================
   J · ADMIN-CONTROLLED SECTION ACCENTS, AND THE BUTTON/LINK CONTRAST LAYER
   ---------------------------------------------------------------------------
   Section A's docblock used to say "nothing in this file is reachable from
   Admin". That is no longer true, and the distinction that replaced it matters:

     an administrator selects an APPROVED OPTION; the stylesheet decides what
     that option looks like.

   Every class below is emitted by section_classes() from a `select` whose
   options are declared in BlockRegistry. There is still no CSS field, and the
   single free-form control — a custom hex — is validated in the sanitiser and
   arrives as a custom property on a scoped rule, never as inline CSS.

   Nothing here changes an existing page. Every control's default is "automatic",
   which emits no class at all, and every token falls back to the approved value
   it replaced.
   =========================================================================== */

/* ── J1 · CHAPTER NUMERAL INK ─────────────────────────────────────────────
   The outlined 01 / 02 / 03. Its default is a hairline on light bands and a
   20%-white stroke on dark ones, which is right for a page that alternates —
   and wrong for six navy sections in a row, which is the problem these give an
   administrator a way to solve. */
.hl-cn--hairline{ --hl-cn-ink:var(--hl-line-2); }
.hl-cn--navy    { --hl-cn-ink:var(--hl-navy-400); }
.hl-cn--red     { --hl-cn-ink:var(--hl-red-400); }
.hl-cn--ink     { --hl-cn-ink:var(--hl-ink-700); }
.hl-cn--white   { --hl-cn-ink:rgba(255,255,255,.34); }
.hl-cn--faint   { --hl-cn-ink:rgba(255,255,255,.16); }

/* Filled rather than outlined — the same numeral at a weight that reads as a
   decision rather than a watermark. Kept deliberately low-contrast: a chapter
   number that competes with the heading is a bug, not a feature. */
.hl-cn--solid{ --hl-cn-fill:var(--hl-cn-ink, var(--hl-line-2)); }
.hl-cn--solid .hl-ihead__n{ -webkit-text-stroke-width:0; }

/* ── J2 · EYEBROW INK ─────────────────────────────────────────────────────
   The eyebrow carries a small gradient bar; recolouring the text without the
   bar would look like an oversight, so both move together. */
.hl-eb--red  { --hl-eb-ink:var(--hl-brand-red);
               --hl-eb-bar:linear-gradient(180deg,var(--hl-red-400),var(--hl-red-600));
               --hl-eb-glow:0 0 12px rgba(207,41,39,.6); }
.hl-eb--navy { --hl-eb-ink:var(--hl-navy-500);
               --hl-eb-bar:linear-gradient(180deg,var(--hl-navy-400),var(--hl-navy-600));
               --hl-eb-glow:0 0 12px rgba(42,45,124,.45); }
.hl-eb--light{ --hl-eb-ink:var(--hl-navy-300);
               --hl-eb-bar:linear-gradient(180deg,var(--hl-navy-300),var(--hl-navy-500));
               --hl-eb-glow:0 0 12px rgba(144,150,228,.45); }
.hl-eb--white{ --hl-eb-ink:#fff;
               --hl-eb-bar:linear-gradient(180deg,#fff,rgba(255,255,255,.5));
               --hl-eb-glow:0 0 12px rgba(255,255,255,.35); }
.hl-eb--muted{ --hl-eb-ink:var(--hl-text-muted);
               --hl-eb-bar:linear-gradient(180deg,var(--hl-line-2),var(--hl-text-muted));
               --hl-eb-glow:none; }

/* ── J3 · HEADING INK ─────────────────────────────────────────────────────
   Restricted to the section heading, and restricted to values that hold their
   contrast on the band the option is offered for. There is no "any colour"
   heading: a heading is the one element on a section that cannot be allowed to
   fail legibility. */
.hl-hd--ink  { --hl-hd-ink:var(--hl-text-dark); }
.hl-hd--navy { --hl-hd-ink:var(--hl-brand-navy); }
.hl-hd--white{ --hl-hd-ink:#fff; }

/* A custom hex is validated in PHP, then applied through these tokens by a
   scoped rule PageRenderer emits — `.hl-s-<section id>{ --hl-cn-ink:#… }`. The
   class is only emitted when a custom value exists, so a page that uses none
   produces byte-identical markup to before. */


/* ===========================================================================
   J4 · BUTTONS AND LINKS — EVERY VARIANT, EVERY STATE, BOTH BANDS
   ---------------------------------------------------------------------------
   Two button systems reached the same element:

     components.css   paints .hl-btn from --hl-btn-bg / --hl-btn-fg /
                      --hl-btn-border, and re-asserts the FOREGROUND on :hover
                      (`.hl-btn:hover{ color:var(--hl-btn-fg) }`, default #fff).
     this file        sets `color` and `background` directly, per variant.

   They agree at rest and disagree on hover, and that disagreement is a defect
   that shipped: "View All Equipment" (.hl-btn--link, red) sits on a white
   section and turned WHITE on hover, because the E-bridge reset for `--link`
   neutralised --hl-btn-bg and --hl-btn-border and never reset --hl-btn-fg.

   Auditing the rest of the family rather than patching that one call site found
   three more instances of the same class of bug:

     .hl-btn--secondary  white background, ink label, and NO :hover rule at all
                         — so hover fell through to #fff on #fff.
     .hl-btn--ghost      `color:#fff` unconditionally, while the `content` and
                         `promotion` blocks render it on a LIGHT band.
     every dark-band button  layout.css's `.hl-section--dark a:hover` is more
                         specific than `.hl-btn:hover`, so hovering the primary
                         CTA repainted its label in --hl-accent-light — which is
                         the colour of its own background. Fixed at source there
                         with `:not(.hl-btn)`.

   The mechanism below replaces the two-system fight with one token. Every
   variant declares `--hl-btn-ink`; one rule re-asserts it on every state. A
   variant can therefore never be handed a foreground it did not choose.
   =========================================================================== */

.hl-btn{ --hl-btn-ink:currentColor; }

/* The single rule that outranks components.css's `.hl-btn:hover`: same
   specificity, later file — so it wins, and it wins with the variant's own ink
   rather than with #fff. */
.hl-btn:hover,
.hl-btn:focus,
.hl-btn:focus-visible,
.hl-btn:active{ color:var(--hl-btn-ink); }

/* The loading spinner is drawn from --hl-btn-fg by components.css; point it at
   the same ink so a loading button does not flash a white ring on white. */
.hl-btn.is-loading::before{ color:var(--hl-btn-ink); border-top-color:transparent; }

/* Focus. base.css already rings every anchor and button; these make the ring
   correct on a band whose class is `--dark` rather than `.hl-on-dark`, and stop
   `overflow:hidden` from clipping it on the pill shapes. */
.hl-btn:focus-visible{
  outline:3px solid var(--hl-brand-red); outline-offset:3px; overflow:visible;
}
.hl-section--dark .hl-btn:focus-visible,
.hl-section--brand .hl-btn:focus-visible,
.hl-ihero .hl-btn:focus-visible,
.hl-shero .hl-btn:focus-visible{
  outline-color:#fff; box-shadow:0 0 0 6px rgba(207,41,39,.45);
}

/* ── J4.1 · PRIMARY / ACCENT — the red gradient ────────────────────────────
   Reads on both bands, so it does not vary by section. */
.hl-btn--primary,
.hl-btn--accent{ --hl-btn-ink:#fff; }

/* ── J4.2 · DARK — the navy gradient ───────────────────────────────────── */
.hl-btn--dark{ --hl-btn-ink:#fff; }

/* ── J4.3 · LIGHT / SECONDARY — white ground, ink label ────────────────────
   Identical treatment; `--secondary` is the vocabulary alias the page builder
   offers. On a light band a white pill needs an edge or it is a floating label,
   and it needs a hover that changes the background rather than the ink. */
.hl-btn--light,
.hl-btn--secondary{ --hl-btn-ink:var(--hl-ink-800); color:var(--hl-btn-ink); background:#fff; }
.hl-btn--light:hover,
.hl-btn--secondary:hover{ --hl-btn-ink:var(--hl-ink-900); background:var(--hl-paper); transform:translateY(-2px); }
.hl-btn--light:active,
.hl-btn--secondary:active{ background:var(--hl-paper-2); transform:translateY(0); }

.hl-section--light .hl-btn--light,
.hl-section--light .hl-btn--secondary,
.hl-section--alt .hl-btn--light,
.hl-section--alt .hl-btn--secondary{
  border:1px solid var(--hl-line-2); box-shadow:var(--hl-sh-sm);
}
.hl-section--light .hl-btn--light:hover,
.hl-section--light .hl-btn--secondary:hover,
.hl-section--alt .hl-btn--light:hover,
.hl-section--alt .hl-btn--secondary:hover{ border-color:var(--hl-brand-navy); background:var(--hl-paper); }

/* ── J4.4 · GHOST — the quiet companion to a primary ───────────────────────
   The approved treatment is a translucent white pill for a dark environment.
   The `content`, `promotion` and `products` blocks all render it on a light one,
   where `color:#fff` made the label vanish. On a light band it becomes the same
   shape in ink on white — the design's own light-band treatment, not a new
   button. */
.hl-btn--ghost{ --hl-btn-ink:#fff; color:var(--hl-btn-ink); }
.hl-btn--ghost:hover{ --hl-btn-ink:#fff; }

.hl-section--light .hl-btn--ghost,
.hl-section--alt .hl-btn--ghost{
  --hl-btn-ink:var(--hl-text-dark);
  color:var(--hl-btn-ink);
  background:#fff; border-color:var(--hl-line-2); backdrop-filter:none;
}
.hl-section--light .hl-btn--ghost:hover,
.hl-section--alt .hl-btn--ghost:hover{
  --hl-btn-ink:var(--hl-brand-navy);
  background:var(--hl-paper); border-color:var(--hl-brand-navy);
}

/* ── J4.5 · OUTLINE ───────────────────────────────────────────────────────
   E3 already gave this its light-band form; what it lacked was an ink token, so
   hover still resolved through --hl-btn-fg. */
.hl-btn--outline{ --hl-btn-ink:#fff; color:var(--hl-btn-ink); }
.hl-btn--outline:hover{ --hl-btn-ink:#fff; background:rgba(255,255,255,.10); border-color:rgba(255,255,255,.34); }
.hl-section--light .hl-btn--outline,
.hl-section--alt .hl-btn--outline{ --hl-btn-ink:var(--hl-text-dark); color:var(--hl-btn-ink); }
.hl-section--light .hl-btn--outline:hover,
.hl-section--alt .hl-btn--outline:hover{ --hl-btn-ink:var(--hl-brand-navy); }

/* ── J4.6 · TEXT LINK — the reported bug, and its whole family ─────────────
   Red on a light band, a lighter red on a dark one, and never white on either.
   The hover deepens the red rather than replacing it, so the underline that
   grows underneath is the state change — which is what the design intended. */
.hl-btn--link{ --hl-btn-ink:var(--hl-brand-red); color:var(--hl-btn-ink); }
.hl-btn--link:hover,
.hl-btn--link:active{ --hl-btn-ink:var(--hl-red-700); }

.hl-section--dark .hl-btn--link,
.hl-section--brand .hl-btn--link{ --hl-btn-ink:var(--hl-red-400); }
.hl-section--dark .hl-btn--link:hover,
.hl-section--brand .hl-btn--link:hover{ --hl-btn-ink:var(--hl-red-300); }

.hl-btn--link-light{ --hl-btn-ink:var(--hl-navy-300); color:var(--hl-btn-ink); }
.hl-btn--link-light:hover{ --hl-btn-ink:#fff; }
.hl-section--light .hl-btn--link-light,
.hl-section--alt .hl-btn--link-light{ --hl-btn-ink:var(--hl-navy-500); }
.hl-section--light .hl-btn--link-light:hover,
.hl-section--alt .hl-btn--link-light:hover{ --hl-btn-ink:var(--hl-brand-navy); }

/* The E-bridge reset neutralised --hl-btn-bg and --hl-btn-border for a text
   link and stopped short of the foreground. Completed here. */
.hl-btn--link,
.hl-btn--link:hover,
.hl-btn--link:focus-visible,
.hl-btn--link:active{ --hl-btn-fg:var(--hl-btn-ink); --hl-btn-bg:transparent; --hl-btn-border:transparent; }
.hl-btn--link:focus-visible{ outline-offset:6px; }

/* ── J4.7 · DISABLED ──────────────────────────────────────────────────────
   `opacity:.55` over a red gradient leaves white text at roughly 1.7:1, which is
   the invisible-state failure the audit was looking for. A disabled control is a
   flat neutral with a legible label instead: --hl-text-muted on --hl-paper-2 is
   4.67:1, and 50%-white on a dark band clears AA too. */
.hl-btn[disabled],
.hl-btn[aria-disabled="true"],
.hl-btn.is-disabled{
  opacity:1; cursor:not-allowed; pointer-events:none; transform:none;
  --hl-btn-ink:var(--hl-text-muted); color:var(--hl-btn-ink);
  background:var(--hl-paper-2); background-image:none;
  border:1px solid var(--hl-line-2); box-shadow:none;
}
.hl-section--dark .hl-btn[disabled],
.hl-section--dark .hl-btn[aria-disabled="true"],
.hl-section--dark .hl-btn.is-disabled,
.hl-section--brand .hl-btn[disabled],
.hl-section--brand .hl-btn[aria-disabled="true"],
.hl-section--brand .hl-btn.is-disabled{
  --hl-btn-ink:var(--hl-text-light-3); background:rgba(255,255,255,.07);
  border-color:var(--hl-line-dark-2);
}
/* A disabled text link keeps its shape rather than becoming a grey pill. */
.hl-btn--link[disabled],
.hl-btn--link[aria-disabled="true"],
.hl-btn--link.is-disabled{ background:none; border:0; padding:0; }

/* ── J4.8 · THE OTHER LINK COMPONENTS ─────────────────────────────────────
   `.hl-link-arrow` is components.css's tertiary link and predates the approved
   family. It resolves to --hl-primary, and --hl-accent on hover, which is
   correct on a light band — but on a dark SECTION (as opposed to a `.hl-on-dark`
   container) it was navy on near-black. Same audit, same fix. */
.hl-section--dark .hl-link-arrow,
.hl-section--brand .hl-link-arrow{ color:var(--hl-text-on-dark,#f5f6fb); }
.hl-section--dark .hl-link-arrow:hover,
.hl-section--brand .hl-link-arrow:hover{ color:var(--hl-red-300); }

/* Footer links sit in a dark chrome that is not a `.hl-section`, so they are
   checked here explicitly rather than assumed. */
.hl-footer a:not(.hl-btn):hover{ color:var(--hl-red-300); }


/* ===========================================================================
   J5 · THE SECTION CTA VARIANT — ONE ADMIN SELECT, FIFTEEN VIEWS UNTOUCHED
   ---------------------------------------------------------------------------
   `cta_variant` becomes a class on the SECTION (`hl-cta--v-outline`), not on the
   button. That is what makes the control reachable without editing a view: every
   block that renders a primary action already sits inside a section whose
   classes come from section_classes(), so the fifteen existing views honour this
   without a line of PHP, and a view added next year inherits it for free.

   WHICH button it repaints, and why that needed deciding:

     The views do not agree on what a primary action looks like. Fourteen call
     sites render `.hl-btn--primary`, ten render `.hl-btn--dark`, two render
     `.hl-btn--accent` — all three are the loud one, chosen per block by whoever
     built it. Targeting only `--primary` would have left this control silently
     inert on ten blocks, which is exactly the dead setting this pass exists to
     remove. So all three are targeted, and the quiet companions (`--ghost`,
     `--link`, `--light`, `--outline`, `--secondary`) are deliberately left
     alone: a section whose two actions look identical has no primary action.

     `--sm` is excluded. That size is what the design uses for utility controls
     INSIDE a component — the catalog Search and Apply filters submits, a
     testimonial card Trustpilot button, the page rail action. Those are not the
     section call to action, and turning a form submit into a bare text link
     because an editor set a section CTA variant would be a defect, not a
     preference.

   Every variant below is the SAME paint as its `.hl-btn--x` equivalent in J4,
   band-aware wherever that equivalent is band-aware. This is a re-labelling of
   the approved family, not a seventh button design. `:is()` carries the
   specificity of one class, so each rule is (0,3,0) and each hover (0,4,0) —
   above the variant rules they override, and above nothing else.
   =========================================================================== */

/* ── J5.1 · PRIMARY — the red gradient ─────────────────────────────────── */
.hl-cta--v-primary :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm){
  --hl-btn-ink:#fff; color:var(--hl-btn-ink);
  background:linear-gradient(170deg,var(--hl-red-400),var(--hl-red-600));
  border:0; box-shadow:var(--hl-sh-red), inset 0 1px 0 rgba(255,255,255,.28);
}
.hl-cta--v-primary :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover{
  box-shadow:0 16px 38px -10px rgba(207,41,39,.65), inset 0 1px 0 rgba(255,255,255,.3);
  transform:translateY(-2px);
}

/* ── J5.2 · DARK — the navy gradient ───────────────────────────────────── */
.hl-cta--v-dark :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm){
  --hl-btn-ink:#fff; color:var(--hl-btn-ink);
  background:linear-gradient(170deg,var(--hl-ink-750),var(--hl-ink-850));
  border:0; box-shadow:var(--hl-sh-navy), inset 0 1px 0 rgba(255,255,255,.16);
}
.hl-cta--v-dark :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover{
  box-shadow:0 18px 40px -12px rgba(42,45,124,.55), inset 0 1px 0 rgba(255,255,255,.2);
  transform:translateY(-2px);
}

/* ── J5.3 · LIGHT — a white pill, for a dark band ───────────────────────── */
.hl-cta--v-light :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm){
  --hl-btn-ink:var(--hl-ink-800); color:var(--hl-btn-ink);
  background:#fff; background-image:none; border:0;
  box-shadow:0 10px 24px -12px rgba(0,0,0,.6);
}
.hl-cta--v-light :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover{
  --hl-btn-ink:var(--hl-ink-900); background:var(--hl-paper); transform:translateY(-2px);
}
/* On a LIGHT band a white pill with no edge is a floating label, so it takes the
   same hairline J4.3 gives `.hl-btn--light` there. */
.hl-section--light.hl-cta--v-light :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm),
.hl-section--alt.hl-cta--v-light :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm){
  border:1px solid var(--hl-line-2); box-shadow:var(--hl-sh-sm);
}
.hl-section--light.hl-cta--v-light :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover,
.hl-section--alt.hl-cta--v-light :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover{
  border-color:var(--hl-brand-navy); background:var(--hl-paper);
}

/* ── J5.4 · SECONDARY — the same white pill, edged on every band ─────────
   The distinction J4.3 already draws: `light` is the dark-band treatment,
   `secondary` is the one that carries its own edge wherever it lands. */
.hl-cta--v-secondary :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm){
  --hl-btn-ink:var(--hl-ink-800); color:var(--hl-btn-ink);
  background:#fff; background-image:none;
  border:1px solid var(--hl-line-2); box-shadow:var(--hl-sh-sm);
}
.hl-cta--v-secondary :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover{
  --hl-btn-ink:var(--hl-brand-navy); background:var(--hl-paper);
  border-color:var(--hl-brand-navy); transform:translateY(-2px);
}

/* ── J5.5 · OUTLINE — band-aware, because a transparent pill has to be ─── */
.hl-cta--v-outline :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm){
  --hl-btn-ink:var(--hl-text-dark); color:var(--hl-btn-ink);
  background:#fff; background-image:none;
  border:1px solid var(--hl-line-2); box-shadow:none;
}
.hl-cta--v-outline :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover{
  --hl-btn-ink:var(--hl-brand-navy); background:var(--hl-paper);
  border-color:var(--hl-brand-navy); transform:translateY(-2px);
}
.hl-section--dark.hl-cta--v-outline :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm),
.hl-section--brand.hl-cta--v-outline :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm){
  --hl-btn-ink:#fff; color:var(--hl-btn-ink);
  background:rgba(255,255,255,.03); border-color:var(--hl-line-dark-2);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
}
.hl-section--dark.hl-cta--v-outline :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover,
.hl-section--brand.hl-cta--v-outline :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover{
  --hl-btn-ink:#fff; background:rgba(255,255,255,.10); border-color:rgba(255,255,255,.34);
}

/* ── J5.6 · TEXT LINK — the pill geometry has to go, not just its paint ───
   Mirrors `.hl-btn--link` exactly, including the underline that grows on hover,
   so a section set to Text link produces the design's text link rather than a
   button with its background removed. */
.hl-cta--v-link :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm){
  --hl-btn-ink:var(--hl-brand-red); color:var(--hl-btn-ink);
  height:auto; padding:0; gap:7px; border:0; border-radius:0;
  background:none; box-shadow:none; align-self:flex-start;
  font-size:var(--hl-fs-sm);
}
.hl-cta--v-link :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover{
  --hl-btn-ink:var(--hl-red-700); background:none; box-shadow:none; transform:none;
}
.hl-cta--v-link :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm)::after{
  content:""; position:absolute; left:0; right:22px; bottom:-4px; height:1px;
  background:currentColor; opacity:.28;
  transition:opacity var(--hl-t-med), right var(--hl-t-med) var(--hl-e-out);
}
.hl-cta--v-link :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover::after{
  opacity:.7; right:0;
}
.hl-section--dark.hl-cta--v-link :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm),
.hl-section--brand.hl-cta--v-link :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm){
  --hl-btn-ink:var(--hl-red-400);
}
.hl-section--dark.hl-cta--v-link :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover,
.hl-section--brand.hl-cta--v-link :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover{
  --hl-btn-ink:var(--hl-red-300);
}
/* A text link keeps its focus ring clear of the underline it grows. */
.hl-cta--v-link :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):focus-visible{
  outline-offset:6px;
}

/* ── J6 · SECTION BAND OVERRIDE ────────────────────────────────────────────
   The control that makes "alternate the sections" real.

   THE PROBLEM. Twenty-eight of the approved compositions paint their own
   ground: `.hl-price` is a navy gradient, `.hl-partners` is paper, the three
   heroes are stacked radial glows. Each does it with a single-class selector in
   THIS file, which loads after layout.css — so `.hl-section--light` (0,1,0,
   earlier file) lost to `.hl-price` (0,1,0, later file) and four of the five
   bands were inert wherever a composition was in play. An administrator could
   set "Soft light" on the partner strip and watch nothing happen; worse, on the
   chargeback page two adjacent sections set to `light` and `dark` rendered the
   same navy ground with DIFFERENT accent colours, which looks like a bug in the
   page rather than a limit of the control.

   THE RULE. `section_classes()` compares the stored theme against
   `BlockRegistry::defaultTheme()` and emits `.hl-section--reband` only when they
   differ. So this whole section is dormant on every page nobody has touched —
   and it is dormant by NOT MATCHING, not by resolving to the same value. None
   of the twenty-eight rules below are edited; J6 only adds rules that outrank
   them, which is why "existing pages retain their current appearance" is a
   structural guarantee here and not a promise to be re-tested.

   THE SPECIFICITY. Two classes on the section root plus the composition itself
   inside `:is()`, (0,3,0), against the composition's own (0,1,0) — and last in
   the last stylesheet, which settles navy against layout.css's equally-specific
   `.hl-section--dark.hl-section--navy`. Sections with NO composition need
   nothing here: layout.css's bands were never the losing side for them.

   WHEN THE OVERRIDE IS *NOT* APPLIED, AND WHY THAT MATTERS MORE.
   A composition drawn on paper does not need its ground replaced when the
   selection is Light or Soft light. It already is that band — and its own
   gradient (`.hl-hw` runs paper → white → paper to lift the product shots off
   the fold) is a better rendering of the same answer than a flat fill. Likewise
   a deep-navy composition asked for Deep navy. So those pairings keep the
   artwork and the selection is satisfied rather than ignored.

   Highline navy and Brand gradient always override, on all twenty-eight,
   because they are not different renderings of a ground the composition already
   has: they are the two bands an administrator reaches for precisely to make
   one navy chapter read differently from the navy chapter above it, which is
   the visual-rhythm problem this control exists to solve.

   The effect on the live site, which is the test that counts: of the forty
   sections whose stored theme differs from their block default, ten sit on a
   composition, and all ten are same-family pairings — `hl-partners` + Soft
   light, `hl-price` + Deep navy, `hl-hw` + Light. Every one keeps its artwork.
   Nothing on twenty-six published pages moves by a pixel, and the control is
   nonetheless live the moment anyone chooses across the divide. */

/* A composition drawn on paper, asked for a dark ground. */
.hl-section--reband.hl-section--dark:is(.hl-acc,.hl-ben,.hl-binds,.hl-calc,.hl-cd,
  .hl-faq-sec,.hl-hw,.hl-hw2,.hl-partners,.hl-revs,.hl-rhw,.hl-rwhy,.hl-story,
  .hl-why-sec,.hl-why2){
  background:linear-gradient(178deg, var(--hl-ink-900) 0%, var(--hl-ink-850) 55%, var(--hl-ink-900) 100%);
}
/* A composition drawn on deep navy, asked for a paper ground. */
.hl-section--reband.hl-section--light:is(.hl-final,.hl-floor,.hl-flow,.hl-fund,
  .hl-hero--highline,.hl-ihero,.hl-ind,.hl-ioffer,.hl-net-sec,.hl-price,.hl-rfund,
  .hl-shero,.hl-sys){
  background:var(--hl-bg, #fff);
}
.hl-section--reband.hl-section--alt:is(.hl-final,.hl-floor,.hl-flow,.hl-fund,
  .hl-hero--highline,.hl-ihero,.hl-ind,.hl-ioffer,.hl-net-sec,.hl-price,.hl-rfund,
  .hl-shero,.hl-sys){
  background:var(--hl-paper, #f5f7fc);
}
/* The two that always win, on either family. */
.hl-section--reband.hl-section--navy:is(.hl-acc,.hl-ben,.hl-binds,.hl-calc,.hl-cd,
  .hl-faq-sec,.hl-final,.hl-floor,.hl-flow,.hl-fund,.hl-hero--highline,.hl-hw,
  .hl-hw2,.hl-ihero,.hl-ind,.hl-ioffer,.hl-net-sec,.hl-partners,.hl-price,.hl-revs,
  .hl-rfund,.hl-rhw,.hl-rwhy,.hl-shero,.hl-story,.hl-sys,.hl-why-sec,.hl-why2){
  background:linear-gradient(178deg, var(--hl-primary-dark, #1b1e45) 0%, var(--hl-primary, #2a2d7c) 100%);
}
.hl-section--reband.hl-section--brand:is(.hl-acc,.hl-ben,.hl-binds,.hl-calc,.hl-cd,
  .hl-faq-sec,.hl-final,.hl-floor,.hl-flow,.hl-fund,.hl-hero--highline,.hl-hw,
  .hl-hw2,.hl-ihero,.hl-ind,.hl-ioffer,.hl-net-sec,.hl-partners,.hl-price,.hl-revs,
  .hl-rfund,.hl-rhw,.hl-rwhy,.hl-shero,.hl-story,.hl-sys,.hl-why-sec,.hl-why2){
  background:var(--hl-gradient-brand);
}

/* ── J6.1 · THE LEGIBILITY GUARD — dark composition, light band ─────────────
   Requirement 16 says a CMS selection must never produce invisible text, and
   must fall back to the nearest safe design-system foreground on its own.

   This is where that bites hardest. A composition drawn for a dark ground has
   its ink written into its children — thirty-nine declarations across the
   thirteen dark compositions, on a four-tier ladder plus one accent:

     #fff                  the headline / the strong value
     --hl-text-light-2     .74  the lede
     --hl-text-light-3     .50  the supporting line
     --hl-text-light-4     .34  the disclaimer
     --hl-navy-300              the accent word, the contact link

   Re-band the section to white and all five vanish. So the marker that raises
   the band also remaps that ladder onto the light-ground ramp, tier for tier,
   preserving the hierarchy the composition was designed with rather than
   flattening everything to one ink. `:is()` keeps the lists readable and
   carries the specificity of its most specific argument, so a descendant
   selector like `.hl-final__stack em` is still outranked.

   ONE EXCLUSION, AND IT IS THE WHOLE DIFFICULTY OF THIS GUARD. Ink only follows
   the band if the band is what is actually behind it. Most of these panels are
   either unpainted or painted in translucent white — `.hl-ind__aside` is 7%
   white, `.hl-ioffer__card` is a red-over-navy wash — so on a paper band they
   resolve to paper and their ink has to go dark with it. `.hl-sysfoot` does
   not: it is `--hl-ink-950`, opaque, near-black, and it stays near-black no
   matter what the section does. Flipping its ink would have produced exactly
   the invisible text this guard exists to prevent, from inside the guard. It is
   excluded here and re-asserted in J6.5 along with the other opaque islands. */

/* The SECTION HEADINGS are split out of the tier-1 list below, with one extra
   condition: they step aside when the administrator has chosen a heading ink.
   Everything else in that list — ledes, emphasised words, step labels — has no
   control pointed at it and is remapped unconditionally.

   Without the split, "Heading colour" was inert on every composition in this
   list. `:is()` takes the specificity of its most specific argument, and
   `.hl-sysempty .hl-h2` made the whole rule (0,4,0) — above anything the
   control could reasonably assert. The same automatic-then-overridable order
   as J6.4, and only for the inks that are safe on this ground (M11 decides
   which). */
.hl-section--reband:is(.hl-section--light,.hl-section--alt):not([class*="hl-hd--"])
:is(.hl-final__title, .hl-ioffer__title, .hl-price__title, .hl-shero__h1){
  color:var(--hl-ink-900);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt)
:is(.hl-final__stack span, .hl-final__stack em,
    .hl-ind__aside b, .hl-ioffer__tag, .hl-ioffer__amt b,
    .hl-ioffer__pts span, .hl-price__lede,
    .hl-price__body strong, .hl-price__steps b, .hl-rfund__grid b,
    .hl-sysempty .hl-h2){
  color:var(--hl-ink-900);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt)
:is(.hl-final__lede, .hl-floor__foot span, .hl-ioffer__copy, .hl-price__body,
    .hl-shero__lede, .hl-sysempty .hl-lead){
  color:var(--hl-text-body);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt)
:is(.hl-final__chips li, .hl-fund__note, .hl-ind__aside p, .hl-ioffer__amt span,
    .hl-price__steps span:last-child, .hl-rfund__grid span:last-child){
  color:var(--hl-text-muted);
}
/* The .34 tier is a disclaimer, not decoration — it stays quieter than body
   copy but still has to clear AA, so it lands on the same audited muted token
   rather than on a paler one invented for the purpose. */
.hl-section--reband:is(.hl-section--light,.hl-section--alt)
:is(.hl-floor__roomtag, .hl-fund__disclaimer, .hl-ioffer__disc,
    .hl-net-sec__disc, .hl-price__disc, .hl-rfund__note){
  color:var(--hl-text-muted);
}
/* The accent word. --hl-navy-300 is a pale lavender chosen to glow on navy; on
   paper it is barely there, so it steps down the ramp to the brand navy. */
.hl-section--reband:is(.hl-section--light,.hl-section--alt)
:is(.hl-ind__aside-ico, .hl-shero__h1 em){
  color:var(--hl-navy-600);
}

/* ── J6.2 · THE SAME GUARD FOR SURFACES AND HAIRLINES ──────────────────────
   Text is the requirement, but a chip whose ground was `rgba(255,255,255,.05)`
   and a card hairline that was `inset 0 1px 0 rgba(255,255,255,.12)` disappear
   on white too — and a list of steps that loses its tiles reads as broken
   markup rather than as a design choice. Same inversion, same ramp. */
.hl-section--reband:is(.hl-section--light,.hl-section--alt)
:is(.hl-final__stack span, .hl-final__stack em, .hl-floor__foot span,
    .hl-ioffer__pts, .hl-price__steps li, .hl-rfund__grid li){
  background:var(--hl-paper-2);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt)
:is(.hl-price__steps li:hover, .hl-rfund__grid li:hover){
  background:var(--hl-paper-3);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-ind__aside{
  background:linear-gradient(155deg, var(--hl-paper), var(--hl-white));
  border-color:var(--hl-line);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-ioffer__card{
  box-shadow:var(--hl-sh-lg), inset 0 1px 0 var(--hl-white);
}
/* The decorative SVG layers. These are aria-hidden artwork, so the standard is
   "still visible" rather than any contrast ratio — a route drawn in 9% white on
   a white band is simply gone, and the section loses the infrastructure motif
   that ties it to the rest of the site. */
.hl-section--reband:is(.hl-section--light,.hl-section--alt)
:is(.hl-final__conv .hl-rte__base, .hl-floor__div, .hl-floor .hl-sroute){
  stroke:var(--hl-line-2);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-floor__room{
  stroke:var(--hl-line-2); fill:rgba(42,45,124,.022);
}
/* The red glow behind the closing CTA is a light source. It has nothing to lift
   off a white ground, and left in place it reads as a printing error. */
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-final__glow{
  opacity:.14;
}

/* ── J6.3 · THE OTHER DIRECTION — light composition, dark band ──────────────
   Cheaper, because the fifteen light compositions took their ink from tokens
   rather than writing it down, and layout.css's `.hl-section--dark` already
   flips those tokens for the whole subtree. What it does not flip is a panel
   ground written as a literal white — those survive as white slabs on navy,
   which is legible but reads as a different section pasted in. Every selector
   below was taken from the stylesheet, not guessed: these are the only five
   panels in those fifteen compositions that paint their own light ground. */
.hl-section--reband:is(.hl-section--dark,.hl-section--navy,.hl-section--brand)
:is(.hl-calcbox, .hl-hw2__note, .hl-rhw__feature, .hl-rhw__note){
  background:rgba(255,255,255,.045);
  border-color:var(--hl-line-dark-2);
  box-shadow:none;
}
/* The hardware stage is a lit alcove for a product shot. Inverted, it becomes a
   pool of shadow instead — same gesture, opposite ground. */
.hl-section--reband:is(.hl-section--dark,.hl-section--navy,.hl-section--brand) .hl-rhw__art{
  background:radial-gradient(ellipse 70% 60% at 50% 42%, rgba(255,255,255,.07), transparent 70%);
  border-color:var(--hl-line-dark-2);
}
/* The product placeholder frame is drawn in the light hairline because the
   three hardware chapters are light. On a dark band that edge disappears and
   the silhouette floats. */
.hl-section--reband:is(.hl-section--dark,.hl-section--navy,.hl-section--brand) .hl-pslot__ph{
  --hl-ph-name:var(--hl-text-light-2); --hl-ph-note:var(--hl-text-light-4);
}

/* ── J6.4 · CHAPTER NUMERALS AND EYEBROWS FOLLOW THE BAND ──────────────────
   Both already resolve through `--hl-cn-ink` / `--hl-eb-ink` (J1, J2), and both
   have a per-section override an administrator may have set. So this supplies
   only the DEFAULT for the new ground, and does it at the section root where an
   explicit `.hl-cn--*` / `.hl-eb--*` class or the `.hl-s-<id>` custom colour
   both outrank it — the automatic answer, overridable, in that order. */
/* CORRECTED in the visual correction pass. The paragraph above says an explicit
   `.hl-cn--*` / `.hl-eb--*` class outranks these defaults. It did not.
   `.hl-section--reband:is(…)` is (0,2,0) and `.hl-cn--red` is (0,1,0), so the
   automatic answer beat the administrator's on every re-banded section — which
   is precisely the set of sections an editor is most likely to be tuning. A
   control test that set all seven chapter inks and all five eyebrow inks on a
   re-banded section measured ONE resulting colour.

   Specificity cannot settle it — raising these would break the other direction
   — so they now simply do not match when a choice has been made. The accent
   classes carry unique prefixes, so `:not([class*="hl-cn--"])` is exact: the
   automatic answer applies, is overridable, in that order, and now actually is. */
.hl-section--reband:is(.hl-section--light,.hl-section--alt):not([class*="hl-cn--"]){
  --hl-cn-ink:var(--hl-line-2);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt):not([class*="hl-eb--"]){
  --hl-eb-ink:var(--hl-brand-red);
  --hl-eb-bar:linear-gradient(180deg,var(--hl-red-400),var(--hl-red-600));
  --hl-eb-glow:0 0 12px rgba(207,41,39,.6);
}
.hl-section--reband:is(.hl-section--dark,.hl-section--navy,.hl-section--brand):not([class*="hl-cn--"]){
  --hl-cn-ink:rgba(255,255,255,.16);
}
.hl-section--reband:is(.hl-section--dark,.hl-section--navy,.hl-section--brand):not([class*="hl-eb--"]){
  --hl-eb-ink:var(--hl-navy-300);
  --hl-eb-bar:linear-gradient(180deg,var(--hl-navy-300),var(--hl-navy-500));
  --hl-eb-glow:0 0 12px rgba(144,150,228,.45);
}
/* Nothing further is needed for the numeral itself. `section_head_class()` and
   the two views that hand-roll the same ternary all ask `section_is_dark()`,
   which reads the SAME stored theme this class was emitted from — so a section
   re-banded to light never carries `hl-ihead--light`, and one re-banded to dark
   always does. The outline stroke already resolves through `--hl-cn-ink`, so the
   two declarations above are the whole of it. Worth stating, because the
   obvious-looking `-webkit-text-stroke-color` override here would be dead code
   guarding a state the renderer cannot produce. */

/* ── J6.5 · THE OPAQUE ISLANDS ─────────────────────────────────────────────
   Four panels paint an opaque dark ground of their own and keep it whatever the
   section does: the catalog footer (`--hl-ink-950`), the why-panel feature card,
   the calculator's result half, and the industry floor's detail panel. Three of
   them already live inside LIGHT compositions, which is why their eyebrows are
   marked `--light` unconditionally in the views — correct then, correct now.

   What reaches them is inheritance, not a selector: J6.4 sets `--hl-eb-ink` on
   the section root, and a custom property set on an ancestor does not stop at a
   panel boundary. So a re-banded light section would hand these dark panels the
   red-on-paper eyebrow meant for the band outside them. Re-asserting the
   dark-ground values here is the whole fix, and it is the same shape as the
   problem: one token, set closer to the element that reads it.

   `.hl-sysfoot`'s ink is restated too, because J6.1 excludes it and its own
   rules resolve to the light ramp only by virtue of not being overridden — that
   is a guarantee worth writing down rather than inferring. */
.hl-section--reband
:is(.hl-sysfoot, .hl-wfeat, .hl-calcbox__result, .hl-fpanel){
  --hl-eb-ink:var(--hl-navy-300);
  --hl-eb-bar:linear-gradient(180deg,var(--hl-navy-300),var(--hl-navy-500));
  --hl-eb-glow:0 0 12px rgba(144,150,228,.45);
  --hl-cn-ink:rgba(255,255,255,.16);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-sysfoot p{
  color:var(--hl-text-light-3);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-sysfoot__contact a{
  color:var(--hl-navy-300);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-sysfoot__contact a:hover{
  color:#fff;
}


/* ===========================================================================
   K · THE PRODUCT DETAIL TEMPLATE — hero discipline, gallery, chapter variants
   ---------------------------------------------------------------------------
   The PDP is one shared template (resources/views/products/detail.php) built
   from numbered chapters. This section carries what the chapters need that
   the block vocabulary does not already provide:

     K1  hero media discipline — a real photograph may not dominate the
         viewport; it fits INTO the stage frame like everything else
     K2  feature presentation variants — rows / checks / cards / tiles
     K3  band inversions for chapters an administrator has re-banded
         (the seeded rhythm is light overview / dark features / light specs /
         navy built-for, and every component above was drawn for its seed)
     K4  the light-hero guard — a hero re-banded to white must take its price,
         maker and gallery chrome with it

   Tokens that do NOT flip on `.hl-section--dark` (--hl-paper, --hl-line,
   --hl-text-dark, --hl-text-body) are avoided in new components or given an
   explicit dark override here — see layout.css for the flip list.
   =========================================================================== */

/* ── K1 · HERO MEDIA DISCIPLINE ────────────────────────────────────────────
   The stage is a fixed-height alcove, not a canvas the upload inflates. A
   2000×1000 lifestyle shot and a 300×800 portrait both land inside the same
   frame at comparable scale: contain behaviour, internal padding, and a hard
   cap so no photograph ever pushes the hero past one viewport. */
.hl-pdphero .hl-rstage__frame{ position:relative; z-index:2; }
.hl-pdphero .hl-rstage__slot{ min-height:280px; }
.hl-pdphero .hl-rstage__slot img{ max-height:380px; }
.hl-pdphero .hl-shero__viz.hl-ihero__viz{ width:100%; max-width:520px; margin-inline:auto; }

/* ── K2 · FEATURE PRESENTATION VARIANTS ────────────────────────────────────
   One structured list, four approved treatments. The admin enters label +
   detail + optional icon; this decides what that becomes. */
.hl-pfeat--checks{
   grid-template-columns:repeat(auto-fill, minmax(min(100%, 300px), 1fr));
   gap:0 clamp(20px, 3vw, 44px);
}
.hl-pfeat--checks .hl-pfeat__row{
   background:none; border:0; border-bottom:1px solid var(--hl-line-dark);
   border-radius:0; padding:12px 2px;
}
.hl-pfeat--cards,
.hl-pfeat--tiles{
   grid-template-columns:repeat(auto-fill, minmax(min(100%, 250px), 1fr));
   gap:clamp(14px, 1.8vw, 22px);
}
.hl-pfeat__card{
   min-width:0; padding:20px 18px; background:#fff;
   border:1px solid var(--hl-line); border-radius:var(--hl-r-xl);
   box-shadow:var(--hl-sh-sm);
}
.hl-pfeat__ico{ display:block; width:22px; height:22px; margin:0 0 12px; color:var(--hl-brand-red); }
.hl-pfeat__card b{ display:block; font:600 var(--hl-fs-body)/1.35 var(--hl-ff-display); color:var(--hl-text-dark); }
.hl-pfeat__card i{ display:block; margin-top:5px; font-style:normal; font-size:var(--hl-fs-xs); line-height:1.6; color:var(--hl-text-muted); }
/* Tiles: the dense variant — quiet ground, a navy rule where the card's top
   edge would be, no shadow. */
.hl-pfeat--tiles{ grid-template-columns:repeat(auto-fill, minmax(min(100%, 215px), 1fr)); }
.hl-pfeat--tiles .hl-pfeat__card{
   background:transparent; border:1px solid var(--hl-line);
   border-top:2px solid var(--hl-brand-navy); border-radius:var(--hl-r-lg);
   box-shadow:none; padding:16px;
}

/* The dark-band forms of every treatment. Features seed onto deep navy, so
   these are the DEFAULTS in practice; the light forms above are what a
   re-banded chapter gets. */
.hl-section--dark .hl-pfeat__row,
.hl-section--brand .hl-pfeat__row{
   background:rgba(255,255,255,.045); border-color:var(--hl-line-dark-2);
}
.hl-section--dark .hl-pfeat__txt b,
.hl-section--brand .hl-pfeat__txt b{ color:#fff; }
.hl-section--dark .hl-pfeat__txt i,
.hl-section--brand .hl-pfeat__txt i{ color:var(--hl-text-light-3); }
.hl-section--dark .hl-pfeat__card,
.hl-section--brand .hl-pfeat__card{
   background:rgba(255,255,255,.05); border-color:var(--hl-line-dark-2); box-shadow:none;
}
.hl-section--dark .hl-pfeat__card b,
.hl-section--brand .hl-pfeat__card b{ color:#fff; }
.hl-section--dark .hl-pfeat__card i,
.hl-section--brand .hl-pfeat__card i{ color:var(--hl-text-light-3); }
.hl-section--dark .hl-pfeat--tiles .hl-pfeat__card,
.hl-section--brand .hl-pfeat--tiles .hl-pfeat__card{
   background:transparent; border-top-color:var(--hl-navy-300);
}

/* ── K3 · CHAPTER BAND INVERSIONS ───────────────────────────────────────────
   Specifications seed onto light, Built For onto navy — the opposite of how
   their components were first drawn. These overrides make each component
   correct on EITHER family, which is what makes the per-chapter band selects
   safe to offer at all. */
.hl-section--light .hl-pspecs__title,
.hl-section--alt .hl-pspecs__title{ color:var(--hl-brand-navy); }
.hl-section--light .hl-pspecs__row,
.hl-section--alt .hl-pspecs__row{ border-bottom-color:var(--hl-line); }
.hl-section--light .hl-pspecs__row dt,
.hl-section--alt .hl-pspecs__row dt{ color:var(--hl-text-muted); }
.hl-section--light .hl-pspecs__row dd,
.hl-section--alt .hl-pspecs__row dd{ color:var(--hl-text-dark); }

.hl-section--dark .hl-puse__card,
.hl-section--navy .hl-puse__card,
.hl-section--brand .hl-puse__card{
   background:rgba(255,255,255,.05); border-color:var(--hl-line-dark-2); box-shadow:none;
}
.hl-section--dark .hl-puse__title,
.hl-section--navy .hl-puse__title,
.hl-section--brand .hl-puse__title{ color:#fff; }
.hl-section--dark .hl-puse__text,
.hl-section--navy .hl-puse__text,
.hl-section--brand .hl-puse__text{ color:var(--hl-text-light-3); }
.hl-section--dark .hl-puse__ico,
.hl-section--navy .hl-puse__ico,
.hl-section--brand .hl-puse__ico{ color:var(--hl-red-400); }

.hl-section--dark .hl-pdpfin,
.hl-section--navy .hl-pdpfin,
.hl-section--brand .hl-pdpfin{
   background:rgba(255,255,255,.04); border-color:var(--hl-line-dark-2); box-shadow:none;
}
.hl-section--dark .hl-pdpfin__title,
.hl-section--navy .hl-pdpfin__title,
.hl-section--brand .hl-pdpfin__title{ color:#fff; }
.hl-section--dark .hl-pdpfin__note,
.hl-section--navy .hl-pdpfin__note,
.hl-section--brand .hl-pdpfin__note{ color:var(--hl-text-light-2); }
.hl-section--dark .hl-pdpfin__disc,
.hl-section--navy .hl-pdpfin__disc,
.hl-section--brand .hl-pdpfin__disc{ color:var(--hl-text-light-3); }
.hl-section--dark .hl-pdpfin .hl-eyebrow,
.hl-section--navy .hl-pdpfin .hl-eyebrow,
.hl-section--brand .hl-pdpfin .hl-eyebrow{ color:var(--hl-navy-300); }

/* ── K4 · THE LIGHT-HERO GUARD ──────────────────────────────────────────────
   The product hero is drawn for deep navy. An administrator who re-bands it
   to Light or Soft light gets these corrections with the band — the J6
   mechanism covers the headline, lede and crumb; the price ladder, maker line
   and gallery chrome are PDP-specific and live here instead. */
.hl-section--reband:is(.hl-section--light,.hl-section--alt)
:is(.hl-pdp__maker, .hl-pdp__price i, .hl-pdp__price small, .hl-rstage__foot){
   color:var(--hl-text-muted);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-pdp__price b{ color:var(--hl-ink-900); }
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-pdp__call{ color:var(--hl-brand-navy); }
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-shero__h1 em{ color:var(--hl-navy-600); }
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-chips li{
   color:var(--hl-text-body); background:var(--hl-paper); border-color:var(--hl-line);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-pgal__thumb{
   background:var(--hl-paper); border-color:var(--hl-line);
}
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-pgal__thumb:hover{ background:var(--hl-paper-2); }
.hl-section--reband:is(.hl-section--light,.hl-section--alt) .hl-infra{ opacity:.16; }

/* ── K5 · RESPONSIVE ───────────────────────────────────────────────────────── */
@media (max-width:760px){
   /* The stage shrinks WITH the phone rather than dominating it, and the
      gallery stays thumb-sized enough to keep four in view. */
   .hl-pdphero .hl-shero__viz.hl-ihero__viz{ max-width:440px; }
   .hl-pdphero .hl-rstage__slot{ min-height:210px; }
   .hl-pdphero .hl-rstage__slot img{ max-height:260px; }
   .hl-pgal{ gap:6px; }
   .hl-pgal__thumb{ width:48px; height:48px; }
   /* Checks and tiles collapse to one column before they get cramped — a
      check row needs its hairline to read, and two-up tiles under 215px
      truncate labels. */
   .hl-pfeat--checks{ grid-template-columns:minmax(0,1fr); }
   .hl-pfeat--cards,
   .hl-pfeat--tiles{ grid-template-columns:minmax(0,1fr); }
}
@media (max-width:420px){
   .hl-pgal__thumb{ width:42px; height:42px; padding:4px; }
}
@media (prefers-reduced-motion:reduce){
   .hl-pgal__thumb{ transition:none; }
}


/* ===========================================================================
   L · PAGE START, INHERITED INK, AND THE BANDS BETWEEN CHAPTERS
   ---------------------------------------------------------------------------
   Added by the visual correction pass. Three defect families, each fixed once
   at the layer that causes it rather than at the places it showed up:

     L1  headings that took body ink on a dark band and vanished
     L2  the header's hairline sitting OUTSIDE the height every hero pulls up by
     L3  chapter rhythm — the vertical space between a chapter head and its
         content, which several sections had far too much of

   Every rule here is either a token re-point or a spacing correction. Nothing
   introduces a colour an administrator did not already have, and nothing adds
   a control.
   =========================================================================== */

/* ── L1 · HEADING INK FOLLOWS THE BAND ─────────────────────────────────────
   `:where(body.hl-body) h1…h4` sets the heading colour for every heading that
   does not carry a component class naming one. Its specificity (0,0,1) beats
   INHERITANCE, so `.hl-section--dark { color: … }` never reached those
   headings — and five published pages rendered an H1 in #0A0E24 on a #0A0B1F
   hero at 1.02:1. /terms, /privacy-policy, /easysign, /system/404 and
   /system/maintenance were all completely headless to a reader.

   The base rule now resolves through `--hl-heading-ink`, so a band re-points
   the token instead of fighting the cascade. A component that names its own
   colour is untouched; a component that relies on inheritance now inherits
   something correct. */
.hl-section--dark,
.hl-section--brand,
.hl-on-dark,
.hl-footer,
.hl-drawer,
.hl-announce,
.hl-promo-modal__card{ --hl-heading-ink:var(--hl-text-light); }

/* A light island inside a dark chapter keeps dark heading ink: the token
   inherits across the panel boundary exactly the way J6.5 describes for
   eyebrows, and a white heading on a white card is the same bug in the other
   direction. Islands are named rather than guessed, and each one is a panel
   that paints an opaque light ground of its own. */
.hl-section--dark :is(.hl-pcard, .hl-card, .hl-panel--light, .hl-mega, .hl-dropdown,
                      .hl-form, .hl-note--light, .hl-tile--light),
.hl-section--brand :is(.hl-pcard, .hl-card, .hl-panel--light, .hl-mega, .hl-dropdown,
                       .hl-form, .hl-note--light, .hl-tile--light){
  --hl-heading-ink:var(--hl-text-dark);
}

/* The other direction: a section re-banded onto a light ground by an
   administrator (J6) must take dark heading ink back, because the marker class
   sits on the same element as the `--dark` class it replaced. */
.hl-section--reband:is(.hl-section--light,.hl-section--alt){ --hl-heading-ink:var(--hl-text-dark); }

/* ── L2 · THE HEADER'S OWN HEIGHT ──────────────────────────────────────────
   `.hl-header` is `position:sticky`, so it OCCUPIES flow space, and every dark
   opening hero cancels that space with `margin-top:calc(var(--hl-nav-h) * -1)`
   and gives it back as padding. The header's 1px bottom border made its border
   box 1px TALLER than `--hl-nav-h`, so every one of those pull-ups landed a
   pixel short and left a hairline of white page background across the top of
   the hero, under the announcement bar, on every page.

   Moving the hairline to a pseudo-element makes the border box exactly
   `--hl-nav-h` — which is the number the rest of the stylesheet already
   assumes — and paints the same line in the same place. */
.hl-header{ border-bottom-width:0; }
.hl-header::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:1px;
  background:transparent; pointer-events:none;
  transition:background-color var(--hl-t-med) var(--hl-e-soft);
}
.hl-header:not(.hl-header--over-hero)::after,
.hl-header.is-stuck::after{ background:var(--hl-line-dark); }

/* The mega panel hangs off `top:100%`, which is now 1px higher; the panel's own
   top border keeps the join reading as one edge. */

/* ── L4 · THE GLASS PANELS RAISE THE FLOOR ─────────────────────────────────
   The approved diagram panels are translucent surfaces floating ON a dark
   chapter — `rgba(42,45,124,.34)` over navy, `rgba(255,255,255,.05)` nodes on
   top of that. Their interior sits several steps lighter than the band around
   them, so the two quiet inks that clear 4.5:1 against the band do NOT clear it
   inside the panel: the acceptance diagram's captions measured 3.8:1 on every
   service page, and the home page's payment-flow cards 3.2:1.

   The token, not the rules, is what moves — the same shape as J6.5. Each panel
   re-points the quiet inks for its own interior, so every caption, unit, index
   and footnote inside it follows without a single one being named. */
.hl-accv,
.hl-corenode,
.hl-ipanel,
.hl-fchart,
.hl-mini,
.hl-pz{
  --hl-text-light-3:rgba(255,255,255,.74);
  --hl-text-light-4:rgba(255,255,255,.64);
}

/* The home page's floating payment cards sit on the lightest ground of the set
   — a navy gradient that reaches #434891 — so they need one step more again. */
.hl-ecard{
  --hl-text-light-3:rgba(255,255,255,.82);
  --hl-text-light-4:rgba(255,255,255,.72);
}

/* Two accents inside those panels are hues rather than tints, so they cannot be
   fixed by an alpha. The step index sits in a red-tinted chip on a violet card
   at 3.92:1 in `--hl-red-300`; the chip keeps its brand tint and the numeral
   takes the white the neighbouring card labels already use. */
.hl-ecard__step{ color:#fff; }
.hl-ipanel__kicker{ color:#B9BDF0; }

/* ── L5 · THE LAST TWO CONTRAST HOLD-OUTS ─────────────────────────────────
   `.hl-btn--link-light` is the text-link button on a dark band. It was painted
   in `--hl-red-400`, which is 4.19:1 on the navy panel it is used on — the same
   family of defect J4.6 fixed for the light-band text link, one ramp step short.
   `--hl-red-300` is the dark-band member of that pair and clears 7:1. */
.hl-btn--link-light{ --hl-btn-ink:var(--hl-red-300); color:var(--hl-red-300); }
.hl-btn--link-light:hover,
.hl-btn--link-light:focus-visible,
.hl-btn--link-light:active{ --hl-btn-ink:#fff; color:#fff; }

/* The product card's "Most requested" chip: brand red on a 6%-red ground is
   4.49:1, which is a rounding error away from AA and reads as a pass in a
   screenshot. One ramp step down on the ink clears it at 5.6:1 and is
   indistinguishable at 11px. */
.hl-pcard__badge{ color:var(--hl-red-600); }


/* ===========================================================================
   M · PRODUCT DETAIL COMPOSITION
   ---------------------------------------------------------------------------
   The chapter architecture was right; its proportions were not. Every rule
   below is a spacing or a track-count correction to a composition that already
   existed — no new component, no new control, and nothing that changes what an
   administrator can choose.
   =========================================================================== */

/* ── M1 · THE CHAPTER HEAD ─────────────────────────────────────────────────
   `.hl-ihead` reserves `--hl-s-14` under itself, which is right for a chapter
   that opens with a wide diagram and far too much for one that opens with a
   list. On the product page it read as a heading marooned above its own
   content — the "very large empty area before the actual feature content" in
   the review. The gap is now proportional and the numeral column stops eating
   a third of the measure on a narrow chapter. */
.hl-pdp-chapter .hl-ihead{ margin-bottom:clamp(24px,2.6vw,40px); }
.hl-pdp-chapter .hl-ihead__lede{ margin-top:var(--hl-s-4); max-width:56ch; }

/* ── M2 · KEY FEATURES ─────────────────────────────────────────────────────
   Two columns from 900px up, one below it, for every treatment. `rows` was a
   single column at ANY width, so four short labels became four full-bleed bars
   with a thousand pixels of empty space to the right of each one. */
@media (min-width:900px){
   .hl-pfeat{ grid-template-columns:repeat(2, minmax(0,1fr)); gap:12px clamp(18px,2vw,28px); }
   .hl-pfeat--checks{ grid-template-columns:repeat(2, minmax(0,1fr)); }
}
@media (min-width:1280px){
   /* Three columns only when the entries are short enough to keep a sane
      measure — the check list — and never for detailed cards, whose paragraphs
      need the width. */
   .hl-pfeat--checks{ grid-template-columns:repeat(3, minmax(0,1fr)); }
}
@media (max-width:899px){
   .hl-pfeat,
   .hl-pfeat--checks,
   .hl-pfeat--cards,
   .hl-pfeat--tiles{ grid-template-columns:minmax(0,1fr); }
}

/* A check row carries a label and nothing else, so it does not need a card's
   padding; the hairline and the tick are the whole affordance. */
.hl-pfeat--checks .hl-pfeat__row{ align-items:center; }
.hl-pfeat--checks .hl-pfeat__txt b{ font-size:var(--hl-fs-sm); }

/* ── M3 · SPECIFICATIONS ───────────────────────────────────────────────────
   The definition list ran the full width with the value column starting at
   about 45%, so three specifications occupied a 1,200px band and left most of
   it blank. Capped to a readable measure and paired up on desktop. */
.hl-pspecs{ max-width:960px; }
@media (min-width:900px){
   .hl-pspecs{ grid-template-columns:repeat(2, minmax(0,1fr)); }
   /* One group on its own should not be stretched across both tracks. */
   .hl-pspecs__group:only-child{ grid-column:1 / -1; max-width:640px; }
}

/* ── M4 · FINANCING ────────────────────────────────────────────────────────
   The chapter now carries a standard head, so the card holds only the note,
   the disclaimer and the action — and it no longer needs a heading's worth of
   padding above them. */
.hl-pdpfin{ padding:clamp(22px,2.4vw,34px); align-items:center; }
.hl-pdpfin__copy{ max-width:70ch; }
.hl-pdpfin__note{ margin:0 0 var(--hl-s-3); }

/* ── M5 · RELATED EQUIPMENT ────────────────────────────────────────────────
   `auto-fill` with a 280px track gives four columns at 1440px, so three
   related devices sat in three of four tracks with an empty column beside
   them. The related row is a fixed three-up on desktop: the repository asks
   for three, so the grid should be built for three. */
@media (min-width:1024px){
   .hl-pgrid--rel{ grid-template-columns:repeat(3, minmax(0,1fr)); }
}
@media (min-width:640px) and (max-width:1023px){
   .hl-pgrid--rel{ grid-template-columns:repeat(2, minmax(0,1fr)); }
}

/* ── M6 · THE TERTIARY ACTION ──────────────────────────────────────────────
   "The Account Behind It" leaves the device, so it is a text-arrow link under
   the pair rather than a third pill wrapping onto its own line.

   `.hl-link-arrow` predates the approved arrow glyph and animates a child
   called `.hl-link-arrow__icon`; every other arrow on this site is
   `.hl-arrow`, and that is what the views emit. Without this the tertiary
   link would be the one arrow on the page that does not move. */
.hl-pdp__tertiary{ margin:var(--hl-s-6) 0 0; display:flex; flex-wrap:wrap; gap:var(--hl-s-6); }
.hl-pdp__tertiary--center{ justify-content:center; margin-top:var(--hl-s-6); }
.hl-link-arrow .hl-arrow{ transition:transform var(--hl-t-med) var(--hl-e-out); }
.hl-link-arrow:hover .hl-arrow{ transform:translateX(4px); }
@media (prefers-reduced-motion:reduce){
  .hl-link-arrow .hl-arrow{ transition:none; }
  .hl-link-arrow:hover .hl-arrow{ transform:none; }
}

/* ── M7 · THE HERO ─────────────────────────────────────────────────────────
   Compact and balanced: the copy column keeps a readable measure, the chips
   sit tight under the actions, and the stage never grows past the copy beside
   it. */
.hl-pdphero .hl-shero__shell{ padding-block:clamp(36px,3.6vw,60px) var(--hl-hero-air); }
.hl-pdphero .hl-shero__h1{ margin-bottom:var(--hl-s-4); }
.hl-pdphero .hl-pdp__maker{ margin:0 0 var(--hl-s-4); }
.hl-pdphero .hl-shero__lede{ margin-bottom:var(--hl-s-6); max-width:46ch; }
/* The chips' own top margin used to be set here, for this hero only, because
   the shared `.hl-chips` margin was being suppressed site-wide (see the list
   reset near the top of this file). Section N now gives every chip list the
   same `--hl-flow-tight` step, so the PDP-only patch is gone and this hero is
   no longer a special case. */

/* ── M8 · THE CLOSING BAND ON EITHER FAMILY ────────────────────────────────
   `.hl-pdpend` hard-coded `#fff` for its heading and a light-band ink for its
   copy, which is correct on the deep navy it is pinned to and invisible the
   moment the band is anything else. The band is an administrator's choice, so
   the component has to work on both families — the same guarantee K3 gives the
   specification list and the use-case cards. */
.hl-section--light .hl-pdpend__title,
.hl-section--alt .hl-pdpend__title{ color:var(--hl-text-dark); }
.hl-section--light .hl-pdpend__text,
.hl-section--alt .hl-pdpend__text{ color:var(--hl-text-body); }

/* The financing card is drawn for a light band; on a dark one it becomes the
   translucent panel the rest of the dark chapters use. That rule already
   existed for `--dark`/`--navy`/`--brand`; what it lacked was the disclaimer. */
.hl-section--dark .hl-pdpfin__disc,
.hl-section--navy .hl-pdpfin__disc,
.hl-section--brand .hl-pdpfin__disc{ color:var(--hl-text-light-4); }

/* ── M9 · THE CARD BADGE AS A FLAG ─────────────────────────────────────────
   Pinned to the media stage so it costs no flow height and every card in a row
   keeps its title, copy and affordance on the same baselines. The stage is
   already a fixed alcove (`--hl-pslot-h`), so nothing here can change a card's
   height whatever the artwork is. */
.hl-pcard__art{ position:relative; }
.hl-pcard__badge--flag{
  position:absolute; top:0; left:0; z-index:2;
  background:var(--hl-red-500); color:#fff;
  box-shadow:0 6px 16px -8px rgba(207,41,39,.9);
}
.hl-section--dark .hl-pcard__badge--flag{ background:var(--hl-red-500); color:#fff; }

/* ── M10 · CHECKS ARE HAIRLINE ROWS ON EVERY BAND ──────────────────────────
   K2 draws the compact list as hairline rows, and then the dark-band form of
   `.hl-pfeat__row` — written for the `rows` treatment — re-filled them,
   because the two selectors carry the same specificity and the dark one is
   later in the file. So the same treatment was a filled chip on a dark chapter
   and a hairline row on a light one. It is a hairline row on both. */
.hl-section--dark .hl-pfeat--checks .hl-pfeat__row,
.hl-section--brand .hl-pfeat--checks .hl-pfeat__row{
  background:none; border:0; border-bottom:1px solid var(--hl-line-dark-2);
  border-radius:0; padding:12px 2px;
}

/* ── M11 · HEADING INK REACHES EVERY SECTION HEADING ───────────────────────
   J3 declares `--hl-hd-ink`, and exactly two classes read it:
   `.hl-shead__title` and `.hl-ihead__title`. Every other section composition
   names its own heading class and hard-codes a colour — `.hl-price__title` is
   `#fff`, and there are a dozen more like it — so "Heading colour" was an
   Admin control that did nothing on most of the site. A control test that set
   all three values on a `content · steps` chapter measured one colour, three
   times.

   Two things have to be true at once, and that is why this is four rules
   rather than one.

   It has to WIN. A composition's own title class is (0,1,0), and on a
   re-banded section J6.1's legibility remap is (0,3,0). So the pairs below are
   (0,2,1) and (0,3,1) respectively — `:is(h1,h2)` contributes one element,
   which is the cheapest way past both.

   It has to stay SAFE. J3 offers three inks and no custom value precisely
   because a heading is the one element that cannot be allowed to fail
   legibility, so each rule matches only the ink that suits the band it is on:
   ink and navy on a light ground, white on a dark one. An unsafe pairing
   simply does not match, and the automatic answer — which is always legible —
   stands. That is the same shape as J6.4: automatic, overridable, in that
   order, and only where the override is sound.

   Card headings are h3/h4 throughout the design system and are untouched;
   this is the SECTION heading control. */

/* Light ground, dark ink. The exclusion list is the set of compositions that
   paint a dark ground of their own: on those, `--light` without a re-band is a
   label rather than a fact (J6 leaves their artwork alone by design), so dark
   ink there would be dark-on-dark. Re-banded, they are genuinely light, which
   is what the second rule is for. */
:is(.hl-section--light, .hl-section--alt):is(.hl-hd--ink, .hl-hd--navy):not(.hl-final,
  .hl-floor,.hl-flow,.hl-fund,.hl-hero--highline,.hl-ihero,.hl-ind,.hl-ioffer,
  .hl-net-sec,.hl-price,.hl-rfund,.hl-shero,.hl-sys) :is(h1, h2){
  color:var(--hl-hd-ink, inherit);
}
.hl-section--reband:is(.hl-section--light, .hl-section--alt):is(.hl-hd--ink, .hl-hd--navy) :is(h1, h2){
  color:var(--hl-hd-ink, inherit);
}

/* Dark ground, white ink. */
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand).hl-hd--white :is(h1, h2){
  color:var(--hl-hd-ink, inherit);
}
.hl-section--reband:is(.hl-section--dark, .hl-section--navy, .hl-section--brand).hl-hd--white :is(h1, h2){
  color:var(--hl-hd-ink, inherit);
}

/* ── M12 · AN UNSAFE ACCENT CHOICE IS IGNORED, NOT OBEYED ──────────────────
   J6.1 and J6.4 now step aside whenever an explicit accent class is present,
   which is what makes those controls work at all. On its own that would hand
   an editor a way to pick white type for a paper band — the exact failure
   requirement 16 forbids, arriving through the door that was opened to fix a
   different one.

   So the pairings that cannot hold are neutralised here, on the band rather
   than at the call site: the automatic answer is restored and the selection is
   simply not applied. Nothing warns, because there is nothing to warn about —
   a heading cannot be allowed to fail legibility, which is why J3 offers no
   custom heading colour in the first place.

   The chapter numeral is deliberately NOT filtered. It is `aria-hidden`
   decoration drawn as a 1.4px outline at low contrast by design; a quiet one
   is a quiet one, and there is no reading to fail. */

/* Eyebrow: the two light inks cannot sit on a paper band, and the three dark
   ones cannot sit on navy — `--hl-navy-500` on the deep-navy band measures
   2.22:1, which a control test found before anyone had to look at it. */
:is(.hl-section--light, .hl-section--alt):is(.hl-eb--light, .hl-eb--white){
  --hl-eb-ink:var(--hl-brand-red);
  --hl-eb-bar:linear-gradient(180deg,var(--hl-red-400),var(--hl-red-600));
  --hl-eb-glow:0 0 12px rgba(207,41,39,.6);
}
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand):is(.hl-eb--red, .hl-eb--muted, .hl-eb--navy){
  --hl-eb-ink:var(--hl-navy-300);
  --hl-eb-bar:linear-gradient(180deg,var(--hl-navy-300),var(--hl-navy-500));
  --hl-eb-glow:0 0 12px rgba(144,150,228,.45);
}

/* Heading: white on paper, and either dark ink on navy. The re-banded forms
   carry a third class so they outrank J6.1's (0,4,0) remap list. */
:is(.hl-section--light, .hl-section--alt).hl-hd--white :is(h1, h2){ color:var(--hl-ink-900); }
.hl-section--reband:is(.hl-section--light, .hl-section--alt).hl-hd--white :is(h1, h2){ color:var(--hl-ink-900); }
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand):is(.hl-hd--ink, .hl-hd--navy) :is(h1, h2){ color:var(--hl-text-light); }
.hl-section--reband:is(.hl-section--dark, .hl-section--navy, .hl-section--brand):is(.hl-hd--ink, .hl-hd--navy) :is(h1, h2){ color:var(--hl-text-light); }

/* ── M13 · THE GENERIC HERO'S HEADLINE ─────────────────────────────────────
   `blocks/hero.php` now runs its heading through `approved_headline()` like
   every other hero variant, so the `*emphasis*` and `//line break` conventions
   this project's headline copy is written in finally reach it — the 404 page
   read "That Page Is *Not Here*." until this pass.
   `:where(body.hl-body) em{font-style:normal}` would have rendered the emphasis
   identically to the words around it, which is a marker that has been removed
   rather than honoured, so it takes the same accent the service hero gives it. */
.hl-heroblock__title em{ font-style:normal; color:var(--hl-navy-300); }
:is(.hl-section--light, .hl-section--alt) .hl-heroblock__title em{ color:var(--hl-brand-navy); }
.hl-heroblock__title .hl-line{ display:block; }

/* ── M14 · THE TEXT LINK ON THE TWO MID-NAVY BANDS ─────────────────────────
   J4.6 treats every dark band as one case and gives them all `--hl-red-400`.
   That is right on deep navy (#04050E–#0A0B1F) and wrong on the two bands that
   climb into mid navy:

     Highline navy   #1B1E45 → #2A2D7C     red-400 measures 3.24:1 at the top
     Brand gradient  #2A2D7C → #565AC2     worse again

   And the next step up the ramp makes it worse rather than better — red-300 on
   #565AC2 is 2.75:1 — because a light red and a mid navy converge instead of
   separating. There is no member of the red family that holds here.

   So on those two bands the text link is white. The underline the component
   grows on hover is still the state change, so nothing about the interaction
   moves; only the ink, to the one value that clears 5.7:1.

   Found by `public/_review-buttons.php`, which renders every variant on every
   band precisely because the site-wide sweep can only measure the combinations
   that happen to be in use — and no live page currently puts a text link on
   either of these two. */
:is(.hl-section--navy, .hl-section--brand) .hl-btn--link,
:is(.hl-section--navy, .hl-section--brand) .hl-btn--link:hover,
:is(.hl-section--navy, .hl-section--brand) .hl-btn--link:focus-visible,
:is(.hl-section--navy, .hl-section--brand) .hl-btn--link:active{ --hl-btn-ink:var(--hl-text-light); }

:is(.hl-section--navy, .hl-section--brand).hl-cta--v-link :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm),
:is(.hl-section--navy, .hl-section--brand).hl-cta--v-link :is(.hl-btn--primary,.hl-btn--accent,.hl-btn--dark):not(.hl-btn--sm):hover{
  --hl-btn-ink:var(--hl-text-light);
}

/* The same two bands, the same reason, for the other red-on-navy link. */
:is(.hl-section--navy, .hl-section--brand) .hl-btn--link-light{ --hl-btn-ink:var(--hl-text-light); color:var(--hl-text-light); }

/* ── M15 · THE TWO MID-NAVY BANDS CARRY LIGHTER QUIET INK ──────────────────
   `--hl-text-light-3` and `--hl-text-light-4` are tuned for the deep-navy
   family (#04050E–#12142E), where they clear AA comfortably. Highline navy
   climbs to `--hl-primary` (#2A2D7C) and the brand gradient to
   `--hl-secondary` (#565AC2), and a tint tuned for near-black does not survive
   either: the product page's financing disclaimer measured 3.74:1 the moment
   the automatic rhythm put that chapter on Highline navy.

   Same shape as L4 — the band re-points the tokens for its own interior, so
   every disclaimer, caption and unit inside it follows without one of them
   being named. Brand is a step further again because it is a genuinely light
   ground; a "quiet" ink there is quiet only by comparison.

   The eyebrow is the same problem in a hue rather than a tint: `--hl-navy-300`
   is 4.35:1 on #2A2D7C. It steps aside for an explicit `.hl-eb--*` class the
   way J6.4 does, so the Admin control still wins — and M12 still stops an
   unsafe choice. */
.hl-section--dark.hl-section--navy{
  --hl-text-light-3:rgba(255,255,255,.76);
  --hl-text-light-4:rgba(255,255,255,.66);
}
.hl-section--brand{
  --hl-text-light-3:rgba(255,255,255,.90);
  --hl-text-light-4:rgba(255,255,255,.84);
}

.hl-section--dark.hl-section--navy:not([class*="hl-eb--"]),
.hl-section--brand:not([class*="hl-eb--"]){
  --hl-eb-ink:#B9BDF0;
  --hl-eb-bar:linear-gradient(180deg,#B9BDF0,var(--hl-navy-400));
  --hl-eb-glow:0 0 12px rgba(185,189,240,.45);
}

/* ── M16 · THE OVERVIEW HAS A MEASURE ──────────────────────────────────────
   `.hl-pdp__copy--wide` was a class the template emitted and nothing styled,
   so the overview ran the full 1,280px container — around 150 characters a
   line, roughly twice what is comfortable to read, and the widest running text
   anywhere on the site. Visible the moment a device had a real description:
   five of the six had none, so nothing had ever filled that band.

   The two measures follow the ones the rest of the system already uses: the
   chapter lede is 62ch, so body prose sits a little wider and the "wide"
   modifier a little wider again — a modifier that now means something. */
/* Corrected in the final composition pass. `68ch`/`78ch` measured 94 and 108
   characters a line — see the note on --hl-measure-editorial in tokens.css for
   why a ch-based measure at body size renders ~39% wider than it reads. These
   two land at roughly 75 and 85 characters, which is the range the brief asks
   for and the range the rest of the system's ledes already sit in. */
.hl-pdp__copy{ max-width:54ch; }
.hl-pdp__copy--wide{ max-width:61ch; }


/* ===========================================================================
   N · VERTICAL RHYTHM CONTRACT
   ---------------------------------------------------------------------------
   Where one content group ends and the next begins.

   The section padding (`--hl-sec-pad`) governs the space around a chapter, and
   the typography margins govern the space between lines of prose. Nothing
   governed the space between GROUPS — a paragraph and the action row under it,
   an action row and the chips under that — so every action row on the site was
   `display:flex; gap:…` and nothing else, and its vertical position was
   whatever the element above it happened to leave behind. That produced 32px in
   nineteen places, 24px in six, 20px in three and 0px in seven, from the same
   intended relationship.

   So this is not a new scale. 32px is what the composition already used most
   often; the contract names it and applies it where the accident produced less.

   HOW THE FLOOR WORKS. In normal flow, adjacent siblings' vertical margins
   collapse to the larger of the two. A `margin-top:var(--hl-flow)` on the lower
   group therefore RAISES a 0 or 20px gap to 32px and LEAVES a deliberate 40px
   or 48px alone — which is what a floor should do, and why the closing CTA
   composition below keeps its wider setting without being listed as an
   exception. Flex and grid parents do not collapse margins, so a container that
   already spaces its children with `gap` owns the flow there and its children
   opt out; those are named at the end.
   =========================================================================== */

/* ── N1 · THE GROUP PRIMITIVES ─────────────────────────────────────────────
   An action row — a row of buttons or button-styled links that acts on the
   copy above it. This is the allowlist, in the same spirit as the section and
   accent class allowlists: a component joins the rhythm by being named here,
   not by matching a pattern.

   Chrome is deliberately absent. The header, announcement bar, sticky rail,
   promotional modal and mobile drawer lay their actions out horizontally
   against a fixed height, and a 32px block margin would push them out of it. */
:is(
  .hl-hero__cta, .hl-hero__actions, .hl-shero__cta, .hl-heroblock__actions,
  .hl-content__actions, .hl-cta__actions, .hl-about__actions,
  .hl-funding__actions, .hl-form__actions,
  .hl-price__cta, .hl-cd__cta, .hl-ioffer__cta, .hl-fund__cta,
  .hl-story__cta, .hl-pdpend__cta, .hl-ipanel__foot, .hl-hw__leadcta,
  .hl-final__cta
):not(:first-child){
  margin-top:var(--hl-flow);
}

/* ── N2 · SUBORDINATE GROUPS ───────────────────────────────────────────────
   Chips, tags and the fine print that qualifies the group above them are not
   peers of it — they are attached to it, and they read as a separate group at
   a smaller step than two peers need. `.hl-chips` already declared exactly
   this value; re-pointing it at the token leaves the rendering identical and
   removes the second place the number was written down. */
.hl-chips{ margin:var(--hl-flow-tight) 0; }

:is(.hl-final__chips, .hl-btile__chips, .hl-wtile__chips, .hl-pcard__tags):not(:first-child){
  margin-top:var(--hl-flow-tight);
}

/* A disclaimer that follows an action row is separated by a hairline, so the
   space above the rule is the group step and the space below it belongs to the
   rule. `.hl-price__disc` set 20px above its own border, which read as the
   fine print crowding the buttons rather than closing the block. */
.hl-price__cta + .hl-price__disc{ margin-top:var(--hl-flow); }

/* ── N3 · CONTAINERS THAT OWN THEIR OWN FLOW ───────────────────────────────
   `gap` does not collapse with a margin, it adds to it. In a column that
   already spaces its children, the contract margin would produce 52px from a
   20px gap and a 32px floor, so the container sets the step instead and its
   children stand down.

   `.hl-wtile` and `.hl-pcard` are cards: a tighter internal rhythm is correct
   there and the card's own gap is left as designed. */
.hl-hw__lead{ row-gap:var(--hl-flow); }
.hl-hw__lead > :is(.hl-hw__leadcta, .hl-chips){ margin-top:0; }

/* `.hl-wtile` is a flex column too, and a card wants a tighter internal rhythm
   than a chapter does: added on top of the card's own spacing, the chip margin
   put 44px between the chips and the text they belong to, inside a 26px-padded
   box. The card already spaces them the way it was drawn, so the chips stand
   down here rather than the card being re-spaced around them. */
.hl-wtile > :is(.hl-chips, .hl-wtile__chips){ margin-block:0; }

/* ── N4 · THE CLOSING CTA KEEPS ITS WIDER SETTING ──────────────────────────
   Recorded rather than enforced. `.hl-final__cta` sits 40px under its lede and
   `.hl-final__chips` 48px under the buttons, both from the preceding element's
   own margin. Margin collapsing means N1's 32px floor cannot reduce either, so
   the closing composition needs no exception — but the intent is written down
   here so a later change to the floor is understood to affect it. */


/* ===========================================================================
   O · THE SPACING PRESET, APPLIED
   ---------------------------------------------------------------------------
   Sixteen of the approved compositions set `padding-block:var(--hl-sec-pad)` on
   their own component class — `.hl-faq-sec`, `.hl-price`, `.hl-flow`, `.hl-cd`,
   `.hl-ioffer`, `.hl-fund`, `.hl-net-sec`, `.hl-acc`, `.hl-hw`, `.hl-hw2`,
   `.hl-sys`, `.hl-ind`, `.hl-calc`, `.hl-revs`, `.hl-floor`, `.hl-rhw`. This
   file loads after layout.css, so on a specificity tie those rules beat
   `.hl-section--compact` and `.hl-section--roomy`, and the Spacing select did
   nothing at all on any of them. It was a control that looked like it worked.

   The correction is the one section J6 already makes for the band: the preset
   wins where an administrator has CHANGED it, and nowhere else. `section_classes()`
   emits `--respace` only when the stored value differs from the one the block
   ships with, so an untouched page renders exactly the bytes it rendered
   before — this section adds rules rather than editing the sixteen it beats.

   `padding-block` is the only property touched. A composition's ground, glows,
   rails and internal layout are its own.
   =========================================================================== */

/* `none` is deliberately absent.

   On a plain block it already means zero, from layout.css, because nothing
   else declares padding there. On one of the sixteen it means "the composition
   sets its own" — which is what the preset is labelled, and what these
   sections have always done. Forcing zero here instead collapsed every FAQ
   chapter on the site the moment the marker started being emitted, because the
   seeds store `none` on exactly those sections: the value was chosen while the
   control was inert, and it meant "leave this alone" then too. */
.hl-section--respace.hl-section--compact  { padding-block:var(--hl-sec-pad-compact); }
.hl-section--respace.hl-section--normal   { padding-block:var(--hl-sec-pad-normal); }
.hl-section--respace.hl-section--roomy    { padding-block:var(--hl-sec-pad-roomy); }
.hl-section--respace.hl-section--spacious { padding-block:var(--hl-sec-pad-spacious); }

/* A hero puts its padding on the inner shell so the stage can bleed past it.
   Re-spacing the section would add to that rather than replace it, so the
   shell stands down and the preset owns the band — but only where a preset is
   actually being applied, which `none` is not. */
.hl-section--respace:not(.hl-section--none) :is(.hl-shero__shell, .hl-hero__shell){
  padding-block:0;
}

/* ── N4.1 · THE RE-SPACED HERO STILL HAS TO CLEAR THE HEADER ───────────────
   The header is transparent and sticky, and a dark opening hero deliberately
   sits UNDER it: `.hl-heroblock--under-header` (section E5) pulls the section
   up by the header's height and pays it back as padding, so the breadcrumb and
   the H1 start below the nav rather than behind it.

   That padding is a single class, (0,1,0). The preset rules immediately above
   are (0,2,0) and land later in the file, so on any hero whose Spacing has
   been changed from its default the preset REPLACED the offset instead of
   adding to it — and the section kept its negative margin. The result was a
   breadcrumb rendering 28px above the bottom of the header at 1440 and 20px at
   390: not clipped, not overlapped, simply behind it.

   Seven pages were affected, all of them `hero · centered` with a stored
   Spacing — the four legal documents, the 404 and the maintenance page (the
   two a lost visitor is most likely to see), and one draft landing page.

   The fix restates each preset WITH the header offset added, at (0,3,0) so it
   outranks the preset it is correcting. `none` is included because a hero
   carrying `none` still needs to clear the header — it just adds nothing else. */
.hl-section--respace.hl-heroblock--under-header.hl-section--none{
  padding-top:var(--hl-header-height, 4.5rem);
}
.hl-section--respace.hl-heroblock--under-header.hl-section--compact{
  padding-top:calc(var(--hl-header-height, 4.5rem) + var(--hl-sec-pad-compact));
}
.hl-section--respace.hl-heroblock--under-header.hl-section--normal{
  padding-top:calc(var(--hl-header-height, 4.5rem) + var(--hl-sec-pad-normal));
}
.hl-section--respace.hl-heroblock--under-header.hl-section--roomy{
  padding-top:calc(var(--hl-header-height, 4.5rem) + var(--hl-sec-pad-roomy));
}
.hl-section--respace.hl-heroblock--under-header.hl-section--spacious{
  padding-top:calc(var(--hl-header-height, 4.5rem) + var(--hl-sec-pad-spacious));
}


/* ── N5 · RICH TEXT HAS A FLOOR ────────────────────────────────────────────
   The editor writes prose; it should never have to write SPACE.

   Paragraphs, lists, headings, quotes and tables all carry a margin, so an
   editor typing normally gets a normal rhythm. What has no margin at all is
   anything the reset flattened — an image or a figure, which `body.hl-body`
   sets to `display:block; margin:0` — and anything the browser gives no
   default to. Put an image between two paragraphs and it touches both, and the
   only tool an editor has to fix that from inside a rich-text field is a run of
   empty lines. That is the `<br><br>` hack, and it is a hack because the system
   left a hole, not because the editor was careless.

   This closes it the same way section N1 does: a `margin-top` on the following
   sibling collapses with whatever the previous one already reserved, so it
   RAISES a zero gap to one line and cannot reduce a deliberate 1.5em. The
   heading rule in base.css is `.hl-rich h2` at (0,1,1) and still wins its
   larger step; `:first-child` never matches `* + *`.

   No stored content currently uses a doubled `<br>`; this is here so none ever
   needs to. */
.hl-rich > * + *{ margin-top:1em; }


/* ===========================================================================
   P · THE ENLARGED PRODUCT GALLERY
   ---------------------------------------------------------------------------
   A `<dialog>`, so the scrim is a real `::backdrop` and the focus trap, the
   inert background and Escape are the platform's rather than a second
   implementation of them.

   The panel is sized from the VIEWPORT, not from the image. A product shot is
   whatever resolution it was uploaded at; letting it drive the layout means a
   large one overflows and a small one floats in the middle of a black field.
   Capping the picture and centring it inside a fixed frame makes every product
   open the same way.
   =========================================================================== */

.hl-lightbox{
  width:100vw; max-width:100vw; height:100dvh; max-height:100dvh;
  margin:0; padding:0; border:0; background:transparent; overflow:hidden;
}
/* The scrim has to hide a DARK page, which is why .88 was not enough.
   `rgba(4,5,14,.88)` is near-black, and a product page's hero is near-black
   too, so the scrim sat at almost the same luminance as what it was covering:
   the nav, the H1, the breadcrumbs and the red primary button all stayed
   legible behind it, competing with the photograph (audit PD-07, confirmed at
   1536 after the correction pass — the rule was never changed). Alpha alone has
   diminishing returns against a dark ground; what actually destroys the
   legibility of text is the blur, so that carries most of the increase. */
.hl-lightbox::backdrop{ background:rgba(4,5,14,.94); backdrop-filter:blur(14px); }

/* The document must not scroll behind a full-screen overlay: a visitor who
   closes it should be where they left. */
html.hl-lightbox-open{ overflow:hidden; }

.hl-lightbox__panel{
  position:relative; display:grid; grid-template-rows:auto 1fr;
  width:100%; height:100%; padding:clamp(12px,2vw,28px);
  gap:var(--hl-s-4);
}

.hl-lightbox__bar{
  display:flex; align-items:center; justify-content:space-between; gap:var(--hl-s-4);
  min-height:44px;
}
.hl-lightbox__title{
  margin:0; color:#fff; font-size:var(--hl-fs-sm); font-weight:700; letter-spacing:-.01em;
}
.hl-lightbox__count{
  margin-left:var(--hl-s-3); font-weight:500; color:var(--hl-text-light-3);
  font-variant-numeric:tabular-nums;
}

.hl-lightbox__close{
  display:grid; place-items:center; width:44px; height:44px; flex:none;
  border-radius:50%; color:#fff; font-size:1.6rem; line-height:1;
  background:rgba(255,255,255,.08); border:1px solid rgba(255,255,255,.18);
  transition:background var(--hl-t-fast), border-color var(--hl-t-fast);
}
.hl-lightbox__close:hover{ background:rgba(255,255,255,.16); border-color:rgba(255,255,255,.34); }

.hl-lightbox__viewport{
  position:relative; display:grid; place-items:center; min-height:0; min-width:0;
  /* The swipe target. Vertical panning stays with the page so a tall picture
     can still be scrolled; horizontal is ours. */
  touch-action:pan-y;
}

/* `minmax(0,1fr)`, not `1fr`.

   A grid track sized `1fr` still has `min-height:auto`, so a 1800x1200
   photograph pushed the track past the panel and the picture ran off the
   bottom and the right of the screen — `max-height:100%` resolved against a
   row that had already grown to fit it. The explicit zero minimum is what
   makes the frame the constraint and the image the thing that fits inside it.

   The viewport-unit cap is deliberate belt-and-braces: it is the one bound
   that does not depend on any ancestor resolving its own height correctly, and
   an enlarged view that overflows is worse than one that is slightly small. */
/* An author `display` beats the UA stylesheet's `[hidden]{display:none}`, so
   giving the slide a `display` made every image in the set render at once,
   stacked down the page. The attribute has to be honoured explicitly. */
.hl-lightbox__slide[hidden]{ display:none; }

/* A centred COLUMN, not two grid rows. With the image in a `1fr` row and the
   caption in an `auto` one, a picture shorter than its row floated in the
   middle while its caption stayed pinned to the bottom of the screen, reading
   as a caption for nothing. Centring the pair as a group keeps them together
   at any aspect ratio. */
.hl-lightbox__slide{
  margin:0; width:100%; height:100%; min-height:0; min-width:0;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:var(--hl-s-4);
}
/* ── THE LIGHT STAGE ───────────────────────────────────────────────────────
   Dark modal → light canvas → transparent image.

   The product library is mostly CUT-OUTS: transparent PNG and WebP whose
   subject is white hardware and whose annotation labels and callout lines are
   black. Painted straight onto the dialog's near-black scrim, the hardware read
   and the labels disappeared, which is the half of a diagram that carries the
   information. The stage puts an approved light neutral between the two so dark
   ink has something to be dark against.

   `--hl-lb-pad` is declared on the SLIDE and consumed twice: once as the
   stage's padding, and once in the image's height budget below. Declaring it in
   one place is what stops those two drifting apart — the failure that would
   show as a picture overflowing the bottom of the screen by exactly the padding
   it was given.

   The stage shrink-wraps its image rather than filling the viewport. On a
   cut-out that makes the light ground read as the diagram's own sheet; on an
   opaque photograph the picture covers everything but the margin, so it reads
   as a mount and not as a white box with a small picture in it. */
.hl-lightbox__slide{ --hl-lb-pad:clamp(14px,2.2vw,30px); }

.hl-lightbox__stage{
  display:flex; align-items:center; justify-content:center;
  box-sizing:border-box; min-height:0; min-width:0; max-width:100%;
  padding:var(--hl-lb-pad);
  background:var(--hl-paper);
  border-radius:var(--hl-r-xl);
  /* Seats the sheet on the scrim instead of letting it float as a flat shape. */
  box-shadow:0 30px 80px -28px rgba(0,0,0,.7);
}

/* The viewport-unit cap stays on the IMAGE, not on the stage.

   A percentage `max-height` resolves against a parent's definite HEIGHT, and
   the stage has a max-height at most — so `max-height:100%` here would compute
   to `none` and a tall diagram would run off the bottom of the screen. The
   explicit arithmetic is the one bound that does not depend on an ancestor
   resolving its own height, and it subtracts the stage's own padding so the
   sheet, not just the picture, is what fits. 150px is the bar, the panel's
   padding and the caption. */
.hl-lightbox__stage img{
  display:block; min-height:0;
  max-width:100%;
  max-height:min(100%, calc(100dvh - 150px - (var(--hl-lb-pad) * 2)));
  width:auto; height:auto;
  object-fit:contain; border-radius:var(--hl-r-md);
}
.hl-lightbox__caption{
  margin:0; text-align:center; color:var(--hl-text-light-3);
  font-size:var(--hl-fs-xs); line-height:1.6; max-width:64ch;
}

/* Moving between images is a small settle, not a slide: the picture is what
   changed, and animating its position makes the set feel like a carousel the
   visitor has to wait for. */
.hl-lightbox__slide--in{ animation:hl-lightbox-in 220ms var(--hl-e-out) both; }
@keyframes hl-lightbox-in{ from{ opacity:0; transform:scale(.985) } to{ opacity:1; transform:none } }

.hl-lightbox__nav{
  position:absolute; top:50%; transform:translateY(-50%);
  display:grid; place-items:center; width:48px; height:48px;
  border-radius:50%; color:#fff; font-size:1.25rem;
  background:rgba(255,255,255,.08); border:1px solid rgba(255,255,255,.18);
  transition:background var(--hl-t-fast), border-color var(--hl-t-fast);
}
.hl-lightbox__nav:hover{ background:rgba(255,255,255,.18); border-color:rgba(255,255,255,.38); }
.hl-lightbox__nav--prev{ left:clamp(8px,1.6vw,24px); }
.hl-lightbox__nav--next{ right:clamp(8px,1.6vw,24px); }

/* ── P2 · THE ZOOM CONTROL ON THE STAGE ────────────────────────────────────
   Always visible, never hover-only. A control that appears on hover does not
   exist on a touch device, which is most of the traffic a product page gets. */
.hl-rstage{ position:relative; }
.hl-rstage__zoom{
  position:absolute; right:14px; bottom:14px; z-index:2;
  display:grid; place-items:center; width:40px; height:40px;
  border-radius:50%; color:#fff;
  background:rgba(10,12,34,.62); border:1px solid rgba(255,255,255,.22);
  backdrop-filter:blur(6px);
  transition:background var(--hl-t-fast), border-color var(--hl-t-fast), transform var(--hl-t-fast);
}
.hl-rstage__zoom svg{ width:19px; height:19px; }
.hl-rstage__zoom:hover{ background:rgba(10,12,34,.86); border-color:rgba(255,255,255,.44); transform:scale(1.06); }

[data-hl-gallery-stage][role="button"]{ cursor:zoom-in; }

@media (max-width:640px){
  .hl-lightbox__nav{ width:42px; height:42px; }
  .hl-lightbox__bar{ min-height:40px; }
  /* A phone has no room to spend on a mount: the sheet keeps enough padding to
     stay a sheet, and gives the rest back to the diagram. */
  .hl-lightbox__slide{ --hl-lb-pad:12px; }
  .hl-lightbox__stage{ border-radius:var(--hl-r-lg); }
}

@media (prefers-reduced-motion:reduce){
  .hl-lightbox__slide--in{ animation:none; }
  .hl-lightbox__close,
  .hl-lightbox__nav,
  .hl-rstage__zoom{ transition:none; }
  .hl-rstage__zoom:hover{ transform:none; }
}


/* ── P3 · PRODUCT DOCUMENTS ────────────────────────────────────────────────
   A list of downloads, drawn as rows rather than cards.

   Cards would compete with the specification chapter above and the related
   equipment below, both of which are already card grids; three card grids in a
   row reads as a page made of boxes. Rows also let the file's weight sit on the
   right of its own line, which is where a reader looks for it.

   The WHOLE ROW is the link. A card with a separate download link inside it
   gives a keyboard visitor two stops for one destination. */
.hl-pdocs{
  display:grid; gap:var(--hl-s-3); max-width:920px;
  margin:0; padding:0; list-style:none;
}

.hl-pdocs__link{
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto auto;
  align-items:center; gap:var(--hl-s-4);
  padding:var(--hl-s-5) var(--hl-s-6);
  border:1px solid var(--hl-line); border-radius:var(--hl-r-lg);
  background:#fff; color:var(--hl-text-body);
  transition:border-color var(--hl-t-fast), box-shadow var(--hl-t-fast), transform var(--hl-t-fast);
}
.hl-pdocs__link:hover{
  border-color:var(--hl-line-2); box-shadow:var(--hl-sh-sm); transform:translateY(-1px);
}

.hl-pdocs__icon{ display:grid; place-items:center; width:38px; height:38px; flex:none;
  border-radius:var(--hl-r-md); color:var(--hl-brand-red);
  background:rgba(207,41,39,.08); border:1px solid rgba(207,41,39,.16); }
.hl-pdocs__icon svg{ width:19px; height:19px; }

.hl-pdocs__body{ display:grid; gap:4px; min-width:0; }
.hl-pdocs__label{ font-weight:700; letter-spacing:-.01em; }
.hl-pdocs__desc{ font-size:var(--hl-fs-xs); line-height:1.6; color:var(--hl-text-muted); }

.hl-pdocs__meta{
  font-size:var(--hl-fs-micro); letter-spacing:.05em; text-transform:uppercase;
  color:var(--hl-text-muted); font-variant-numeric:tabular-nums; white-space:nowrap;
}

.hl-pdocs__arrow{ color:var(--hl-brand-red); transition:transform var(--hl-t-fast); }
.hl-pdocs__link:hover .hl-pdocs__arrow{ transform:translateX(3px); }

/* On a dark chapter the row is a glass panel rather than white paper, the same
   way every other light-on-dark component in the system behaves. */
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand) .hl-pdocs__link{
  background:rgba(255,255,255,.04); border-color:rgba(255,255,255,.13); color:var(--hl-text-light-2);
}
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand) .hl-pdocs__link:hover{
  background:rgba(255,255,255,.07); border-color:rgba(255,255,255,.26);
}
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand) .hl-pdocs__label{ color:#fff; }
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand) .hl-pdocs__desc,
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand) .hl-pdocs__meta{ color:var(--hl-text-light-3); }
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand) .hl-pdocs__icon{
  color:var(--hl-red-400); background:rgba(229,84,78,.14); border-color:rgba(229,84,78,.26);
}

@media (max-width:640px){
  /* The weight moves under the label rather than being squeezed against it. */
  .hl-pdocs__link{ grid-template-columns:auto minmax(0,1fr) auto; padding:var(--hl-s-4) var(--hl-s-5); }
  .hl-pdocs__meta{ grid-column:2; grid-row:2; }
  .hl-pdocs__arrow{ grid-row:1 / span 2; }
}

@media (prefers-reduced-motion:reduce){
  .hl-pdocs__link,
  .hl-pdocs__arrow{ transition:none; }
  .hl-pdocs__link:hover{ transform:none; }
  .hl-pdocs__link:hover .hl-pdocs__arrow{ transform:none; }
}


/* ===========================================================================
   Q · EMBEDDED THIRD-PARTY PAGES
   ---------------------------------------------------------------------------
   A frame this site cannot see inside, given a shape and a waiting state.

   The SHAPE IS DECLARED, not measured. A cross-origin frame will not tell this
   page how tall its content is, and nothing may ask — so the height comes from
   an aspect ratio the administrator chooses, and the frame scrolls inside it.
   The alternative, a frame that resizes itself from a postMessage, is a
   third-party origin being trusted to set this page's layout.
   =========================================================================== */

.hl-embed__shell{ display:grid; gap:var(--hl-flow); }

.hl-embed__head{ max-width:64ch; }
.hl-embed__title{
  font-size:var(--hl-fs-h2); font-weight:800; letter-spacing:-.03em; line-height:1.08;
  margin:var(--hl-s-4) 0 0; color:var(--hl-heading-ink, inherit);
}
.hl-embed__lede{
  margin:var(--hl-s-4) 0 0; font-size:var(--hl-fs-lede); line-height:1.68;
  color:var(--hl-text-light-2);
}
.hl-section--light .hl-embed__lede,
.hl-section--alt .hl-embed__lede{ color:var(--hl-text-muted); }

/* ── Q1 · THE FRAME ────────────────────────────────────────────────────────
   `position:relative` so the waiting state and the escape hatch can sit over
   it; `overflow:hidden` so the provider's own scrollbar stays inside the
   rounded corner rather than cutting across it. */
.hl-embed__frame{
  position:relative; overflow:hidden;
  border-radius:var(--hl-r-xl);
  border:1px solid var(--hl-line);
  background:var(--hl-paper);
  /* A third-party document is not part of this page's colour scheme; giving it
     a white ground stops a transparent provider page inheriting a dark band
     and rendering its own dark text on it. */
}
.hl-embed__frame iframe{
  display:block; width:100%; height:100%; border:0; background:#fff;
}

:is(.hl-section--dark, .hl-section--navy, .hl-section--brand) .hl-embed__frame{
  border-color:rgba(255,255,255,.14);
}

/* The shapes. `aspect-ratio` rather than a padding hack: the frame is a real
   box with a real height, so the waiting state can centre inside it. */
.hl-embed--tall .hl-embed__frame{ aspect-ratio:3 / 4; max-height:min(1100px, 88dvh); }
.hl-embed--video .hl-embed__frame{ aspect-ratio:16 / 9; }
.hl-embed--square .hl-embed__frame{ aspect-ratio:1 / 1; }
.hl-embed--viewport .hl-embed__frame{ aspect-ratio:auto; height:min(1100px, 82dvh); }

@media (min-width:769px){
  .hl-embed--tall .hl-embed__frame{ aspect-ratio:4 / 3; }
}

/* ── Q2 · SHELL WIDTHS ─────────────────────────────────────────────────────
   How much of the page the frame is allowed to take. */
.hl-embed--panel .hl-embed__frame{ max-width:940px; }
.hl-embed--wide .hl-embed__frame{ max-width:none; }
.hl-embed--full .hl-embed__shell{ max-width:none; padding-inline:0; }
.hl-embed--full .hl-embed__frame{ border-radius:0; border-inline:0; }
.hl-embed--full .hl-embed__head{ padding-inline:var(--hl-gutter); margin-inline:auto; }

/* ── Q3 · WAITING ──────────────────────────────────────────────────────────
   Shown while the frame is on its way, hidden the moment it arrives or its
   deadline expires. It never outlives either. */
.hl-embed__wait{
  position:absolute; inset:0; z-index:2;
  display:grid; place-content:center; justify-items:center; gap:var(--hl-s-4);
  background:var(--hl-paper); color:var(--hl-text-muted);
  font-size:var(--hl-fs-sm);
}
.hl-embed__wait[hidden]{ display:none; }

.hl-embed__spinner{
  width:26px; height:26px; border-radius:50%;
  border:2px solid var(--hl-line-2); border-top-color:var(--hl-brand-red);
  animation:hl-embed-spin 820ms linear infinite;
}
@keyframes hl-embed-spin{ to{ transform:rotate(360deg) } }

/* ── Q4 · THE ESCAPE HATCH ─────────────────────────────────────────────────
   A provider that refuses to be framed produces a frame that never arrives,
   and a visitor cannot tell that from a slow connection. This is what they get
   instead — and it is in the markup from the start, so it works with no
   JavaScript at all. */
.hl-embed__blocked{
  position:absolute; inset:0; z-index:3;
  display:grid; place-content:center; justify-items:center; gap:var(--hl-s-5);
  padding:var(--hl-s-8); text-align:center;
  background:var(--hl-paper);
}
.hl-embed__blocked[hidden]{ display:none; }
.hl-embed__blockedtext{
  margin:0; max-width:44ch; color:var(--hl-text-body);
  font-size:var(--hl-fs-sm); line-height:1.65;
}

/* The permanent way out. Quiet enough not to compete with the embed, present
   whatever happens — because the one failure mode this page cannot detect is a
   frame that loaded a provider's refusal page. */
.hl-embed__escape{
  margin:var(--hl-s-4) 0 0; font-size:var(--hl-fs-xs);
  color:var(--hl-text-muted);
}
.hl-embed__escape a{ color:var(--hl-brand-red); text-decoration:underline; text-underline-offset:3px; }
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand) .hl-embed__escape{ color:var(--hl-text-light-3); }
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand) .hl-embed__escape a{ color:var(--hl-red-400); }

/* ── Q5 · REFUSED BEFORE IT WAS EVER FRAMED ────────────────────────────────
   An address that is not on an approved provider's origin. No link is offered:
   the address the system just refused is exactly the one it should not be
   sending anybody to. */
.hl-embed__refused{
  display:grid; gap:var(--hl-s-3); justify-items:start;
  padding:var(--hl-s-8);
  border:1px dashed var(--hl-line-2); border-radius:var(--hl-r-xl);
  background:var(--hl-paper);
}
.hl-embed__refusedtitle{ margin:0; font-weight:700; color:var(--hl-text-body); }
.hl-embed__refusedtext{ margin:0; font-size:var(--hl-fs-sm); color:var(--hl-text-muted); max-width:56ch; }

@media (prefers-reduced-motion:reduce){
  /* The spinner stops, but the waiting state stays legible — a visitor who
     asked for less motion still needs to know something is happening. */
  .hl-embed__spinner{ animation:none; border-top-color:var(--hl-brand-red); opacity:.85; }
}

/* ===========================================================================
   FUNDING PRE-QUALIFICATION
   ===========================================================================
   The pre-qualification block reuses the whole `hl-embed` presentation — the
   frame, the waiting state, the escape hatch and the refused panel are the
   same components and are not duplicated here. What is different is the
   HEIGHT, and only the height.

   WHY A SET HEIGHT RATHER THAN AN ASPECT RATIO. The `embed` block's shapes are
   ratios because a signing ceremony and a video have a shape. An application
   form does not: it is a column of questions whose length is decided by the
   provider, and a 4:3 box on a wide screen makes a tall form scroll inside a
   short window for no reason. So the owner sets a height in Settings and the
   frame is that tall.

   WHY THE PHONE IGNORES IT. A 900px frame on a 700px-tall phone is a small
   window with a scrollbar inside a page that also scrolls — two scroll
   contexts stacked, which is the worst way to fill in a form. Below the
   breakpoint the frame takes the screen instead, so the form has as much room
   as the device has.
   ------------------------------------------------------------------------ */

.hl-embed--set .hl-embed__frame{
  aspect-ratio:auto;
  height:var(--hl-embed-h, 900px);
  max-height:none;
}

@media (max-width:768px){
  /* `dvh`, not `vh`: on a phone the browser chrome moves, and `vh` measures a
     viewport the visitor never actually has. */
  .hl-embed--set .hl-embed__frame{ height:min(var(--hl-embed-h, 900px), 78dvh); }
}

/* ── THE HAND-OFF ──────────────────────────────────────────────────────────
   Shown when the form is configured but switched off in Settings. Not an
   error state — the route onward is still open, it simply opens at the
   provider rather than inside the page. */
.hl-prequal__handoff{
  display:grid; gap:var(--hl-s-4); justify-items:start;
  /* The same 940px the framed form gets in a panel shell. Without it the
     hand-off spans the full grid while its copy is capped at 60ch, and the
     panel reads as a wide box with its content pushed into one corner. */
  max-width:940px;
  padding:var(--hl-s-8);
  border:1px solid var(--hl-line); border-radius:var(--hl-r-xl);
  background:var(--hl-paper);
}
.hl-prequal__lead{
  margin:0; font-size:var(--hl-fs-lede); line-height:1.62; color:var(--hl-text-body); max-width:60ch;
}
.hl-prequal__note{
  margin:0; font-size:var(--hl-fs-sm); color:var(--hl-text-muted); max-width:56ch;
}
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand) .hl-prequal__handoff{
  border-color:rgba(255,255,255,.14); background:rgba(255,255,255,.04);
}
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand) .hl-prequal__note{
  color:var(--hl-text-light-3);
}
:is(.hl-section--dark, .hl-section--navy, .hl-section--brand) .hl-prequal__lead{
  color:var(--hl-text-light-2);
}


/* ===========================================================================
   R · THE EDITORIAL CHAPTER
   ===========================================================================
   A chapter whose ONLY content is prose.

   ── THE DEFECT THIS EXISTS TO REMOVE ──────────────────────────────────────

   Every other chapter on this site is a head plus something wide underneath
   it — a card grid, a specification table, a switchboard, a track. The head
   sits at its own measure and the content below runs to the shell edge, and
   the difference between the two reads as hierarchy, because the wide thing
   under it anchors the right side of the page.

   A text-only chapter has no wide thing. It inherits the same 1,280px shell
   and puts a 764px paragraph in the left of it, and the 428px that are left
   over do not read as margin — they read as the column that failed to load.
   Measured on the product Overview at 1920px: heading ending at 1,384px, body
   at 1,128px, shell at 1,556px. Three different right edges and nothing to
   explain any of them.

   ── WHAT REPLACES IT ──────────────────────────────────────────────────────

   The section keeps its full-width background. Inside it, the whole content
   group — numeral, eyebrow, heading and body together — moves into ONE
   container at the editorial measure, centred in the page.

   Centred CONTAINER, left-aligned TEXT. The type does not become centred and
   the composition does not become a template hero; it becomes a column, the
   way the legal pages already are, and the space either side of it is
   symmetrical and therefore obviously deliberate.

   ── WHY IT IS OPT-IN RATHER THAN AUTOMATIC ────────────────────────────────

   CSS cannot ask "does this chapter have a second column of real content".
   The template can, and does — a chapter adds `hl-section--editorial` only
   where its composition is prose and nothing else. Applying it by guesswork
   would collapse a chapter the moment its optional media happened to be
   absent, which is the same class of bug one layer down.
   ------------------------------------------------------------------------ */

.hl-section--editorial > .hl-shell{
  max-width:calc(var(--hl-measure-editorial) + 2 * var(--hl-gutter));
}

/* Inside the editorial container the group is the container. The head's own
   1,020px cap and the body's own measure would both re-introduce a second
   edge inside a column that is already at the measure. */
.hl-section--editorial .hl-ihead,
.hl-section--editorial .hl-ihead__lede,
.hl-section--editorial .hl-pdp__copy,
.hl-section--editorial .hl-pdp__copy--wide,
.hl-section--editorial .hl-rich{
  max-width:none;
}

/* The heading and the body belong to one composition. `--hl-s-14` is the
   distance a head keeps from a card grid, and it is too far from the sentence
   that continues its thought — 63px of nothing between a heading and the
   paragraph that finishes it. */
.hl-section--editorial .hl-ihead{ margin-bottom:var(--hl-s-8); }

/* A chapter this short does not need a chapter-sized band around it. The
   padding stays generous enough to separate it from its neighbours and stops
   being a room the content is lost in. */
.hl-section--editorial{ --hl-sec-pad:clamp(56px, 5vw, 88px); }

/* Below the breakpoint the editorial container is wider than the viewport, so
   it stops doing anything and the ordinary gutter governs.

   THE INNER MEASURE HAS TO COME BACK WHEN IT DOES. The rule above sets the
   head and copy to `max-width:none` because the CONTAINER is providing the
   measure; once the container is full-width, nothing is. The first version of
   this block left them unconstrained and the product overview ran 101
   characters a line at 768px — the desktop defect moved to tablet rather than
   fixed. */
@media (max-width:768px){
  .hl-section--editorial > .hl-shell{ max-width:none; }
  .hl-section--editorial .hl-pdp__copy,
  .hl-section--editorial .hl-pdp__copy--wide,
  .hl-section--editorial .hl-rich > p,
  .hl-section--editorial .hl-ihead__lede{ max-width:var(--hl-measure-note); }
}


/* ===========================================================================
   S · FINE PRINT HAS A MEASURE
   ===========================================================================
   Notes, disclaimers and diagram captions had no `max-width` at all, so each
   one ran the full width of whatever contained it. Measured at 1920px:

     .hl-rhw__note        1,192px at 12.8px  =  194 characters a line
     .hl-track__note      1,144px at 14px    =  175
     .hl-ioffer__disc       743px at 11.12px =  143
     .hl-pdpfin__note       685px at 14px    =  104

   Fine print is the hardest text on a page to read — it is the smallest, and
   it is where the underwriting and no-offer-of-credit statements live. Running
   it to 194 characters is the one place a long line does real harm.

   ── WHY ONE RULE AND WHY IN `em` ──────────────────────────────────────────

   This family is set in three sizes (11.12px, 12.8px, 14px). A measure in
   px or rem gives each a different line length; `ch` is wrong for all three
   by the same 39% (see tokens.css). `em` is relative to the element's own
   size, so one declaration holds ~86 characters at every one of them.

   `max-width` only ever constrains. Every member of this list that already
   sits in a narrower container — a product card foot, a drawer, a lightbox
   caption — is unaffected, which is why the list can be broad without being
   risky.

   ── WHAT IS DELIBERATELY NOT IN THE LIST ──────────────────────────────────

   The `__foot` classes that are ROWS rather than prose — `.hl-pcard__foot`,
   `.hl-check__foot`, `.hl-rev__foot`, `.hl-paid__foot`, `.hl-ipanel__foot`,
   `.hl-rstage__foot`, `.hl-floor__foot`, `.hl-drawer__foot`. Those carry
   buttons and links, and a text measure on a button row squeezes the row.
   `.hl-accv__foot` IS in the list: it is a diagram caption, and it was
   measured at 96 characters.
   ------------------------------------------------------------------------ */

.hl-accv__foot,
.hl-announce__aside,
.hl-calcbox__disc,
.hl-catfoot__note,
.hl-cpanel__note,
.hl-ecard__note,
/* `.hl-footer__disc p` is deliberately NOT in this list any more. The footer
   legal row is two proportional grid tracks sized to the copy they carry, and
   the TRACK is the measure there — an 86-character cap inside a 720px track put
   the dead space back in the middle of the row, which is the whole defect §W
   exists to fix. See §W. */
.hl-form__note,
.hl-formsec__aside,
.hl-fund__disclaimer,
.hl-fund__note,
.hl-hw2__note,
.hl-ind__aside,
.hl-ioffer__disc,
.hl-lightbox__caption,
.hl-partners__note,
.hl-pcard__note,
.hl-pdpfin__disc,
.hl-pdpfin__note,
.hl-prequal__note,
.hl-price__disc,
.hl-rfund__note,
.hl-rhw__note,
.hl-shead__aside,
.hl-stack__caption,
.hl-tp__note,
.hl-track__note,
.hl-track__note > p,
.hl-turn__note,

/* ── AND THE SAME MEASURE FOR RUNNING PROSE IN PANELS ──────────────────────
   The sweep that found the fine print found these too, and they are the same
   defect one type-size up: body and lede copy inside a panel, with no measure,
   running the panel's full width. Measured at 1024-1920px:

     .hl-faq__copy   151 characters      .hl-hw2__lede     144
     .hl-rwhy__copy  148                 .hl-cd__lede      125
     p in .hl-btile  150                 p in .hl-wfeat    138

   The token is in `em`, so the one value that holds ~86 characters of 11px
   fine print also holds ~86 characters of 16px body copy. And `max-width`
   only constrains — inside the narrow tiles several of these live in, it
   changes nothing at all, which is why the list can include them safely. */
.hl-faq__copy,
.hl-rwhy__copy,
.hl-hw2__lede,
.hl-cd__lede,
.hl-net-sec__disc,
.hl-rstage__foot,
.hl-btile > p,
.hl-wfeat > p,
.hl-wtile > p,
.hl-wtile__half > p,
.hl-hstage__meta > p,
.hl-fpanel__body > p,

/* The "Label | text" fact rows render as an unclassed definition list, so
   there is nothing more specific to hold on to. At desktop each `dd` already
   sits in a narrow column — measured at 24-38 characters — so this constrains
   nothing there. It applies at 768px, where the two-column list collapses and
   the value ran the full tablet width at 116-124 characters. */
main dd{
  max-width:var(--hl-measure-note);
}
