/* ===================== the flywheel =====================
   Monarch's cycle drawn as one wheel: the model at the hub, four stations
   around it, every station feeding the model and the model handing the next
   prediction back to the bench. The wheel is the first screen of How it
   works and takes the largest square the window allows.

   The node labels here are placeholders. Copy gets assigned per node later;
   the geometry is sized so a label of up to eleven characters a line fits
   inside a station, which is what the longest placeholder needs. */
/* The wheel is the page's first screen, so this page starts at the top of the
   window rather than on the interior pages' deep top padding. The intro that
   used to lead the page takes its own clearance underneath instead. */
/* ---- this page's header ----
   Elsewhere the masthead floats over the page. Here a drawer slides up to it,
   so it is a defined bar instead: fixed, opaque, on a hairline, and above the
   drawer rather than under it. The drawer starts where the bar ends, which is
   why the bar needs a height anyone can compute -- the mark is 310x64, so its
   drawn height is its width over that ratio. */
.page-how-it-works{
  --mh-pad:clamp(16px,1.6vw,28px);
  /* The mark is 310x64, so its drawn height is its width over that ratio.
     The safe-area inset belongs in here too: the masthead's own top padding
     carries it (the page is viewport-fit=cover), so a notch makes the real bar
     taller than the figure the drawer and the wheel are measuring against. On
     a 390pt iPhone that left the drawer starting 25px above the bar's
     underside, showing the page through the gap. */
  --fw-header:calc(
    2 * var(--mh-pad)
    + clamp(190px,16.15vw,310px) / 4.84375
    + env(safe-area-inset-top, 0px)
  );
}
.page-how-it-works .masthead{
  position:fixed;
  --masthead-top:calc(var(--mh-pad) + env(safe-area-inset-top, 0px));
  padding-bottom:var(--mh-pad);
  background:var(--band);
  border-bottom:1px solid var(--line);
  z-index:70;
}
.page-how-it-works main.how-page{padding-top:0}
/* The clip that guards the bleed belongs on the body, at the window's edge.
   On main it clips at the page's 1180px measure instead, which cuts the left
   of the wheel off on any window wider than that. overflow:clip is not a
   scroll container, so the sticky nav further down the page still works. */
body.page-how-it-works{overflow-x:clip}

.fw{
  /* Two columns on the landing: the wheel on the left, the page's own opening
     on the right. The drawer covers the right column when a stage opens. */
  --fw-max:540px;
  --fw-drawer-bg:#282828;
  /* The header is a bar with a known height now, so the wheel clears it by
     measurement rather than by guessing at a floating mark's reach. */
  --fw-gap:calc(var(--fw-header) + clamp(24px,4vh,64px));
  /* The wheel's drawn size, named rather than inlined, because the drawer
     reads it to put its first rule on the same line as the top of the wheel.
     The column term is 50vw rather than 100% so it means the same thing in
     both places. */
  --fw-size:min(
    calc(50vw - 2 * var(--gutter-band)),
    calc(100svh - 2 * var(--fw-gap)),
    var(--fw-max)
  );
  position:relative;
  /* The page's reading measure is 1180px; this screen is the window's. The
     negative margins pull the section out of that measure, and main clips the
     overflow so a classic scrollbar cannot turn the bleed into a sideways
     scroll. */
  margin-inline:calc(50% - 50vw);
  min-height:100svh;
  display:grid;
  grid-template-columns:1fr 1fr;
  align-items:center;
  /* The row is as tall as the taller column, which is the copy, not the
     wheel. Without this the row sits at the top of the box and the wheel
     centres inside the row, which is a different line from the one the
     drawer computes. Centring the row too makes the two agree exactly. */
  align-content:center;
  box-sizing:border-box;
  /* The top gap carries the header's height; the bottom has no header to
     clear, so it keeps only the breathing room. Padding them alike put three
     times as much air under the wheel as over it. */
  padding:var(--fw-gap) 0 clamp(24px,4vh,64px);
}
/* The copy comes first in the DOM, so the heading leads the page for a reader
   and for a phone. On two columns the wheel is placed back on the left by
   hand rather than by source order. */
.fw-stage{grid-area:1/1;display:grid;place-items:center;padding-inline:var(--gutter-band);min-width:0}
.fw-svg{
  display:block;
  /* min-width:0 matters: without it the square's automatic minimum size is
     transferred from the row height through the aspect ratio, and the wheel
     pushes its own grid wider than the window on a phone. */
  min-width:0;
  width:min(100%, var(--fw-size));
  aspect-ratio:1/1;
  height:auto;
  overflow:visible;
}

/* The landing copy, which the drawer slides over.

   Everything here is sized against the column rather than the window. The
   page's own h1 runs at 5.7vw, which is drawn for a full-width measure; in a
   column that is half the window it arrives far larger than it should. The
   coefficients here land between that and the column-width scale, which read
   as too quiet.
   The measure is capped as well, so a wide window buys white space rather
   than longer lines. */
.fw-intro{
  /* Both are placed by hand, row included: with the copy first in the DOM,
     naming only the column sends the wheel to a second row, because grid
     auto-placement will not step back to a column it has already passed. */
  grid-area:1/2;
  padding-inline:clamp(24px,4vw,80px) var(--gutter-band);
  max-width:min(100%,36rem);
  min-width:0;
}
.fw-intro h1{
  margin:clamp(24px,3vh,38px) 0 0;
  font-size:clamp(36px,4.1vw,62px);
  line-height:1.08;
  letter-spacing:-.035em;
}
.fw-intro p.how-intro-copy{
  margin-top:clamp(28px,3.6vh,46px);
  max-width:46ch;
  font-size:clamp(17px,1.85vw,23px);
  line-height:1.65;
}
.fw-intro p.how-intro-note{
  margin-top:clamp(26px,3.2vh,40px);
  color:var(--mut);
  font-size:14px;
  line-height:1.6;
}

/* The flows. One hairline ink for the whole wheel, with the arrowheads a
   step brighter so direction reads before anything else does. */
.fw-line,
.fw-pulse,
.fw-head{fill:none}
/* Flat-cut ends and a mitred tip. A rounded cap softens both the shaft where
   it meets a rim and the two arms of the head, which is what made the arrows
   read as drawn rather than drafted. */
.fw-line,
.fw-head{stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:6}
/* The head is the line: same width, same ink. Anything brighter at the tip
   reads as a heavier stroke even when the width is identical, which is what
   made the heads sit on top of the wheel rather than in it. */
.fw-line,
.fw-head{stroke:rgba(255,255,255,.26);stroke-width:2.6}
/* The travelling light keeps its round cap -- it is a light, not an arrow. */
.fw-pulse{stroke-linecap:round}
.fw-line,.fw-head{transition:stroke .3s var(--ease)}

/* A short accent segment travels each flow in its own direction. The delays
   are negative so the wheel is already turning when the page arrives rather
   than standing still for a full cycle, and they are spaced a quarter of the
   cycle apart so a piece of data reaches the hub every 1.5s. Those four
   arrivals are what --fw-period and the hub's tap below are keyed to: change
   one and all five have to move together. */
.fw{--fw-period:6s}
/* OFF FOR NOW, at J's ask: the travelling lights. The animation and the four
   arrival delays below are intact -- delete this one rule to bring them back.
   The hub tap that used to answer them is gone for good, not switched off. */
.fw-pulse{display:none}

.fw-pulse{
  stroke:var(--accent);
  stroke-width:3.4;
  stroke-dasharray:8 92;
  stroke-dashoffset:100;
  animation:fw-travel var(--fw-period) linear infinite;
}
@keyframes fw-travel{from{stroke-dashoffset:100}to{stroke-dashoffset:0}}
/* Arrivals at the hub, in order: 1.5s, 3s, 4.5s, 6s. */
#fw-in-lab{animation-delay:-4.5s}
#fw-in-field{animation-delay:-3s}
#fw-in-dock{animation-delay:-1.5s}
#fw-in-comm{animation-delay:0s}
/* The ring and the return, interleaved between those arrivals. */
#fw-ring-lab-field{animation-delay:-5.25s}
#fw-ring-field-dock{animation-delay:-3.75s}
#fw-ring-dock-comm{animation-delay:-2.25s}
#fw-out-lab{animation-delay:-.75s}

/* The stations. Their fill is the page, so a flow passing behind one is
   clipped by the station rather than crossing its label. */
.fw-node{cursor:pointer;outline:none}
.fw-hit{fill:none;pointer-events:all}
.fw-node-ring{
  fill:var(--band);
  stroke:var(--line-strong);
  stroke-width:2.6;
  transform-box:fill-box;
  transform-origin:center;
  transition:stroke .25s var(--ease),fill .25s var(--ease),transform .25s var(--ease);
}
.fw-node-label{
  fill:var(--dim);
  font-family:var(--mono);
  font-size:20px;
  letter-spacing:.09em;
  text-transform:uppercase;
  transition:fill .25s var(--ease);
}

/* The hub carries the weight: the only teal ring and the only display type. */
.fw-hub-ring{
  fill:rgba(70,165,166,.07);
  stroke:var(--accent);
  stroke-width:3;
  transform-box:fill-box;
  transform-origin:center;
}
.fw-hub-label{
  fill:var(--ink);
  font-family:var(--sans);
  font-size:66px;
  font-weight:300;
  letter-spacing:-.03em;
}
.fw-hub-sub{
  fill:var(--accent);
  font-family:var(--mono);
  font-size:20px;
  letter-spacing:.14em;
  text-transform:uppercase;
}

/* ---- the stage you are on ----
   The circle inverts: the accent becomes its fill and the label takes the
   band's own ink. The mark in the hub is black art held white by a filter, so
   dropping the filter turns it dark against the teal -- the inversion comes
   for free rather than wanting a second file. */
.fw-node[data-fw-on] .fw-node-ring,
.fw-node[data-fw-on] .fw-hub-ring{fill:var(--accent);stroke:var(--accent)}
.fw-node[data-fw-on] .fw-node-label,
.fw-node[data-fw-on] .fw-hub-sub{fill:var(--accent-ink)}
.fw-node[data-fw-on] .fw-hub-mark{filter:none}
.fw-hub-mark{filter:invert(1);transition:filter .25s var(--ease)}
.fw-hub-ring,.fw-hub-sub{transition:fill .25s var(--ease),stroke .25s var(--ease)}

/* ---- hover and focus ---- */
/* The ring lifts a hair and takes the accent; the station's own flows come up
   with it, so hovering shows what that circle is wired to. */
.fw-node:hover .fw-node-ring,
.fw-node:focus-visible .fw-node-ring{stroke:var(--accent);transform:scale(1.035)}
.fw-node:hover .fw-node-label,
.fw-node:focus-visible .fw-node-label{fill:var(--ink)}
.fw-hit{stroke:none;transition:stroke .15s var(--ease)}
.fw-node:focus-visible .fw-hit{stroke:var(--accent);stroke-width:1.6;stroke-dasharray:4 7}


/* The hub answers hover without transform: its ring is already being
   transformed by the tap, and an animation outranks a plain declaration. */
.fw-node[data-fw-node="model"]:hover .fw-hub-ring,
.fw-node[data-fw-node="model"]:focus-visible .fw-hub-ring{stroke-width:4.4}
.fw-node[data-fw-node="model"]:hover .fw-hub-sub,
.fw-node[data-fw-node="model"]:focus-visible .fw-hub-sub{fill:var(--ink)}
.fw-hub-ring,.fw-hub-sub{transition:stroke-width .25s var(--ease),fill .25s var(--ease)}

/* With a station open the rest of the wheel steps back rather than
   disappearing -- the loop still has to read as a loop. */

.fw-flow.is-lit .fw-line,
.fw-flow.is-lit .fw-head{stroke:rgba(255,255,255,.5)}

/* The band's own crop is 50% 59%, framed for the landscape photographs the
   other pages use. This file is already cropped to the rows a band can show --
   centred on the head, the wand and the mist -- so it wants its own centre. */
.page-how-it-works .cta-band-bg{object-position:50% 50%}

/* The first screen already ends on its own breathing room, and it is a full
   screen, so the band begins where it ends. The component's own top margin is
   for pages whose copy runs straight into it. */
.page-how-it-works .cta-band--bleed{margin-top:0}

/* ===================== the drawer =====================
   It slides over the right half of the window, masthead included, and the
   wheel underneath stays live: clicking another circle swaps the panel rather
   than closing and reopening. */
.fw-drawer{
  position:fixed;
  inset:var(--fw-header) 0 0 auto;
  /* Exactly the column it covers. Capping this at 820px left the landing copy
     showing between the divider and the drawer's edge on anything wider than
     1640 -- 140px of it at 1920, 380px at 2400. The reading measure belongs
     inside the drawer, not on the drawer. */
  width:50vw;
  z-index:60;
  background:var(--fw-drawer-bg);
  /* A hairline edge and no shadow: the drawer meets the wheel on a line
     rather than smudging a gradient across it. */
  border-left:1px solid var(--line-strong);
  transform:translateX(100%);
  visibility:hidden;
  transition:transform .46s var(--ease-chrome),visibility 0s linear .46s;
}
.fw[data-fw-open] .fw-drawer{
  transform:translateX(0);
  visibility:visible;
  transition:transform .46s var(--ease-chrome),visibility 0s;
}
.fw-drawer-scroll{
  height:100%;
  overflow-y:auto;
  overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
  /* The content starts at the top of the drawer. It used to be measured down
     to the wheel's own top line, which the script had to compute; J took that
     back, and the measuring went with it. */
  padding-block:0 clamp(64px,10vh,120px);
  padding-inline:clamp(24px,5vw,88px);
  box-sizing:border-box;
}

/* The measure the drawer reads at, centred in whatever width the column is.
   Below about 1500 the column is narrower than this and the padding governs. */
.fw-drawer-bar,
.fw .fw-panel{max-width:680px;margin-inline:auto}

.fw-drawer-bar{
  display:flex;
  justify-content:space-between;
  gap:20px;
  /* No rule above it: the header's own hairline is immediately overhead, and
     two of them a few pixels apart read as a mistake. */
  padding-block:clamp(22px,3.2vh,34px) 0;
}
.fw-drawer-action{
  appearance:none;
  background:none;
  border:0;
  padding:0;
  cursor:pointer;
  color:var(--accent);
  font:12px/1.6 var(--mono);
  letter-spacing:.14em;
  text-transform:uppercase;
  transition:opacity .2s var(--ease);
}
.fw-drawer-action:hover{opacity:.65}
.fw-drawer-action:focus-visible{outline:2px solid var(--accent);outline-offset:4px}

.fw-panel{padding-top:clamp(26px,4vh,44px)}
.fw-panel[hidden]{display:none}
.fw .fw-panel-title{
  margin:0;
  color:var(--accent);
  font-family:var(--sans);
  font-size:clamp(34px,3.6vw,54px);
  font-weight:300;
  line-height:1.05;
  letter-spacing:-.03em;
}
.fw .fw-panel p.fw-panel-lede{
  margin:clamp(20px,3vh,32px) 0 0;
  color:var(--ink);
  font-size:clamp(20px,1.7vw,26px);
  font-weight:300;
  line-height:1.3;
  letter-spacing:-.015em;
}
.fw .fw-panel p{margin:22px 0 0;color:var(--dim);font-size:17px;line-height:1.65}
.fw .fw-panel p.fw-panel-link{margin-top:clamp(26px,4vh,38px)}
.fw-panel-link a{
  color:var(--accent);
  font:12px/1.7 var(--mono);
  letter-spacing:.14em;
  text-transform:uppercase;
  text-decoration:none;
  border-bottom:1px solid transparent;
  padding-bottom:4px;
}
.fw-panel-link a:hover{border-color:var(--accent)}
.fw-panel-rule{
  margin:clamp(30px,5vh,52px) 0 0;
  border:0;
  border-top:1px solid var(--line-strong);
}
.fw .fw-panel p.fw-panel-label{
  margin-top:clamp(20px,3vh,30px);
  color:var(--accent);
  font:12px/1.6 var(--mono);
  letter-spacing:.14em;
  text-transform:uppercase;
}
/* ---- a stage's own markup, inside the drawer ----
   The stages were drawn as a two-column grid with the copy beside its figure.
   In a drawer that is one narrow column they stack, and everything that was
   sized against the window has to come down to the column it is now in. */
.fw .fw-panel-stage{display:block;margin-top:clamp(22px,3.2vh,36px)}
.fw .fw-panel .how-copy,
.fw .fw-panel .how-visual{max-width:none;width:auto}
/* .how-copy is sticky above 900px so the copy holds while its figure scrolls
   past. Inside the drawer's own scroller that pins it over the figure. */
.fw .fw-panel .how-copy{position:static}
.fw .fw-panel .how-visual{margin-top:clamp(26px,4vh,40px)}
.fw .fw-panel .how-eyebrow{
  display:block;
  margin:0 0 10px;
  color:var(--accent);
  font:12px/1.5 var(--mono);
  letter-spacing:.14em;
  text-transform:uppercase;
}
/* The stage headline becomes the panel's lede: it answers the title above it
   rather than opening a page of its own. */
.fw .fw-panel .how-copy h2{
  margin:0;
  font-size:clamp(20px,1.9vw,28px);
  font-weight:300;
  line-height:1.28;
  letter-spacing:-.015em;
  color:var(--ink);
  text-wrap:balance;
}
.fw .fw-panel .how-copy h3{font-size:19px;margin:22px 0 10px}

/* All supporting material is part of the reading flow. */
.fw .fw-panel .how-detail{
  margin:28px 0 0;
  border-top:1px solid var(--line);
}
.fw .fw-panel .how-detail + .how-detail{margin-top:0}
.fw .fw-panel .how-detail > .how-detail-title{
  margin:0;
  padding:24px 0 0;
  color:var(--ink);
  font-family:var(--sans);
  font-size:20px;
  font-weight:400;
  line-height:1.4;
}
.fw .fw-panel .how-detail > .how-detail-body{padding:16px 0 28px}
.fw .fw-panel .how-detail-body > :first-child{margin-top:0}
.fw .fw-panel figcaption,
.fw .fw-panel .how-example-note{font-size:13px;line-height:1.6}
.fw .fw-panel img,
.fw .fw-panel video{max-width:100%;height:auto}
/* The field photographs run one at a time. Their grid is three columns across
   a page; in a drawer that is half a window each one got a third of a half,
   and the captions set in four-word lines. The same goes for the network list.
   Both key off the window, which is the wrong measure in here. */
.fw .fw-panel .how-field-photos,
.fw .fw-panel .how-network-list{grid-template-columns:1fr;gap:clamp(26px,4vh,40px)}
.fw .fw-panel .how-field-photos figure:first-child{grid-column:auto;max-width:none}
/* Square crops, so three photographs of three different shapes read as one
   set. object-fit does it for the two that sit the right way up. */
.fw .fw-panel .how-field-photos img{
  aspect-ratio:1/1;
  object-fit:cover;
  width:100%;
  height:auto;
}
/* The 2025 frame is stored on its side and turned 90deg in place, so
   object-fit cannot reach it -- the rotation happens after the fit. Its
   wrapper does the cropping instead. The percentages are the rotation's own:
   turned a quarter, the element's CSS height becomes its drawn width, so to
   cover a square it needs height:100% and a width of the upright frame's
   765/574, which is where 133.2753% comes from. */
.fw .fw-panel .how-field-photos .how-field-rotated{aspect-ratio:1/1}
.fw .fw-panel .how-field-photos .how-field-rotated img{
  aspect-ratio:auto;
  object-fit:fill;
  width:133.2753%;
  height:100%;
}

/* The clips stay paired: stacked, each portrait frame runs taller than the
   window. */
.fw .fw-panel .how-assay-pair{gap:14px}

/* Methods stay in the same reading column as the evidence they explain. */
.fw .fw-panel .how-method-steps{
  list-style:none;
  counter-reset:method;
  margin:24px 0 0;
  padding:0;
}
.fw .fw-panel .how-method-steps li{
  counter-increment:method;
  position:relative;
  padding:20px 0 22px 38px;
  border-top:1px solid var(--line);
}
.fw .fw-panel .how-method-steps li::before{
  content:counter(method,decimal-leading-zero);
  position:absolute;
  left:0;
  top:22px;
  color:var(--accent);
  font:12px/1.5 var(--mono);
}
.fw .fw-panel .how-method-steps strong,
.fw .fw-panel .how-evidence-path strong{
  display:block;
  color:var(--ink);
  font-weight:400;
  font-size:18px;
  line-height:1.4;
}
.fw .fw-panel .how-method-steps .how-caption-label{display:block;margin-bottom:9px}
.fw .fw-panel .how-method-steps p{margin-top:8px;font-size:16px}
.fw .fw-panel .how-evidence-path{
  list-style:none;
  margin:28px 0;
  padding:0 0 0 18px;
  border-left:1px solid var(--accent);
}
.fw .fw-panel .how-evidence-path li{position:relative;padding:0 0 22px 7px}
.fw .fw-panel .how-evidence-path li:last-child{padding-bottom:0}
.fw .fw-panel .how-evidence-path li::before{
  content:"";
  position:absolute;
  width:5px;
  height:5px;
  left:-21px;
  top:10px;
  border-radius:50%;
  background:var(--accent);
}
.fw .fw-panel .how-evidence-path span{display:block;margin-top:5px;color:var(--dim);font-size:15px;line-height:1.5}

.fw-panel-media{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:16px;
  margin-top:18px;
}
.fw-panel-frame{
  aspect-ratio:4/3;
  border:1px solid var(--line);
  background:rgba(255,255,255,.03);
}

@media (max-width:900px){
  /* Stacked there is no symmetry to hold, and the wheel ends much closer to
     the band than it does on two columns, so the floor opens up a little. */
  /* Stacked, the content runs past the window anyway, so centring it only
     adds slack that iOS's viewport makes unpredictable. Start it under the
     bar and let it run. */
  .fw{
    grid-template-columns:1fr;
    gap:clamp(28px,5vh,56px);
    align-content:start;
    padding-bottom:clamp(48px,7vh,84px);
  }
  /* Stacked, both columns are the only column, and the copy leads because
     that is the order they are written in. */
  .fw-stage{grid-area:2/1}
  .fw-intro{grid-area:1/1}
  .fw-stage{padding-inline:var(--gutter-band)}
  .fw-svg{width:min(100%, calc(100vw - 2 * var(--gutter-band)), 560px)}
  .fw-intro{padding:0 var(--gutter-band);max-width:none}
  .fw-drawer{width:100vw;border-left:0}
  /* Full width, so the drawer owes its content the page's own gutter and no
     more: at 390px the generous desktop inset cost the assay clips 12px each,
     making them narrower in here than they are on the page they came from. */
  .fw-drawer-scroll{
    padding-inline:var(--gutter-band);
    padding-block:0 clamp(48px,8vh,96px);
  }
  /* The drawer is the whole window here, so the way out has to stay put: the
     bar sticks to the top of the drawer's own scroller, on the drawer's
     surface so the panel passes under it, and spans the full width by
     cancelling the scroller's gutter. Its rule moves underneath, where it now
     divides the bar from the panel rather than capping the panel. */
  .fw-drawer-bar{
    position:sticky;
    top:0;
    z-index:2;
    margin-inline:calc(-1 * var(--gutter-band));
    padding:clamp(18px,3.4vh,26px) var(--gutter-band);
    background:var(--fw-drawer-bg);
    border-top:0;
    border-bottom:1px solid var(--line-strong);
  }
}

/* Below the wheel's own breakpoint the square is narrower than the type was
   drawn for, so the labels come back up to a readable size. */
@media (max-width:720px){
  .fw{--fw-gap:calc(var(--fw-header) + clamp(14px,2.2vh,28px))}
  .fw-node-label{font-size:26px;letter-spacing:.06em}
  .fw-hub-sub{font-size:24px;letter-spacing:.1em}
  .fw-hub-label{font-size:78px}
}

/* Neutralise the clock for the whole wheel rather than naming each animated
   rule, so nothing that sets its own timing slips through. */
@media (prefers-reduced-motion:reduce){
  .fw *,.fw *::before,.fw *::after{
    animation:none !important;
    transition:none !important;
  }
  .fw-pulse{display:none}
}
