/* ============================================================
   SYSTEM SECTIONS — the Loop, the C.A.R.E. map, the complaints map
   and the operating-system comparison.

   Moved from the homepage to /employee-leadership-system/ on
   2026-10-16 (homepage v3), verbatim: the notes below still describe
   them as homepage sections. The shared header, reveal, eyebrow and
   text-link rules are COPIED here (the homepage keeps its own inline
   copy), so the two pages can diverge without touching each other.
   ============================================================ */

/* ============================================================
   "THE LOOP" SECTION (hero-v2 only)

   A ring that draws a quarter at a time as four statements scroll
   past it, sitting on a full-width cream band.

   Palette: gold var(--color-gold) #B97A2B, charcoal
   var(--color-charcoal) #1F1F1F, band var(--color-section-alt)
   #f7f7f5, #DDD5C8 (the unlit ring and resting dots), #4A443F
   (body) and #78716c (site stone-500) for mono labels. No new
   button styles.

   RING GEOMETRY — viewBox 0 0 440 440, r=132 about (220,220), so
   the circumference is 2*pi*132 = 829.38 and the dash array is
   829.4. The drawing arc carries transform="rotate(-90 220 220)"
   so its dash starts at 12 o'clock rather than 3. The four dots sit
   on the ring at 220+/-132 in each axis: (220,88) (352,220)
   (220,352) (88,220). Progress is stroke-dashoffset = 829.4 * (1 -
   quarters/4), set inline by the observer.

   NO-JS / PRE-JS DEFAULT IS "FULLY DRAWN". Every rule below paints
   the finished state — arc at offset 0, all dots gold, all terms
   visible, all steps at full opacity. The scroll behaviour is
   opt-in: the script adds .is-scroll to the container, and only
   then does anything dim. If the script never runs the section is
   complete and readable, which is also exactly what mobile wants. */
.hv2-loop { background: var(--color-section-alt); }

/* header — site heading treatment + gold rule */
.hv2-loop h2 { font-size: clamp(1.9rem, 3.4vw, 2.6rem); font-weight: 600; line-height: 1.2; max-width: 20ch; }
.hv2-loop-rule { width: 3.5rem; height: 3px; background: var(--color-gold); margin: 1.25rem 0; }
.hv2-loop-lede { max-width: 60ch; color: #4A443F; font-size: 1.0625rem; line-height: 1.6; }

/* ---- two columns: sticky ring | scrolling steps ---- */
.hv2-loop-scroll {
  margin-top: 3.25rem;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(36px, 5vw, 72px);
}
/* align-self:start is what makes the sticky work — a grid item is
   stretched to the row's full height by default, and an element as tall
   as its container has no room to stick. */
.hv2-loop-circle {
  position: sticky;
  top: calc(50vh - 240px);
  align-self: start;
  justify-self: center;
  width: 100%;
  max-width: 480px;
}
.hv2-ring { display: block; width: 100%; height: auto; overflow: visible; }

/* Resting/finished state. `r` and `fill` are animatable SVG geometry
   presentation attributes; setting them in CSS lets the dots grow
   without JS touching the DOM. */
.hv2-dot { r: 9.5; fill: var(--color-gold); }
.hv2-term {
  font-family: var(--font-sans);
  font-weight: 700; font-size: 15px; fill: var(--color-charcoal);
  opacity: 1;
}

/* ---- the four steps ---- */
/* Round 1 review (2026-10-15): the white space between steps and between
   map rows is roughly halved (steps 46vh -> 33vh; map rows sized by
   content plus 2rem padding instead of 54vh), lead-ins halved
   (14vh -> 7vh), and both observers now
   light an item as soon as it enters the viewport — cumulatively — not
   while it crosses a mid-screen band. Older notes below describe the
   original tuning. */
.hv2-step {
  min-height: 33vh;
  display: flex; flex-direction: column; justify-content: center;
  opacity: 1;
}
.hv2-step-label {
  font-family: var(--font-mono); font-size: 11px; font-weight: 500;
  color: var(--color-gold); letter-spacing: 0.16em; text-transform: uppercase;
  margin-bottom: 0.85rem;
}
.hv2-step-stmt {
  font-size: clamp(21px, 2.4vw, 30px); font-weight: 600;
  line-height: 1.28; color: var(--color-charcoal);
  max-width: 20ch;
}
/* Subordinate second line: same measure family, clearly quieter than
   the statement above it — smaller, muted, and a narrower 31ch. */
.hv2-step-sub {
  margin-top: 13px;
  font-size: clamp(15.5px, 1.6vw, 18px);
  color: #6B6560;
  line-height: 1.5;
  max-width: 31ch;
}
/* 04 only: the two-word concession sits a shade darker so it reads as
   a beat before the rest of the line. */
.hv2-step-sub-em { color: #3F3A35; font-weight: 500; }

/* ---- scroll behaviour, armed by JS only ----
   Three-stage arm, same as the CARE diagram: (1) CSS default is the
   finished ring, so no-JS and mobile are correct with no scripting;
   (2) .is-scroll jumps to step -1 — no transitions are declared for it
   alone, so this is instantaneous and invisible; (3) .is-live a frame
   later brings the transitions into existence. Declaring them in stage 2
   would animate the page's own set-up — the arc visibly retracting and
   the terms fading out on load. */
.hv2-loop-scroll.is-scroll .hv2-step { opacity: .26; }
.hv2-loop-scroll.is-scroll .hv2-step.is-on { opacity: 1; }
.hv2-loop-scroll.is-scroll .hv2-term { opacity: 0; }
.hv2-loop-scroll.is-scroll .hv2-term.is-on { opacity: 1; }
.hv2-loop-scroll.is-scroll .hv2-dot { r: 7; fill: #DDD5C8; }
.hv2-loop-scroll.is-scroll .hv2-dot.is-on { r: 9.5; fill: var(--color-gold); }
/* step -1: the arc is fully retracted. Set here rather than inline so
   nothing is written to the DOM before the transitions exist. */
.hv2-loop-scroll.is-scroll .hv2-arc { stroke-dashoffset: 829.4; }

/* ---- transitions, added a frame after arming ---- */
.hv2-loop-scroll.is-live .hv2-step { transition: opacity .3s ease; }
.hv2-loop-scroll.is-live .hv2-term { transition: opacity .3s ease; }
.hv2-loop-scroll.is-live .hv2-dot  { transition: r .25s cubic-bezier(.4, 0, .2, 1), fill .25s ease; }
.hv2-loop-scroll.is-live .hv2-arc  { transition: stroke-dashoffset .5s cubic-bezier(.4, 0, .2, 1); }

/* The closing block is the last thing in the right-hand column, and the
   ring is still stuck beside it. Give it the same centring the steps
   use so it sits level with the ring instead of riding up against the
   top of it.

   WHY max(46vh, 480px) AND NOT PLAIN 46vh: a sticky element cannot pass
   the bottom of its containing block, and that containing block ends at
   this block's bottom edge — it is the last thing in the column. At
   46vh (414px at a 900px viewport) the ring ran out of room and was
   pushed up 33px while this block sat dead centre. The block has to be
   at least as tall as the ring for the ring's centre to still reach the
   block's centre, and the ring is never taller than its 480px cap — so
   max(46vh, 480px) holds at every viewport height rather than at the
   one I happened to measure.

   Only while there IS a ring beside it — below 900px the layout is one
   column and this would just add dead space. */
@media (min-width: 900px) {
  .hv2-loop-close {
    min-height: max(46vh, 480px);
    display: flex; flex-direction: column; justify-content: center;
  }
}

/* ---- closing block + hairline ---- */
.hv2-loop-close { margin-top: 2.25rem; }
.hv2-loop-close-lead { font-size: clamp(1.5rem, 3vw, 2.1rem); font-weight: 600; line-height: 1.3; color: var(--color-charcoal); max-width: 26ch; }
.hv2-loop-close-lead .g { color: var(--color-gold); }
.hv2-loop-close-sub { margin-top: 26px; color: #4A443F; font-size: 1.0625rem; line-height: 1.6; max-width: 54ch; }
.hv2-loop-hairline { border: 0; border-top: 1px solid var(--color-stone-divider); margin: 2.75rem 0 0; }

/* ---- under 900px: one column, ring on top, steps as a plain list ----
   The ring is shown finished here, so the .is-scroll rules above are
   all unwound. stroke-dashoffset is the one property the observer
   writes as an INLINE style, so it needs !important to be overridden —
   this is why the script needs no viewport logic and no resize
   listener: crossing the breakpoint mid-session lands correctly. */
/* LEAD-IN. Step 01 sits at the top of the grid, which is also where the
   sticky ring starts — so with the steps flush to the top, 01 crossed the
   observer band while the ring was still rising into view, and the first
   node was already lit by the time the ring was readable.

   That was first solved with 46vh of padding above 01 — half a screen —
   which fixed the ordering and bought it with half a screen of EMPTY
   right-hand column: the section arrived as a ring beside nothing.
   14vh still holds 01 out of the band until the whole grid is on screen,
   and the rest of the gap was never the padding at all — a 46vh step
   with justify-content: center puts its text 23vh down its own box. So
   01 alone top-aligns; 02–04 stay centred, because by then there is
   always a step above and below and centring is what keeps them level
   with the ring. Same fix, same reason, as the CARE diagram's lead-in. */
@media (min-width: 900px) {
  .hv2-loop-steps { padding-top: 7vh; }
  .hv2-step:first-child { justify-content: flex-start; }
}

@media (max-width: 899px) {
  .hv2-loop-scroll { grid-template-columns: 1fr; gap: 0; }
  /* The viewBox is 440 wide with the ring at r=132, so ~20% of the SVG
     box is empty on every side — about 65px at this size. The bottom
     margin is trimmed to 1rem to account for that padding rather than
     stacking a full gap on top of it. */
  .hv2-loop-circle {
    position: static; max-width: 330px;
    justify-self: center; margin-bottom: 1rem;
  }
  .hv2-arc { stroke-dashoffset: 0 !important; }
  .hv2-loop-steps { padding-top: 0; }
  .hv2-loop-scroll.is-scroll .hv2-step,
  .hv2-loop-scroll.is-scroll .hv2-term { opacity: 1; }
  .hv2-loop-scroll.is-scroll .hv2-dot { r: 9.5; fill: var(--color-gold); }
  .hv2-step { min-height: 0; padding: .9rem 0; }
  .hv2-step + .hv2-step { border-top: 1px solid var(--color-stone-divider); }
  .hv2-loop-close { margin-top: 1.5rem; }
}

/* ============================================================
   SHARED HEADER TREATMENT for the sections below the Loop.
   Mirrors the Loop's h2 + gold rule + lede rhythm without touching
   .hv2-loop's own rules. Lede caps at 38rem per the build reference. */
.hv2-sec h2 { font-size: clamp(1.9rem, 3.4vw, 2.6rem); font-weight: 600; line-height: 1.2; max-width: 20ch; }
.hv2-sec-rule { width: 3.5rem; height: 3px; background: var(--color-gold); margin: 1.25rem 0; }
.hv2-sec-lede { max-width: 38rem; color: #4A443F; font-size: 1.0625rem; line-height: 1.6; }

/* Entry motion for everything below the Loop: fade and rise, once.
   Default is VISIBLE — `.is-armed` is added by JS, so with the script
   dead or absent nothing is ever hidden. The Loop is the page's one set
   piece; this is deliberately the whole motion budget down here. */
.hv2-reveal.is-armed {
  opacity: 0; transform: translateY(14px);
  transition: opacity .35s ease, transform .35s ease;
}
.hv2-reveal.is-armed.in { opacity: 1; transform: none; }
/* Section 5 is a plateau: fade only, no rise. */
.hv2-reveal--fade.is-armed { transform: none; }

/* ============================================================
   SECTION 4 — WHAT OWNERS SAY

   Eight statements on the left, four causes on the right, a thin
   connector from each statement to its cause. Two statements land on
   every cause, and the statement order is deliberately NOT grouped by
   cause, so the lines cross — that crossing IS the argument the section
   makes: unrelated-sounding complaints share a small set of origins.

   The connectors are one absolutely-positioned SVG over the board.
   It is a grid CHILD but takes no grid cell: absolutely-positioned grid
   children are out of flow. Path coordinates are recomputed in JS from
   live element boxes — on load, on resize, after webfonts settle, and
   every time a diagnosis opens, since opening one changes the height of
   everything below it and therefore every anchor point.

   Anchors are the BUTTON's box, never the item's, so a statement's line
   stays put when its own diagnosis expands underneath it. */
.hv2-say-board { position: relative; margin-top: 3rem; }
.hv2-say-links {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none; z-index: 0; overflow: visible;
}
.hv2-say-list, .hv2-say-causes { position: relative; z-index: 1; }
/* ENTRY DRAW. Each path carries pathLength="100", so the dash values are
   in hundredths of the line regardless of how long that line actually
   is — which matters because `d` is recomputed on every resize and on
   every diagnosis opening. A measured getTotalLength() would have to be
   re-measured and re-applied each time; this never does.

   PER LINE, NOT PER BOARD, AND REVERSIBLE. `.is-drawn` lands on the
   individual path while its own statement is past the middle of the
   viewport, and comes off when it isn't — scroll down and the line
   draws, scroll back up and it retracts. Scroll position is the
   sequencer, so there is no authored stagger to fall out of step with
   how fast someone is scrolling. A board-level trigger drew all eight
   at the top of the section, which meant the lower lines had finished
   drawing before they were ever on screen.

   Three-stage arm, as on the CARE diagram: (1) CSS default is the drawn
   line, so no-JS is correct; (2) .is-anim retracts, with no transition
   declared for that state alone, so it is instantaneous and invisible;
   (3) .is-live two frames later brings the transitions into existence.
   See the script for why the order matters. */
.hv2-say-link {
  fill: none; stroke: #DDD5C8; stroke-width: 1;
  stroke-dasharray: 100; stroke-dashoffset: 0;
  transition: stroke .25s ease, stroke-width .25s ease, opacity .25s ease;
}
.hv2-say-board.is-anim .hv2-say-link { stroke-dashoffset: 100; }
.hv2-say-board.is-anim .hv2-say-link.is-drawn { stroke-dashoffset: 0; }
.hv2-say-board.is-live .hv2-say-link {
  transition: stroke-dashoffset .45s cubic-bezier(.4, 0, .2, 1),
              stroke .25s ease, stroke-width .25s ease, opacity .25s ease;
}
/* Dimming is a response to a SELECTION, not the resting state — the
   board at rest shows all eight connectors at full weight. `.has-active`
   is set only while a statement is open. */
.hv2-say-board.has-active .hv2-say-link { opacity: .32; }
.hv2-say-board .hv2-say-link.is-on { stroke: var(--color-gold); stroke-width: 1.6; opacity: 1; }

.hv2-say-item {
  border-left: 2px solid transparent;
  transition: border-color .25s ease;
}
.hv2-say-item + .hv2-say-item { margin-top: .35rem; }
.hv2-say-item.is-on { border-left-color: var(--color-gold); }
.hv2-say-btn {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: none; border: 0; font: inherit; color: var(--color-charcoal);
  padding: .7rem 0 .7rem 1rem;
  font-size: clamp(15.5px, 1.5vw, 17.5px); font-weight: 600; line-height: 1.4;
  transition: opacity .25s ease;
}
.hv2-say-btn:focus-visible { outline: 2px solid var(--color-gold); outline-offset: 2px; }
.hv2-say-board.has-active .hv2-say-item:not(.is-on) .hv2-say-btn { opacity: .58; }

.hv2-say-close {
  margin-top: 2.75rem; padding-top: 1.5rem;
  border-top: 1px solid var(--color-stone-divider);
  font-size: clamp(1.05rem, 1.6vw, 1.25rem); line-height: 1.5;
  color: var(--color-charcoal); max-width: 38rem;
}
.hv2-say-close strong { color: var(--color-gold); font-weight: 600; }
.hv2-say-cta { margin-top: 1.5rem; }
.hv2-say-tag {
  display: none; margin-top: .4rem;
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase; color: var(--color-gold);
}
.hv2-say-diag {
  display: none;
  padding: 0 0 .95rem 1rem; max-width: 38rem;
  color: #4A443F; font-size: .95rem; line-height: 1.65;
}
.hv2-say-item.is-on .hv2-say-diag { display: block; }

.hv2-say-causes { display: flex; flex-direction: column; justify-content: space-between; }
.hv2-cause {
  padding: .9rem 0 .9rem 1rem;
  border-left: 2px solid var(--color-stone-divider);
  transition: border-color .25s ease;
}
.hv2-cause.is-on { border-left-color: var(--color-gold); }
.hv2-cause-name { font-size: 1.0625rem; font-weight: 600; color: var(--color-charcoal); }


@media (min-width: 860px) {
  .hv2-say-board {
    display: grid;
    grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr);
    column-gap: clamp(56px, 7vw, 116px);
  }
}
/* Under 860 the lines go entirely and each statement carries its cause
   as a tag instead; the causes list still follows, stacked. */
@media (max-width: 859px) {
  .hv2-say-links { display: none; }
  .hv2-say-tag { display: block; }
  .hv2-say-causes { margin-top: 2.5rem; gap: 1rem; }
}

/* ============================================================
   SECTION 5 — EVERYTHING IN ONE PLACE (dark, sticky diagram)

   Charcoal ground: the page's first tonal shift. Palette is the same
   verified set as before — off-white headings, gold accents, stone-400
   body, all clearing AA on #1F1F1F.

   THE DIAGRAM. viewBox 0 0 520 520. A solid gold hub at (260,260) r=52
   holds eight unlabelled dots. Four line-drawn destinations sit at the
   compass points at .18 opacity. As each row activates its destination
   resolves, its artwork draws in, and its two dots travel out of the
   hub to their final coordinates; their labels fade in on arrival. The
   scoreboard's three bars scale up from their baseline rather than
   fading. After the fourth row the hub goes from solid to outline.

   Each dot is authored AT ITS FINAL POSITION and pushed back into the
   hub by a per-dot `--dx/--dy` translate, so the resolved state is what
   the markup says and the animation is the offset — meaning the no-JS
   and mobile states are correct with no scripting at all.

   NOTHING MOVES ON LOAD. Three-stage arming:
     1. CSS default = fully resolved (no JS, no motion, readable).
     2. JS adds .is-anim  -> jumps to step -1. No transitions are
        declared yet, so this is instantaneous and invisible.
     3. Two rAFs later JS adds .is-live -> transitions now exist.
   Declaring the transitions in step 2 would have animated the page's
   own set-up: eight dots visibly flying INTO the hub on load. */
.hv2-els { background: var(--color-charcoal); }
.hv2-els h2 { color: var(--color-off-white); }
.hv2-els .hv2-sec-lede { color: var(--color-stone-grey); }

.hv2-map {
  margin-top: 3rem;
  display: grid; grid-template-columns: 1fr;
  gap: clamp(32px, 4vw, 64px);
}
@media (min-width: 920px) {
  .hv2-map { grid-template-columns: minmax(0, 510px) minmax(0, 1fr); }
  /* align-self:start — a stretched grid item is as tall as the row and
     has no room to stick */
  .hv2-map-fig { position: sticky; top: calc(50vh - 250px); align-self: start; }

  /* LEAD-IN. Row 1 sits at the top of the grid, which is also where the
     sticky figure starts — so with the rows flush to the top, row 1 hit
     the observer band while the diagram was still rising into view. It
     fired 104px BEFORE the diagram was fully on screen and 292px before
     it settled sticky, so the first two dots finished their 0.9s
     journey off the bottom edge and the hub looked pre-emptied.

     Space above row 1 fixes the ordering: the diagram arrives, settles,
     and holds at step -1 for a beat before anything moves. Chosen over
     widening/moving the rootMargin because the rows are 54vh and the
     band is 10vh — shifting the band high enough to delay row 1 would
     leave every row highlighted only as its content left the top of the
     screen.

     14vh, NOT THE 48vh THIS STARTED AT. Half a screen delayed row 1
     correctly and paid for it with half a screen of empty right-hand
     column — the section came into view as a diagram beside nothing.
     14vh still keeps row 1 out of the band until the whole grid is on
     screen. The other half of that void was never the padding: a 54vh
     row with justify-content: center holds its text 27vh down its own
     box, so row 1 alone top-aligns. Rows 2–4 stay centred — from there
     on there is always a row above and below, and centring is what keeps
     each one level with the sticky diagram. */
  .hv2-map-rows { padding-top: 7vh; }
  .hv2-map-row:first-child { justify-content: flex-start; }
}
.hv2-map-fig { width: 100%; max-width: 510px; justify-self: center; }
.hv2-map-svg { display: block; width: 100%; height: auto; overflow: visible; }

/* ---- diagram: resolved state (also the no-JS and mobile state) ---- */
.hv2-hub { fill: rgba(185, 122, 43, 0); stroke: var(--color-gold); stroke-width: 2; }
.hv2-ghost { opacity: .18; }
.hv2-draw { fill: none; stroke: var(--color-gold); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.hv2-bar { fill: var(--color-gold); transform: scaleY(1); transform-box: fill-box; transform-origin: 50% 100%; }
.hv2-dlabel {
  font-family: var(--font-mono); font-size: 9px; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  fill: var(--color-gold); text-anchor: middle;
}
/* charcoal ring so the dots read as distinct while they sit on the solid
   gold hub; invisible against the charcoal ground once they are out */
.hv2-node circle { fill: var(--color-gold); stroke: var(--color-charcoal); stroke-width: 1.5; }
.hv2-nlabel {
  font-family: var(--font-mono); font-size: 9px; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase;
  fill: var(--color-gold); text-anchor: middle; opacity: 1;
}

/* ---- step -1: armed by JS, no transitions declared here ---- */
.hv2-map.is-anim .hv2-hub { fill: var(--color-gold); }
.hv2-map.is-anim .hv2-dlabel { opacity: .18; }
.hv2-map.is-anim .hv2-live .hv2-draw { stroke-dasharray: 100; stroke-dashoffset: 100; }
.hv2-map.is-anim .hv2-live .hv2-bar { transform: scaleY(0); }
.hv2-map.is-anim .hv2-nlabel { opacity: 0; }
.hv2-map.is-anim .hv2-node { transform: translate(var(--dx), var(--dy)); }

/* ---- resolved-per-destination, once a row activates ---- */
.hv2-map.is-anim .hv2-dest.is-on .hv2-dlabel { opacity: 1; }
.hv2-map.is-anim .hv2-dest.is-on .hv2-live .hv2-draw { stroke-dashoffset: 0; }
.hv2-map.is-anim .hv2-dest.is-on .hv2-live .hv2-bar { transform: scaleY(1); }
.hv2-map.is-anim .hv2-node.is-on { transform: translate(0, 0); }
.hv2-map.is-anim .hv2-node.is-on .hv2-nlabel { opacity: 1; }
.hv2-map.is-anim.is-open .hv2-hub { fill: rgba(185, 122, 43, 0); }

/* ---- transitions, added a frame after arming ---- */
.hv2-map.is-live .hv2-hub { transition: fill .45s ease; }
.hv2-map.is-live .hv2-dlabel { transition: opacity .3s ease .15s; }
.hv2-map.is-live .hv2-draw { transition: stroke-dashoffset .55s cubic-bezier(.4, 0, .2, 1); }
.hv2-map.is-live .hv2-node { transition: transform .55s cubic-bezier(.4, 0, .2, 1); }
.hv2-map.is-live .hv2-nlabel { transition: opacity .25s ease .4s; }
/* bars rise after their baseline has drawn, ~180ms apart */
.hv2-map.is-live .hv2-bar { transition: transform .35s cubic-bezier(.4, 0, .2, 1); }
.hv2-map.is-live .hv2-live .hv2-bar:nth-of-type(1) { transition-delay: .2s; }
.hv2-map.is-live .hv2-live .hv2-bar:nth-of-type(2) { transition-delay: .3s; }
.hv2-map.is-live .hv2-live .hv2-bar:nth-of-type(3) { transition-delay: .4s; }

/* ---- the four rows ---- */
.hv2-map-row {
  min-height: 0; padding: 2rem 0;
  display: flex; flex-direction: column; justify-content: center;
  opacity: 1;
}
.hv2-map.is-anim .hv2-map-row { opacity: .22; }
.hv2-map.is-anim .hv2-map-row.is-on { opacity: 1; }
.hv2-map.is-live .hv2-map-row { transition: opacity .3s ease; }
.hv2-map-head { display: flex; align-items: baseline; gap: .85rem; }
.hv2-map-letter { font-size: clamp(2rem, 3.4vw, 2.7rem); font-weight: 600; line-height: 1; color: var(--color-gold); }
.hv2-map-name { font-size: clamp(1.15rem, 1.8vw, 1.4rem); font-weight: 600; color: var(--color-off-white); }
.hv2-map-pair { margin-top: 1.35rem; display: grid; grid-template-columns: 1fr; gap: 1.35rem; }
@media (min-width: 1280px) {
  .hv2-map-pair { grid-template-columns: 1fr 1fr; gap: 2.25rem; }
}
.hv2-map-lbl {
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--color-stone-inactive); margin-bottom: .5rem;
}
.hv2-map-lbl--out { color: var(--color-gold); }
.hv2-map-txt { color: var(--color-stone-grey); font-size: .975rem; line-height: 1.6; }
.hv2-map-txt--out { color: var(--color-off-white); }
/* third beat: what the owner actually gets. Spans the pair's two columns
   so it reads as a conclusion rather than a third parallel column. */
.hv2-map-buys { margin-top: 1.35rem; padding-top: 1.35rem; border-top: 1px solid rgba(250, 250, 248, .14); }
@media (min-width: 1280px) { .hv2-map-buys { grid-column: 1 / -1; } }

.hv2-els-foot {
  margin-top: 2.75rem; max-width: 38rem;
  color: var(--color-stone-grey); font-size: 1.0625rem; line-height: 1.6;
}
.hv2-els-foot strong { color: var(--color-off-white); font-weight: 600; }
/* TEXT LINKS — one rule, and it draws.
   These carried a static gold border-bottom, and main.css separately
   forces `text-decoration: underline !important` on every a:hover — so
   hovering produced two lines at once. The border is gone and the
   global underline is suppressed (only !important reaches it, and
   .hv2-els-link:hover outweighs a:hover on specificity); what's left is
   the same background-size sweep the testimonials use, growing a single
   gold rule from the left. */
.hv2-els-link, .hv2-textlink, .hv2-quietlink {
  font-weight: 600;
  padding-bottom: 2px;
  background-image: linear-gradient(var(--color-gold), var(--color-gold));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 2px;
  transition: background-size .45s cubic-bezier(.4, 0, .2, 1), color .2s ease;
}
.hv2-els-link:hover, .hv2-els-link:focus-visible,
.hv2-textlink:hover, .hv2-textlink:focus-visible,
.hv2-quietlink:hover, .hv2-quietlink:focus-visible {
  background-size: 100% 2px;
  color: var(--color-gold);
  text-decoration: none !important;
}
.hv2-els-link {
  display: inline-block; margin-top: 1.35rem;
  color: var(--color-off-white);
}
/* .hv2-els-link's light-ground twin — identical sweep and rhythm, but
   charcoal, since these two sit on cream rather than on the dark map
   section. A text link and not .btn-primary deliberately: each of these
   is a few hundred pixels from a real button (the say-close CTA above,
   the three cards below), and a second button there would read as the
   page asking twice. */
.hv2-quietlink {
  display: inline-block; margin-top: 1.35rem;
  color: var(--color-charcoal);
}

/* ---- under 920: one column, diagram resolved on top, rows as a list.
       These rules sit after the .is-anim block, so equal specificity
       resolves in their favour and the armed state is fully unwound —
       the script needs no viewport branching. ---- */
@media (max-width: 919px) {
  .hv2-map-fig { max-width: 330px; position: static; }
  .hv2-map.is-anim .hv2-hub { fill: rgba(185, 122, 43, 0); }
  .hv2-map.is-anim .hv2-dlabel { opacity: 1; }
  .hv2-map.is-anim .hv2-live .hv2-draw { stroke-dashoffset: 0; }
  .hv2-map.is-anim .hv2-live .hv2-bar { transform: scaleY(1); }
  .hv2-map.is-anim .hv2-nlabel { opacity: 1; }
  .hv2-map.is-anim .hv2-node { transform: translate(0, 0); }
  .hv2-map.is-anim .hv2-map-row { opacity: 1; }
  .hv2-map-row { min-height: 0; padding: .9rem 0; }
  .hv2-map-row + .hv2-map-row { border-top: 1px solid rgba(250, 250, 248, .14); }
}


/* ============================================================
   SHARED EYEBROW for the sections added below. Same treatment the
   AFTERWARD section already uses; lifted to its own class rather than
   reused by name so the two can diverge without surprise. */
.hv2-eyebrow {
  font-family: var(--font-mono); font-size: 11px; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--color-gold); margin-bottom: .85rem;
}

/* ============================================================
   SECTION A — NOT AN OPERATING SYSTEM (light)

   A comparison laid out as a grid rather than a <table>: the rows are
   four independent comparisons with no header-cell relationships worth
   announcing, and the mobile collapse turns each row into a stacked
   pair, which a real table cannot do without losing its semantics.

   COLUMN GAP IS ZERO on purpose. The gold rule is absolutely
   positioned at exactly the label column's width, so it lands on the
   leading edge of the "Built to Benefit" column. With a column-gap the
   second column would start at 150px + gap and the rule would float in
   open space. Cells carry their own padding instead. */
.hv2-vs-table {
  position: relative;
  margin-top: 2.75rem;
  border-top: 2px solid var(--color-charcoal);
}
/* LABEL COLUMN IS 190px, NOT THE 150px THIS STARTED AT. The mono labels
   went from 10.5px to 13px, and "Time to running" is 15 characters —
   at 13px with .14em tracking that is ~144px, which no longer cleared
   150px once the cell's own 1.75rem of right padding came off it, so it
   wrapped to two lines while its three neighbours stayed on one.
   .hv2-vs-rule's `left` is the same number and moves with it. */
.hv2-vs-head, .hv2-vs-row {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr) minmax(0, 1fr);
  column-gap: 0;
}
.hv2-vs-row { border-top: 1px solid var(--color-stone-divider); }
/* 1.75rem block padding, up from 1.15rem — roughly 10px more above and
   below every cell. At 13px the labels were sitting almost on the
   hairline that separates their row from the one above. */
.hv2-vs-head > *, .hv2-vs-row > * { padding: 1.75rem 1.75rem 1.75rem 0; }
.hv2-vs-head > *:nth-child(2), .hv2-vs-row > *:nth-child(2) { padding-left: 1.5rem; }
.hv2-vs-head > *:nth-child(3), .hv2-vs-row > *:nth-child(3) { padding-left: 1.5rem; }
/* The head has the table's 2px charcoal rule above it rather than a row
   hairline, so it takes the same treatment measured from that edge. */
.hv2-vs-head > * { padding-top: .625rem; padding-bottom: 1.5rem; }

.hv2-vs-us-h, .hv2-vs-them-h {
  font-family: var(--font-mono); font-size: 13px; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
}
.hv2-vs-us-h { color: var(--color-gold); }
.hv2-vs-them-h { color: var(--color-stone-inactive); }
.hv2-vs-lbl {
  font-family: var(--font-mono); font-size: 13px; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--color-stone-inactive);
}
/* SAME WEIGHT BOTH SIDES. The US cell carried font-weight: 500 against
   the THEM cell's inherited 400, so the comparison was being made in
   typography as well as in words — the page putting its thumb on the
   scale. Colour carries the distinction on its own now: charcoal
   against #6B6560. Both weights are stated rather than one being left
   to inherit, so the pair can't drift apart again. */
.hv2-vs-us { color: var(--color-charcoal); font-size: 1rem; font-weight: 400; line-height: 1.55; }
.hv2-vs-them { color: #6B6560; font-size: 1rem; font-weight: 400; line-height: 1.55; }

/* Top of the rows, not of the table: the rule marks the comparison,
   not the header. */
.hv2-vs-rule {
  position: absolute; left: 190px; top: 0; bottom: 0; width: 3px;
  background: var(--color-gold);
  transform: scaleY(0); transform-origin: 50% 0;
}
.hv2-vs-table.is-armed .hv2-vs-rule { transform: scaleY(0); }
.hv2-vs-table.is-armed.in .hv2-vs-rule {
  transform: scaleY(1);
  transition: transform 1.4s cubic-bezier(.4, 0, .2, 1);
}

/* Each row arms itself and runs its own pair — the US cell, then the
   THEM cell 160ms behind it. */
.hv2-vs-row.is-armed .hv2-vs-us,
.hv2-vs-row.is-armed .hv2-vs-them {
  opacity: 0; transform: translateY(10px);
  transition: opacity .5s ease, transform .5s ease;
}
.hv2-vs-row.is-armed .hv2-vs-them { transition-delay: .16s; }
.hv2-vs-row.is-armed.in .hv2-vs-us,
.hv2-vs-row.is-armed.in .hv2-vs-them { opacity: 1; transform: none; }

.hv2-vs-seq {
  margin-top: 2.5rem; padding: .2rem 0 .2rem 1.25rem; max-width: 42rem;
  border-left: 3px solid var(--color-gold);
  color: #4A443F; font-size: 1.0625rem; line-height: 1.6;
}
.hv2-vs-seq strong { color: var(--color-charcoal); font-weight: 600; }
.hv2-vs-note {
  margin-top: 1.35rem; max-width: 42rem;
  color: var(--color-stone-inactive); font-size: .95rem; line-height: 1.6;
}

/* Under 900 the three columns become one stack. The header row and the
   gold rule both describe a column relationship that no longer exists,
   so both go, and each cell names its own side instead. */
@media (max-width: 899px) {
  .hv2-vs-head, .hv2-vs-rule { display: none; }
  .hv2-vs-row { grid-template-columns: 1fr; }
  .hv2-vs-head > *, .hv2-vs-row > * { padding: 0 0 .55rem 0; }
  .hv2-vs-row { padding: 1.25rem 0; }
  .hv2-vs-row > *:nth-child(2), .hv2-vs-row > *:nth-child(3) { padding-left: 0; }
  .hv2-vs-row > *:last-child { padding-bottom: 0; }
  .hv2-vs-us::before {
    content: "Built to Benefit \2014 "; color: var(--color-gold); font-weight: 600;
  }
  .hv2-vs-them::before {
    content: "Operating systems \2014 "; color: var(--color-stone-inactive); font-weight: 600;
  }
}


/* WIDE VIEWPORTS — the vertical-rhythm trim these sections had on the
   homepage. #how-it-works is the C.A.R.E. section (it was #hv2-els). */
@media (min-width: 1280px) {
  #hv2-loop, #hv2-say, #how-it-works { padding-top: 4.75rem; padding-bottom: 4.75rem; }
  .hv2-loop-scroll  { margin-top: 2.25rem; }
  .hv2-loop-close   { margin-top: 1.5rem; }
  .hv2-loop-hairline{ margin-top: 1.875rem; }
}

/* ============================================================
   SCROLL-LINKED LOOP AND C.A.R.E. MAP (2026-10-15, round 2)

   Supersedes the band/observer timing described in the notes above.

   GEOMETRY. Each diagram is a sticky box exactly as big as the
   diagram, with a sticky `top` that centres it in the viewport below
   the site header. In normal flow the diagram and the first item sit
   side by side with their centres level; the column beside it ends
   exactly half a diagram below the last item's centre, so when the
   diagram unsticks it comes to rest centred on the last item.

   TIMING. The alignment point is the diagram's own centre, read from
   its box every frame. The script at the end of the page sets the arc,
   dots, terms, drawings and node positions directly from where the
   text sits relative to that point, so nothing scroll-linked has a
   transition. Below the desktop breakpoints, and with reduced motion,
   the script never arms and both diagrams show finished.
   ============================================================ */
#hv2-loop-scroll { --hv2-hdr: 5rem; }
#hv2-map { --hv2-hdr: 5rem; }
#hv2-loop-scroll .hv2-arc,
#hv2-map .hv2-draw, #hv2-map .hv2-bar, #hv2-map .hv2-node,
#hv2-map .hv2-nlabel, #hv2-map .hv2-dlabel, #hv2-map .hv2-hub { transition: none; }
#hv2-loop-scroll.is-live .hv2-step,
#hv2-loop-scroll.is-live .hv2-term { transition: opacity .2s ease; }
#hv2-loop-scroll.is-live .hv2-dot  { transition: r .2s ease, fill .2s ease; }
#hv2-map.is-live .hv2-map-row { transition: opacity .2s ease; }

/* Mobile: plain lists, equal gaps (.9rem + .9rem) between every step
   and before the closing block. The ring's viewBox is cropped to the
   drawing, so it needs a smaller box than before for the same size. */
@media (max-width: 899px) {
  #hv2-loop-scroll .hv2-loop-circle { max-width: 240px; }
  #hv2-loop-scroll .hv2-loop-close { margin-top: 0; padding-top: .9rem; }
}
/* Mobile and tablet: the diagram fills the column (up to 420px) and the
   icon labels go to 14 units, about 10px at 390 wide. The small node
   labels would overlap each other at a readable size, so they are
   hidden here; the dots stay. */
@media (max-width: 919px) {
  #hv2-map .hv2-map-fig { margin: 0 auto; width: 100%; max-width: 420px; }
  #hv2-map .hv2-dlabel { font-size: 14px; }
  #hv2-map .hv2-nlabel { display: none; }
}

/* ---- loop, desktop ----
   --hv2-ring: the ring's box (its viewBox is cropped to the drawing),
   345px at 1440 wide; the terms scale with it.
   --hv2-pitch: centre-to-centre spacing of steps and the closing block;
   every one is exactly this tall with its text centred in it. When the
   ring is smaller than the pitch it gets symmetric margins instead of
   the column getting padding, so the centres still line up at both
   ends (a sticky box's margins count against its containing block). */
@media (min-width: 900px) {
  #hv2-loop-scroll {
    --hv2-pitch: 300px;
    --hv2-ring: min(clamp(276px, 25.3vw, 345px), calc(100vh - var(--hv2-hdr) - 2rem));
    /* 96px to the ring's box; a ring smaller than the pitch carries a
       top margin (below), so that margin comes off this one */
    margin-top: calc(6rem - max(0px, calc((var(--hv2-pitch) - var(--hv2-ring)) / 2)));
  }
  #hv2-loop-scroll .hv2-loop-circle {
    position: sticky; align-self: start; justify-self: center;
    top: calc(var(--hv2-hdr) + (100vh - var(--hv2-hdr) - var(--hv2-ring)) / 2);
    width: var(--hv2-ring); height: var(--hv2-ring); max-width: none;
    margin: max(0px, calc((var(--hv2-pitch) - var(--hv2-ring)) / 2)) 0;
  }
  #hv2-loop-scroll .hv2-ring { width: 100%; height: 100%; max-width: none; }
  #hv2-loop-scroll .hv2-loop-steps {
    padding-top: max(0px, calc((var(--hv2-ring) - var(--hv2-pitch)) / 2));
    padding-bottom: max(0px, calc((var(--hv2-ring) - var(--hv2-pitch)) / 2));
  }
  #hv2-loop-scroll .hv2-step,
  #hv2-loop-scroll .hv2-loop-close {
    height: var(--hv2-pitch); min-height: 0; margin: 0; padding: 0;
    display: flex; flex-direction: column; justify-content: center;
  }
  /* the hairline would push the closing text off centre; it isn't
     needed on desktop, where the section's own bottom edge follows */
  #hv2-loop-scroll .hv2-loop-hairline { display: none; }
}

/* ---- map, desktop ----
   The figure sits in its own column wrapper. The script sizes that
   wrapper (and the space above C) from the measured pillar blocks,
   because a pillar's height depends on its text: the wrapper ends half
   a diagram below the centre of E's block, so the diagram comes to rest
   centred on it.

   --hv2-map is the diagram's size: 576px at 1440 x 900, about 25%
   larger than the old 510px drawing (its viewBox is now cropped to the
   ink), and never more than the viewport below the header less 4rem.
   It is wider than its 510px column, so it overhangs the column evenly
   on both sides instead of narrowing the text column. */
@media (min-width: 920px) {
  #hv2-map {
    --hv2-map: min(576px, 56vw, calc(100vh - var(--hv2-hdr) - 4rem));
    margin-top: 6rem;
  }
  #hv2-map .hv2-map-figcol { align-self: start; }
  #hv2-map .hv2-map-fig {
    position: sticky;
    top: calc(var(--hv2-hdr) + (100vh - var(--hv2-hdr) - var(--hv2-map)) / 2);
    width: 100%; height: var(--hv2-map); max-width: none;
    display: block;
  }
  #hv2-map .hv2-map-svg {
    width: var(--hv2-map); height: var(--hv2-map); max-width: none;
    margin-left: calc((100% - var(--hv2-map)) / 2);
  }
  #hv2-map .hv2-map-rows { padding-top: 0; padding-bottom: 0; }
  #hv2-map .hv2-map-row { min-height: 0; padding: 6rem 0; justify-content: flex-start; }
  #hv2-map .hv2-map-row:first-child { padding-top: 0; }
  #hv2-map .hv2-map-row:last-child { padding-bottom: 0; }
  #hv2-map ~ .hv2-els-foot { margin-top: 6rem; }
}

/* Each pillar row ends with a link to its pillar page. A flex item in a
   column stretches by default, which would run the link's sweep across the
   whole column. */
.hv2-map-more { align-self: flex-start; }

@media (prefers-reduced-motion: reduce) {
  .hv2-arc { transition: none; }
  .hv2-loop-scroll.is-scroll .hv2-step { opacity: 1; }
  .hv2-loop-scroll.is-live .hv2-step,
  .hv2-loop-scroll.is-live .hv2-term,
  .hv2-loop-scroll.is-live .hv2-dot { transition: none; }
  .hv2-reveal.is-armed { opacity: 1; transform: none; transition: none; }
  .hv2-map.is-live .hv2-hub,
  .hv2-map.is-live .hv2-dest,
  .hv2-map.is-live .hv2-draw,
  .hv2-map.is-live .hv2-node,
  .hv2-map.is-live .hv2-nlabel,
  .hv2-map.is-live .hv2-bar,
  .hv2-map.is-live .hv2-map-row { transition: none; }
  /* Section 4 connectors and section 6 cards: no stagger, no sweep —
     everything is simply there, which is also the no-JS state. These
     sit after both hover media queries, so equal specificity resolves
     in their favour. */
  .hv2-say-board.is-anim .hv2-say-link,
  .hv2-say-board.is-anim .hv2-say-link.is-drawn { stroke-dashoffset: 0; }
  .hv2-say-board.is-live .hv2-say-link { transition: none; }
  .hv2-els-link, .hv2-textlink, .hv2-quietlink { transition: none; }
  .hv2-vs-table.is-armed .hv2-vs-rule,
  .hv2-vs-table.is-armed.in .hv2-vs-rule { transform: scaleY(1); transition: none; }
  .hv2-vs-row.is-armed .hv2-vs-us,
  .hv2-vs-row.is-armed .hv2-vs-them,
  .hv2-vs-row.is-armed .hv2-vs-them {
    opacity: 1; transform: none; transition: none; transition-delay: 0s;
  }
}
