:root {
  --cream:#F7F4EE; --sand:#EDE9E1; --forest:#1E4035;
  --ink:#1A1916; --ink-mid:#5C5750; --ink-soft:#9C9690;
  --accent:#C47A3A; --accent-hov:#A1612C; --sand-text:#A0612B;
  --gold:#C8964A; --line:#DDD9D1;
  --serif:'Source Serif 4',Georgia,serif; --sans:'Inter',sans-serif;

  /* MOTION. Calm and deliberate: one gentle ease-out, three durations.
     Nothing linear, nothing that overshoots. */
  --ease:cubic-bezier(0.22,0.61,0.36,1);
  --dur-quick:200ms;
  --dur:360ms;
  --dur-slow:560ms;
  /* Drift. --ease starts at speed, which reads as a pop when several elements
     fire in sequence. This one eases in as well as out, so staggered elements
     blend into one another instead of stepping. */
  --ease-soft:cubic-bezier(0.37,0,0.28,1);
  /* Screenshots arrive slower and travel further than the copy around them, so
     they read as trailing it under their own weight. Shared by the §5 timeline
     exhibits and the §6 diagnostic shot — retune here and both follow. */
  --shot-in:2000ms;
}
*,*::before,*::after{box-sizing:border-box;}
/* <picture> is only a wrapper for the WebP source. display:contents keeps
   it out of the box tree so every existing selector and layout rule still
   sees the <img> exactly where it was before. */
picture{display:contents;}
body{margin:0;overflow-x:hidden;font-family:var(--sans);background:var(--cream);}
a{color:var(--accent);}a:hover{color:var(--accent-hov);}

/* BAND */
/* Vertical and horizontal band padding interpolate between the design's
   mobile (64/24) and desktop (96/80) values instead of jumping at 768px. */
.band{padding:clamp(64px,53.333px + 2.963vw,96px) clamp(24px,5.333px + 5.185vw,80px);position:relative;}
.band--cream{background:var(--cream);}
.band--sand{background:var(--sand);}
.band--forest{background:var(--forest);color:var(--cream);}
.band__inner{margin:0 auto;width:100%;}
.w-wide{max-width:1100px;}
.w-reading{max-width:760px;}
.w-narrow{max-width:600px;}

/* SECTION HEAD */
.eyebrow{display:block;font-family:var(--sans);font-size:clamp(12px,11.667px + 0.093vw,13px);font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--eyebrow-color,var(--sand-text));margin-bottom:24px;}
.title{font-family:var(--serif);font-weight:400;line-height:1.1;letter-spacing:-.01em;color:var(--ink);text-wrap:pretty;margin:0 0 24px;}
h1.title{font-size:clamp(42px,33.333px + 2.407vw,68px);}
h2.title{font-size:clamp(32px,28px + 1.111vw,44px);}
.title b{color:var(--accent);font-weight:400;}
.standfirst{font-family:var(--serif);font-size:clamp(17px,16px + 0.278vw,20px);line-height:1.5;color:var(--ink-mid);margin:0 0 40px;max-width:480px;}
.standfirst b{color:var(--accent-hov);font-style:italic;}

/* BUTTONS */
.btn{display:inline-flex;align-items:center;font-family:var(--sans);font-size:15px;font-weight:600;padding:14px 28px;min-height:44px;background:var(--accent);color:#fff;border-radius:6px;text-decoration:none;transition:background var(--dur) var(--ease),transform var(--dur) var(--ease),border-color var(--dur) var(--ease);}
.btn:hover,.btn:focus{background:var(--accent-hov);color:#fff;}
/* Subtle lift. Same colours as the approved design, just eased in. */
.btn:hover,.btn:focus-visible{transform:translateY(-1px);}
.btn:active{transform:translateY(0);}
.fineprint{font-family:var(--sans);font-size:clamp(12px,11.667px + 0.093vw,13px);color:var(--ink-soft);margin:16px 0 0;}

/* SPLIT */
.split{display:grid;grid-template-columns:55fr 45fr;gap:72px;align-items:center;}
.photo-frame{aspect-ratio:3/4;border:1px solid var(--line);border-radius:4px;overflow:hidden;background:var(--sand);}
.photo-frame img{width:100%;height:100%;object-fit:cover;object-position:top center;display:block;}
.caption{font-family:var(--sans);font-size:clamp(11.5px,11.333px + 0.046vw,12px);color:var(--ink-mid);margin:8px 0 0;line-height:1.5;}

/* TIMELINE §5 */
.tl{position:relative;max-width:880px;margin:0 auto;padding:0 clamp(24px,18.667px + 1.481vw,40px) clamp(60px,53.333px + 1.852vw,80px);}
.tl::before{content:"";position:absolute;left:66px;top:12px;bottom:90px;width:2px;background:var(--line);}
.tl-step{position:relative;display:grid;grid-template-columns:54px 1fr;gap:30px;padding-bottom:52px;}
/* Scroll reveal. Only ever applied once JS has added .js to the timeline,
   so the no-JS and reduced-motion default is fully visible.

   The step used to arrive as one block. It now ripples internally, the same
   way the §4 steps do: the node leads and the copy follows 90ms behind it,
   over an entrance many times that gap, so the text is always in flight
   together and drifts rather than ticks.

   The screenshot is deliberately out of step with the copy. It starts well
   after the text has committed, travels further and takes half as long again
   to arrive, so it settles a full second after the words have. Reading order
   is text first; the image should feel like it is catching up to a step that
   is already made its point, not competing with it for the same beat.

   Unlike §4 this cannot run off one trigger — the timeline is far taller than
   the viewport, so each step keeps its own observer and ripples as it arrives.
   Delays come from --n, set by position, so the rule does not care that the
   last step has a sixth child the others lack. */
.tl.js{--tl-in:1300ms;--tl-lag:90ms;--tl-img-in:var(--shot-in);--tl-img-delay:700ms;}
.tl.js .tl-step > .tl-node,
.tl.js .tl-step > div:not(.tl-node) > *{opacity:0;}
@keyframes tl-node-in{
  0%{opacity:0;transform:translateY(16px) scale(0.94);}
  100%{opacity:1;transform:none;}
}
@keyframes tl-copy-in{
  0%{opacity:0;transform:translateY(14px);}
  100%{opacity:1;transform:none;}
}
/* Further travel than the copy, so the lag reads as weight rather than as a
   delay someone dialled in. */
@keyframes tl-img-in{
  0%{opacity:0;transform:translateY(24px);}
  100%{opacity:1;transform:none;}
}
.tl.js .tl-step.in > .tl-node{animation:tl-node-in var(--tl-in) var(--ease-soft) both;}
.tl.js .tl-step.in > div:not(.tl-node) > *{
  animation:tl-copy-in var(--tl-in) var(--ease-soft) both;
  animation-delay:calc(var(--n,1) * var(--tl-lag));
}
/* Matched by class, not by index: the exhibit is the fifth child in four steps
   and the fifth and sixth in the last one. */
.tl.js .tl-step.in > div:not(.tl-node) > .tl-exhibit,
.tl.js .tl-step.in > div:not(.tl-node) > .tl-learn-mob{
  animation-name:tl-img-in;
  animation-duration:var(--tl-img-in);
  animation-delay:var(--tl-img-delay);
}
.tl.js .tl-step > div:not(.tl-node) > *:nth-child(1){--n:1;}
.tl.js .tl-step > div:not(.tl-node) > *:nth-child(2){--n:2;}
.tl.js .tl-step > div:not(.tl-node) > *:nth-child(3){--n:3;}
.tl.js .tl-step > div:not(.tl-node) > *:nth-child(4){--n:4;}
.tl.js .tl-step > div:not(.tl-node) > *:nth-child(5){--n:5;}
.tl.js .tl-step > div:not(.tl-node) > *:nth-child(6){--n:6;}
.tl-node{width:54px;height:54px;border-radius:50%;background:var(--cream);border:1.5px solid var(--line);display:flex;align-items:center;justify-content:center;transition:border-color var(--tl-in,var(--dur-slow)) var(--ease-soft);z-index:1;flex-shrink:0;}
.tl-node svg{width:26px;height:26px;stroke:var(--sand-text);}
/* The rim warms to terracotta over the same span the node takes to arrive, so
   the colour blooms with the step rather than snapping after it. */
.tl-step.in .tl-node{border-color:var(--accent);}
.tl-eyb{font-size:12px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;color:var(--sand-text);margin:6px 0 5px;}
.tl-ti{font-family:var(--serif);font-size:26px;line-height:1.08;color:var(--ink);margin:0 0 8px;}
.tl-desc{font-size:16px;line-height:1.5;color:var(--ink-mid);margin:0 0 6px;max-width:560px;}
.tl-tag{font-size:13px;color:var(--ink-soft);margin:0;}

/* TL EXHIBIT — tap/click to zoom */
/* height:auto is load-bearing. The <img> tags carry width/height attributes
   so the browser can reserve space before the image lands; without an explicit
   CSS height those attributes act as presentational hints and pin the element
   to its full intrinsic pixel height. */
.tl-exhibit{margin:24px 0 0;overflow:visible;position:relative;}
.tl-exhibit__trigger{display:inline-block;padding:0;border:0;background:none;cursor:zoom-in;border-radius:12px;}
.tl-exhibit__trigger:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:12px;}
.tl-exhibit__img{display:block;max-width:600px;width:100%;height:auto;border-radius:12px;transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--ease);}
/* Grow on hover and on keyboard focus, so pointer and keyboard match. */
.tl-exhibit__trigger:hover .tl-exhibit__img,
.tl-exhibit__trigger:focus-visible .tl-exhibit__img{transform:scale(1.03);box-shadow:0 8px 28px rgba(0,0,0,.12);}
.tl-exhibit__img--framed{border:1px solid var(--line);}
.tl-learn-mob{display:none;}
.tl-exhibit__duo{display:flex;gap:12px;align-items:flex-start;overflow:visible;}
.tl-exhibit__duo .tl-exhibit__trigger{width:calc(50% - 6px);flex-shrink:0;}
.tl-exhibit__duo .tl-exhibit__trigger .tl-exhibit__img{width:100%;max-width:none;}
/* LIGHTBOX */
.lbx{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(26,25,22,.88);opacity:0;transition:opacity var(--dur-slow) var(--ease);}
.lbx.is-open{opacity:1;}
.lbx[hidden]{display:none;}
.lbx__img{max-width:min(1100px,92vw);max-height:90vh;width:auto;height:auto;border-radius:12px;box-shadow:0 20px 60px rgba(0,0,0,.45);transform:scale(.97);transition:transform var(--dur-slow) var(--ease);will-change:transform;}
.lbx.is-open .lbx__img{transform:none;}
.lbx__close{position:absolute;top:16px;right:20px;width:44px;height:44px;border:0;border-radius:50%;background:var(--cream);color:var(--forest);font-size:26px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;}
.lbx__close:focus-visible{outline:2px solid var(--cream);outline-offset:2px;}
/* SITE NAV */
/* The nav shares the band's box model exactly: gutter on the outer element,
   then a 1100px cap on the inner, so the logo lines up with the hero eyebrow
   and the actions line up with the hero image's right edge at every width. */
.site-nav{background:var(--cream);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:100;padding-left:clamp(24px,5.333px + 5.185vw,80px);padding-right:clamp(24px,5.333px + 5.185vw,80px);}
.site-nav__inner{max-width:1100px;margin:0 auto;padding:0;height:72px;display:flex;align-items:center;justify-content:space-between;gap:16px;}
.site-nav__logo img{height:34px;display:block;}
.site-nav__actions{display:flex;align-items:center;gap:12px;min-width:0;}
.site-nav__logo{flex-shrink:0;}
.btn--primary{background:var(--forest)!important;color:var(--cream)!important;}
.btn--primary:hover,.btn--primary:focus{background:#163329!important;color:var(--cream)!important;}
.btn--ghost{background:transparent!important;color:var(--forest)!important;border:1px solid var(--line)!important;}
.btn--ghost:hover,.btn--ghost:focus{border-color:var(--forest)!important;color:var(--forest)!important;background:transparent!important;}
/* SITE FOOTER */
.site-footer{background:#163329;}
.site-footer__in{max-width:1200px;margin:0 auto;padding:clamp(32px,21.333px + 2.963vw,64px) clamp(24px,13.333px + 2.963vw,56px) 0;}
.site-footer__grid{display:flex;justify-content:space-between;gap:48px;flex-wrap:wrap;}
/* EXPERIMENT (revert this commit to restore the wordmark).
   The footer mark is the monogram glyph, sized by HEIGHT rather than width.
   The wordmark it replaces was width-driven at 190px, which on its 3.265
   ratio rendered 58px tall; pinning that same 58px keeps the footer's
   vertical rhythm and the 18px gap below it identical. The monogram is a
   tall glyph, so it is much narrower here - that is expected. */
.ft-wm{height:58px;width:auto;display:block;margin-bottom:18px;}
.ft-tag{margin:0 0 22px;font-size:15px;color:#B7C4BD;font-family:var(--sans);}
.ft-soc{display:flex;gap:12px;}
.ft-soc a{color:#C7D3CD;display:inline-flex;width:40px;height:40px;align-items:center;justify-content:center;border:1px solid #2C4E43;border-radius:8px;text-decoration:none;transition:color 150ms,border-color 150ms;}
.ft-soc a:hover{color:#C8964A;border-color:#C8964A;}
.ft-cols{flex:1;min-height:1px;}
.ft-sign{max-width:300px;}
.ft-sign-head{font-family:var(--sans);font-size:15px;font-weight:600;color:#F7F4EE;margin:4px 0 8px;}
.ft-sign p{font-size:13px;color:#9FB1A9;margin:0 0 14px;line-height:1.5;font-family:var(--sans);}
.ft-form{display:flex;gap:8px;}
.ft-form input{flex:1;min-width:0;height:44px;border:1px solid #2C4E43;border-radius:6px;background:#F7F4EE;color:#1A1916;padding:0 12px;font-size:14px;font-family:var(--sans);}
.ft-form input:focus-visible{outline:2px solid #F7F4EE;outline-offset:2px;}
.ft-form button{height:44px;padding:0 18px;border:0;border-radius:6px;background:#C8964A;color:#3A2A12;font-weight:600;font-size:14px;cursor:pointer;font-family:var(--sans);transition:background 150ms;}
.ft-form button:hover{background:#D5A659;}
.ft-form button:focus-visible{outline:2px solid #F7F4EE;outline-offset:2px;}
.ft-rule{height:1px;background:#C8964A;opacity:.7;margin:56px 0 0;}
.ft-bottom{text-align:center;padding:14px 0 20px;}
.ft-legal{display:flex;gap:26px;justify-content:center;align-items:center;margin-bottom:8px;}
.ft-legal a{font-size:13px;color:#C7D3CD;text-decoration:none;transition:color 150ms;}
.ft-legal a:hover{color:#F7F4EE;}
.ft-co{margin:0;font-size:12.5px;color:#7E938A;font-family:var(--sans);}
.ft-addr{margin:4px 0 0;font-size:12.5px;color:#7E938A;font-family:var(--sans);}
/* FOCUS RINGS */
a:focus-visible,button:focus-visible{outline:2px solid var(--forest);outline-offset:2px;border-radius:inherit;}

/* HERO ENTRANCE. Runs once on load. --hero-step is the gap between elements;
   raise it for a slower sequence, lower it to get the CTA on screen sooner. */
:root{--hero-step:240ms;}
.anim #s1 .eyebrow,
.anim #s1 .title,
.anim #s1 .standfirst,
.anim #s1 .btn,
.anim #s1 .fineprint,
.anim #s1 .split > div + div{
  opacity:0;transform:translateY(14px);
  transition:opacity var(--dur-slow) var(--ease),transform var(--dur-slow) var(--ease);
}
.anim.hero-in #s1 .eyebrow,
.anim.hero-in #s1 .title,
.anim.hero-in #s1 .standfirst,
.anim.hero-in #s1 .btn,
.anim.hero-in #s1 .fineprint,
.anim.hero-in #s1 .split > div + div{opacity:1;transform:none;}
.anim #s1 .eyebrow{transition-delay:0ms;}
.anim #s1 .title{transition-delay:var(--hero-step);}
.anim #s1 .standfirst{transition-delay:calc(var(--hero-step) * 2);}
.anim #s1 .btn{transition-delay:calc(var(--hero-step) * 3);}
.anim #s1 .fineprint{transition-delay:calc(var(--hero-step) * 3.5);}
/* The image column settles alongside the copy rather than after it. */
.anim #s1 .split > div + div{transition-delay:calc(var(--hero-step) * 1.5);}

/* BAND REVEAL. Same calm fade-rise as the section 5 steps, one per band.
   .band-reveal is added by JS right before the observer attaches, so a browser
   that never runs the script keeps every band visible. */
.band-reveal{opacity:0;transform:translateY(18px);
  transition:opacity var(--dur-slow) var(--ease),transform var(--dur-slow) var(--ease);}
.band-reveal.in{opacity:1;transform:none;}

/* LOOP DRAW. Each SVG child fades in on a delay derived from its position along
   the loop, so the diagram builds in reading order instead of all at once.
   Delays are written inline by JS once the diagram is actually on screen. */
.loop-draw > *{opacity:0;transition:opacity var(--dur-slow) var(--ease);}
.loop-draw.in > *{opacity:1;}

/* §7 STEP NUMBERS */
.step-num{font-family:var(--serif);font-size:clamp(36px,30.667px + 1.481vw,52px);font-weight:400;line-height:1;display:block;padding-right:12px;color:var(--accent);background:var(--cream);}

/* §2 BROKEN LOOP */
.bl-desk-wrap{display:block;margin:64px 0 0;}
.bl-mob-wrap{display:none;max-width:280px;margin:48px auto 40px;}

/* FLOW DIAGRAM SEQUENCE — §2 the broken loop, §8 the Fern & Field loop.
   One component, two usages. The nodes ripple in along the diagram, then each
   arrow draws into the next node and that node pulses as the arrow lands, and
   a return arrow closes the loop. Plays once, on first sight.

   §8 adds two parts §2 has no use for: a .flow-trail, the dotted re-score line,
   which fades in after the loop has closed rather than drawing like the arrows,
   and a .flow-final that arrives after everything else has settled.

   Everything below hangs off .flow-seq, which JS adds only when motion is allowed
   and the observer is about to attach. Without JS, or under reduced motion, the
   diagram is simply already there — nothing is hidden in the first place.

   The two durations live here rather than in :root because they are longer than
   anything else on the site — this sequence drifts where the rest of the page
   settles. The JS constants mirror them; change both together. */
.flow-seq{--flow-entrance:1000ms;--flow-draw:820ms;}

.flow-seq .flow-node{
  opacity:0;transform:translateY(11px);
  transform-box:fill-box;transform-origin:50% 50%;
  transition:opacity var(--flow-entrance) var(--ease-soft),transform var(--flow-entrance) var(--ease-soft);
}
.flow-seq .flow-node.is-in{opacity:1;transform:none;}

/* Pulse is scale only, peaking dead centre on a sine-like curve so it swells and
   recedes at the same rate — a breath, not a beat. The gold "Nothing learned"
   node goes further and picks up a soft glow; it is the point of the section. */
@keyframes flow-pulse{
  0%{transform:scale(1);} 50%{transform:scale(1.05);} 100%{transform:scale(1);}
}
@keyframes flow-pulse-accent{
  0%{transform:scale(1);filter:drop-shadow(0 0 0 rgba(200,150,74,0));}
  50%{transform:scale(1.09);filter:drop-shadow(0 0 8px rgba(200,150,74,0.5));}
  100%{transform:scale(1);filter:drop-shadow(0 0 0 rgba(200,150,74,0));}
}
.flow-seq .flow-node.is-pulse{animation:flow-pulse 1000ms var(--ease-soft) both;}
.flow-seq .flow-node--accent.is-pulse{animation:flow-pulse-accent 1180ms var(--ease-soft) both;}

/* Arrows draw source to target. --flow-len is the measured path length, written
   inline by JS once the SVG is on screen and actually has a layout box. */
/* The fallback keeps the arrows hidden in the frame between the class landing
   and JS writing the measured length — without it they would flash on. */
.flow-seq .flow-arrow__line{stroke-dasharray:var(--flow-len,9999);stroke-dashoffset:var(--flow-len,9999);}
.flow-seq .flow-arrow__head{opacity:0;}
/* Eased in as well as out: the line creeps away from its node and glides to a
   stop at the next one, rather than shooting off at full speed. */
.flow-seq .flow-arrow.is-drawn .flow-arrow__line{
  stroke-dashoffset:0;transition:stroke-dashoffset var(--flow-draw) var(--ease-soft);
}
/* The head resolves as the line arrives, not before. */
.flow-seq .flow-arrow.is-drawn .flow-arrow__head{
  opacity:1;transition:opacity var(--dur) var(--ease-soft) calc(var(--flow-draw) * 0.62);
}
/* The return arrow travels roughly eight times the distance of a single hop and
   is the beat the section rests on — the loop closing on itself. It takes its
   time, slower per pixel than the hops rather than merely longer. */
.flow-seq .flow-arrow--return.is-drawn .flow-arrow__line{
  transition-duration:calc(var(--flow-draw) * 2.6);
}
.flow-seq .flow-arrow--return.is-drawn .flow-arrow__head{
  transition-delay:calc(var(--flow-draw) * 2.2);
}

/* THE RE-SCORE TRAIL (§8 only).
   This one fades; it does not draw. Two reasons, and the first is structural:
   the draw effect works by setting stroke-dasharray to the path length, which
   is the same property that makes this line dotted — animating the draw would
   overwrite "4 3" and silently render it solid.

   The second is emphasis. A line that draws pulls the eye and claims the beat.
   The re-score cycle is an aside to the loop, not a step in it, so it settles
   in quietly after the terracotta return arrow has closed the loop. Its own
   parts are namespaced so the .flow-arrow draw rules cannot reach them. */
.flow-seq .flow-trail,
.flow-seq .flow-trail__label{opacity:0;}
.flow-seq .flow-trail.is-in{
  opacity:1;transition:opacity var(--flow-entrance) var(--ease-soft);
}
.flow-seq .flow-trail__label.is-in{
  opacity:1;transition:opacity var(--dur-slow) var(--ease-soft);
}

/* The closing line, after everything else has settled. */
.flow-seq .flow-final{opacity:0;transform:translateY(8px);}
.flow-seq .flow-final.is-in{
  opacity:1;transform:none;
  transition:opacity var(--flow-entrance) var(--ease-soft),transform var(--flow-entrance) var(--ease-soft);
}

/* §3 WHO IT'S FOR — TRIANGLE.
   The three role panels arrive one at a time, then the centre "You" fills in
   underneath them: the roles converge on the reader. Plays once, on first
   sight, and stops there.

   Same shape as the §2 sequence — hidden only under .wf-seq, which JS adds when
   motion is allowed, so no-JS and reduced motion both get the finished diagram.

   Entrance and settle are one keyframe rather than a transition plus a separate
   pulse: a single animation owns transform throughout, so the rise flows into
   the swell instead of the two fighting over the same property. */
.wf-seq{--wf-entrance:1900ms;--wf-center:3500ms;}
.wf-seq .wf-panel,.wf-seq .wf-center{
  opacity:0;transform-box:fill-box;transform-origin:50% 50%;
}
/* Rise and fade in, swell to a gentle peak, settle. Never dips back below its
   resting size, so it reads as a breath rather than a spring.

   Two things about the peak keyframe. Its scale is small because the gutter
   between panels is only ~16 units: the top panel is 330 tall, so even 1.04
   grew it 13 and the panels visibly closed on each other at the top of the
   swell. And it carries its own easing, because a timing function applies to
   every keyframe segment — with an ease-in curve the settle hesitated at the
   peak before releasing, which read as a hitch at the end. Ease-out leaves the
   peak immediately and decelerates into rest. */
@keyframes wf-panel-in{
  0%{opacity:0;transform:translateY(13px) scale(0.985);}
  45%{opacity:1;}
  58%{transform:translateY(0) scale(1.02);animation-timing-function:var(--ease);}
  100%{opacity:1;transform:none;}
}
/* The centre goes further — it is the point the three roles are converging on.
   No rise: it grows in place, out of the middle of the triangle. Same ceiling
   applies: at 1.08 it grew 12 into a 16 gap and all but touched its neighbours,
   and it paints over them, so the collision showed. */
@keyframes wf-center-in{
  0%{opacity:0;transform:scale(0.94);}
  45%{opacity:1;}
  58%{transform:scale(1.05);animation-timing-function:var(--ease);}
  100%{opacity:1;transform:scale(1);}
}
/* The terracotta saturates a little behind the shape, so the panel reads as
   filling in rather than simply appearing. */
@keyframes wf-fill-in{0%{fill-opacity:0;} 100%{fill-opacity:1;}}
.wf-seq .wf-panel.is-in{animation:wf-panel-in var(--wf-entrance) var(--ease-soft) both;}
.wf-seq .wf-center.is-in{animation:wf-center-in var(--wf-center) var(--ease-soft) both;}
.wf-seq .wf-center.is-in .wf-center__fill{
  animation:wf-fill-in calc(var(--wf-center) * 0.75) var(--ease-soft) both;
}

/* NUMBERED ROW BUILD — §4 the system way, §7 getting started.
   One component, two usages. Rows arrive in order, each number leading its own
   copy in by a beat. The point is that it reads as one continuous drift rather
   than separate lines: the entrance is far longer than the gap between rows, so
   several elements are always in flight at once and the wave never lands on a
   single row. Widening --row-step or shortening --row-in is what breaks that.

   Delays come from --i, written inline on each row, so the whole sequence is
   CSS and every element shares one clock — setTimeout per element would let
   them drift apart under load. Inline rather than nth-of-type because §7's
   rows sit alongside an absolutely positioned rule element; counting siblings
   would silently offset the whole sequence by one.

   Hidden only under .row-seq, added by JS when motion is allowed, so no-JS and
   reduced motion both get the finished list. */
.row-seq{--row-step:340ms;--row-in:1600ms;--row-lag:240ms;}
.row-seq .sw-num,.row-seq .sw-copy,
.row-seq .step-num,.row-seq .gs-copy{opacity:0;}

/* The number drifts up and forward a touch — it leads, so it gets the small
   scale. The copy only rises and fades: scaling live text softens the glyphs
   for the whole of a 1.6s entrance, which is exactly where it would show. */
@keyframes row-num-in{
  0%{opacity:0;transform:translateY(12px) scale(0.97);}
  100%{opacity:1;transform:none;}
}
@keyframes row-copy-in{
  0%{opacity:0;transform:translateY(10px);}
  100%{opacity:1;transform:none;}
}
.row-seq.is-in .sw-num,
.row-seq.is-in .step-num{
  animation:row-num-in var(--row-in) var(--ease-soft) both;
  animation-delay:calc(var(--i) * var(--row-step));
}
.row-seq.is-in .sw-copy,
.row-seq.is-in .gs-copy{
  animation:row-copy-in var(--row-in) var(--ease-soft) both;
  animation-delay:calc(var(--i) * var(--row-step) + var(--row-lag));
}

/* STANDALONE SCREENSHOT ARRIVAL.
   Deliberately reuses the §5 exhibit keyframe, duration and curve rather than
   restating them, so every screenshot on the page arrives the same way: the
   same 24px of travel over the same 2000ms. If the timeline exhibits are
   retuned, this follows them.

   The caption trails into that arrival and lands with it — a caption sitting
   under an image that has not appeared yet reads as orphaned. */
.shot-lag.shot-seq > picture > img,
.shot-lag.shot-seq > .caption{opacity:0;}
.shot-lag.shot-seq.is-in > picture > img{
  animation:tl-img-in var(--shot-in) var(--ease-soft) both;
}
.shot-lag.shot-seq.is-in > .caption{
  animation:tl-copy-in 1300ms var(--ease-soft) 700ms both;
}

/* §8 LOOP DIAGRAM */
.loop-h{display:block;}
.loop-h svg{display:block;width:100%;height:auto;}
.loop-v{display:none;text-align:center;}
.loop-v svg{display:block;width:100%;max-width:244px;height:auto;margin:0 auto;}
.loop-caption{text-align:center;font-size:12.5px;font-weight:600;color:#6B655C;margin-top:6px;}

/* §4 GRID */
.s4-grid{display:grid;grid-template-columns:.82fr 1.18fr;gap:26px;align-items:start;}

/* §9 FOUNDER */
.founder-grid{display:grid;grid-template-columns:3fr 2fr;gap:80px;align-items:start;}

/* §10 PROOF CARDS */
.proof-cards{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:56px;align-items:stretch;}
.proof-card{background:var(--cream);border-radius:4px;padding:40px 36px 36px;display:flex;flex-direction:column;min-height:600px;}
.proof-card__qm{font-family:var(--serif);font-size:128px;color:var(--sand-text);line-height:.72;margin:0 0 24px -6px;user-select:none;}
.proof-card__body{font-family:var(--serif);font-size:24px;font-weight:400;line-height:1.45;color:var(--ink);margin:0;}
.proof-card__spacer{flex:1;min-height:64px;}
.proof-card__attr{margin-top:auto;padding-top:20px;border-top:1px solid var(--line);}
.proof-card__tool{font-family:var(--sans);font-size:10px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-soft);margin:0 0 6px;}
.proof-card__name{font-family:var(--sans);font-size:13px;color:var(--ink-mid);margin:0;line-height:1.45;}

/* §12 FAQ */
.faq-list{border-top:1px solid var(--line);}
.faq-item{border-bottom:1px solid var(--line);}
.faq-btn{display:flex;align-items:center;justify-content:space-between;width:100%;padding:18px 0;background:none;border:none;cursor:pointer;text-align:left;min-height:44px;font-family:var(--sans);font-size:17px;font-weight:600;color:var(--ink);line-height:1.3;}
/* Answers are open by default so they are readable with JavaScript off.
   The .js class on <html> is what collapses them, which is the only state
   a scripted browser ever sees. Height is animated from a measured value in
   js/site.js. padding-bottom animates alongside it: under box-sizing:border-box
   a box cannot shrink below its own padding, so height:0 alone would leave an
   18px stub behind every closed answer. */
.faq-answer{display:block;padding:0 0 18px;font-family:var(--sans);font-size:16px;color:var(--ink-mid);line-height:1.65;}
.js .faq-answer{height:0;padding-bottom:0;overflow:hidden;opacity:0;
  transition:height var(--dur) var(--ease),padding-bottom var(--dur) var(--ease),opacity var(--dur) var(--ease);}
.js .faq-answer.is-open{padding-bottom:18px;opacity:1;}
[data-faq-chevron]{transition:transform var(--dur) var(--ease);}

#sticky-cta{transform:translateY(100%);transition:transform var(--dur) var(--ease);}

@media(max-width:768px){
  .split,.founder-grid{grid-template-columns:1fr;gap:32px;}
  .bl-desk-wrap{display:none;}.bl-mob-wrap{display:block;}
  .loop-h{display:none;}.loop-v{display:block;}
  .tl::before{left:38px;}
  .tl-step{grid-template-columns:38px 1fr;gap:18px;}
  .tl-node{width:38px;height:38px;}
  .tl-node svg{width:18px;height:18px;}
  .tl-exhibit__img{max-width:100%!important;}
  .tl-exhibit__duo{flex-direction:column;gap:12px;}
  .tl-exhibit__duo .tl-exhibit__trigger{width:100%!important;}
  .tl-learn-desk{display:none!important;}
  .tl-learn-mob{display:flex;flex-direction:column;gap:18px;margin:24px 0 0;}
  .site-nav__actions .btn--ghost .nav-ghost-long{display:none;}
  .site-nav__actions .btn--ghost .nav-ghost-short{display:inline;}
  .site-footer__grid{flex-direction:column;}
  .ft-sign{max-width:100%;}
  .ft-cols{display:none;}
  .s4-grid{grid-template-columns:1fr!important;}
  .proof-cards{grid-template-columns:1fr!important;}
  .s5-head{padding:0 24px 32px!important;}
  .s9-photo-col{display:flex!important;flex-direction:column!important;align-items:flex-start!important;}
  .s9-photo-wrap{width:80px!important;aspect-ratio:4/5!important;margin-top:12px!important;}
}
@media(min-width:769px){#sticky-cta{display:none!important;}}
@media(min-width:769px){
  .site-nav__actions .btn--ghost .nav-ghost-short{display:none;}
  .site-nav__actions .btn--ghost .nav-ghost-long{display:inline;}
}
@media(prefers-reduced-motion:reduce){
  /* Everything visible, nothing moves. The accordion and lightbox still
     work, they just change state instantly. */
  .tl.js .tl-step{opacity:1!important;transform:none!important;transition:none!important;}
  .loop-draw > *{opacity:1!important;transition:none!important;transition-delay:0ms!important;}
  .band-reveal{opacity:1!important;transform:none!important;transition:none!important;}
  .anim #s1 .eyebrow,.anim #s1 .title,.anim #s1 .standfirst,
  .anim #s1 .btn,.anim #s1 .fineprint,.anim #s1 .split > div + div{
    opacity:1!important;transform:none!important;transition:none!important;transition-delay:0ms!important;}
  .tl-exhibit__img{transition:none!important;}
  .tl-exhibit__trigger:hover .tl-exhibit__img,
  .tl-exhibit__trigger:focus-visible .tl-exhibit__img{transform:none!important;}
  .btn:hover,.btn:focus-visible,.btn:active{transform:none!important;}
  .lbx{opacity:1;transition:none!important;}
  .lbx__img{transform:none!important;transition:none!important;will-change:auto;}
  *,*::before,*::after{animation-duration:.001s!important;transition-duration:.001s!important;scroll-behavior:auto!important;}
}

/* The export marked the two forest CTA buttons with a style-hover
   attribute that only the design tool's runtime applied. Reproduced here
   as a real CSS rule so the hover survives the port. */
.btn[style-hover]:hover,.btn[style-hover]:focus{background:#163329;}

/* LEGAL PAGES.
   .list-terms lays out a fixed label column plus a 1fr value column. A long
   unbreakable value (support@siebertcreative.com) sets a min-content floor that
   the 1fr track cannot go below, which pushed /terms and /privacy about 38px
   wider than a 360px screen. min-width:0 lets the track shrink; the wrap rule
   is the backstop. Below 480px the pair stacks, which reads better than
   breaking an email address mid-string. */
.legal-doc .list-terms li{min-width:0;}
.legal-doc .list-terms .term,
.legal-doc .list-terms .detail{min-width:0;overflow-wrap:anywhere;}
@media(max-width:479px){
  .legal-doc .list-terms li{grid-template-columns:1fr;gap:4px;}
}

/* MOBILE NAV OVERFLOW.
   At phone widths the nav cannot hold the logo plus both CTAs: at 390px it
   needs 502px of content in 342px of space, which is the whole ~526px document
   overflow. Shrinking type and padding cannot recover 160px, so below 600px the
   primary CTA drops out of the nav. It is not lost: the hero carries the same
   button at the top of the page, and #sticky-cta carries it from the moment the
   hero scrolls away. Both are part of the approved design. */
@media(max-width:599px){
  .site-nav__actions .btn--primary{display:none;}
}

/* ============================================================
   MEMBER HUB (/hub)
   Layered on the shared tokens, .band/.band__inner/.w-wide and the
   .loop-h/.loop-v pair above — the hub adds no new layout primitives.
   The design export shipped its own copies of those; they are dropped
   here so the hub and the sales page stay on one container system.
   ============================================================ */

/* MEMBER NAV.
   Deliberately distinct from .site-nav: no CTAs, shorter bar, text links
   instead of buttons. Members are already sold; this is wayfinding. */
.m-nav{background:var(--cream);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:100;padding-left:clamp(24px,5.333px + 5.185vw,80px);padding-right:clamp(24px,5.333px + 5.185vw,80px);}
.m-nav__in{max-width:1100px;margin:0 auto;height:64px;display:flex;align-items:center;gap:24px;}
.m-nav__brand{display:flex;align-items:center;gap:10px;text-decoration:none;flex-shrink:0;}
.m-nav__logo{height:28px;display:block;}
/* Marks the hub as the members' side of the site, sitting against the same
   logo the marketing pages use. Desktop only: the mobile bar drops it at 768px
   to keep the brand lockup from crowding the links. Ported from the design
   export as-is. */
.m-nav__badge{font-family:var(--sans);font-size:11px;font-weight:500;letter-spacing:.05em;color:var(--ink-soft);border:1px solid var(--line);border-radius:3px;padding:2px 7px;}
.m-nav__links{display:flex;gap:2px;margin-left:auto;}
.m-nav__link{font-family:var(--sans);font-size:14px;font-weight:500;color:var(--ink-mid);text-decoration:none;padding:0 14px;border-radius:4px;min-height:44px;display:inline-flex;align-items:center;transition:color var(--dur-quick) var(--ease),background var(--dur-quick) var(--ease);}
.m-nav__link:hover{color:var(--ink);background:rgba(0,0,0,.04);}
.m-nav__link.active{color:var(--forest);font-weight:600;}

/* HUB HERO */
.hub-hero__grid{display:grid;grid-template-columns:1fr 1fr;gap:48px;align-items:start;}
.hero-h1{font-family:var(--serif);font-size:clamp(44px,5.5vw,68px);font-weight:400;color:var(--ink);margin:0 0 16px;line-height:1.05;}
.hero-sub{font-family:var(--sans);font-size:clamp(16px,1.8vw,18px);line-height:1.6;color:var(--ink-mid);margin:0 0 28px;max-width:520px;}
.hero-aside{margin-top:32px;padding:20px 24px;background:var(--sand);border-left:3px solid var(--line);border-radius:0 4px 4px 0;max-width:520px;}
.hero-aside p{font-family:var(--sans);font-size:14px;line-height:1.6;color:var(--ink-mid);margin:0;}

/* TOOL CARDS */
.tools-note{font-family:var(--sans);font-size:14px;color:var(--ink-mid);margin:0 0 16px;}
.tools-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:22px;}
.tool-card{background:#fff;border:1px solid var(--line);border-radius:14px;padding:26px 26px 24px;display:flex;flex-direction:column;transition:transform var(--dur-quick) var(--ease),box-shadow var(--dur-quick) var(--ease),border-color var(--dur-quick) var(--ease);}
.tool-card:hover{transform:translateY(-4px);box-shadow:0 14px 34px rgba(26,25,22,.11);border-color:#C9C3B8;}
.tool-card__head{display:flex;align-items:center;gap:14px;margin-bottom:14px;}
.tool-card__ico{flex:0 0 50px;width:50px;height:50px;border-radius:12px;background:#F1E7D8;border:1px solid #E7DBC4;display:flex;align-items:center;justify-content:center;transition:border-color var(--dur-quick) var(--ease);}
.tool-card__ico svg{width:25px;height:25px;display:block;}
.tool-card:hover .tool-card__ico{border-color:var(--accent);}
.tool-card__titles{display:flex;flex-direction:column;}
.tool-card__eyb{font-family:var(--sans);font-size:12px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;color:var(--sand-text);margin-bottom:3px;}
.tool-card__name{font-family:var(--serif);font-weight:600;font-size:26px;line-height:1.05;margin:0;color:var(--ink);}
.tool-card__job{font-family:var(--sans);font-size:19px;line-height:1.45;color:var(--ink-mid);margin:0 0 18px;}
.tool-card__meta{margin:0 0 24px;padding-top:16px;border-top:1px solid var(--accent);display:flex;flex-direction:column;gap:11px;}
.tool-card__meta-div{display:flex;gap:14px;font-family:var(--sans);font-size:16px;line-height:1.45;}
.tool-card__meta-dt{flex:0 0 84px;font-weight:600;color:var(--ink);}
.tool-card__meta-dd{color:var(--ink-soft);}
/* Per-card key note. Only the Learning Loop carries one — it is a Sheet
   copy link, not a licensed web tool, so the band-level note does not apply. */
.tool-card__key{font-family:var(--sans);font-size:13px;line-height:1.5;color:var(--ink-mid);margin:-8px 0 20px;}
.tool-card__btn{margin-top:auto;align-self:flex-start;display:inline-flex;align-items:center;font-family:var(--sans);font-size:18px;font-weight:600;color:var(--cream);background:var(--forest);padding:14px 26px;border-radius:6px;text-decoration:none;min-height:48px;transition:background var(--dur-quick) var(--ease);}
.tool-card__btn:hover,.tool-card__btn:focus{background:#163329;color:var(--cream);}

/* LOOP DISCLOSURE.
   The diagram itself renders through the shared .loop-h/.loop-v pair, so the
   desktop/mobile swap is the same one the sales page uses. */
.loop-disc{margin:0 0 24px;}
.loop-disc summary{list-style:none;display:inline-flex;align-items:center;gap:6px;padding:8px 0;cursor:pointer;font-family:var(--sans);font-size:14px;font-weight:600;color:var(--ink-mid);user-select:none;}
.loop-disc summary::-webkit-details-marker{display:none;}
.loop-disc summary::after{content:'';display:inline-block;width:14px;height:14px;background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M4 6l4 4 4-4' stroke='%235C5750' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;transition:transform var(--dur-quick) var(--ease);}
.loop-disc[open] summary::after{transform:rotate(180deg);}
.loop-disc__body{padding:0 0 20px;}

/* INFO POPOVER.
   Desktop shows the same copy in .hero-aside, so the ⓘ affordance only
   appears once the aside is dropped at the mobile breakpoint. */
.info-btn{display:none;font-size:.45em;color:var(--ink-soft);text-decoration:none;vertical-align:middle;line-height:1;margin-left:.18em;cursor:pointer;position:relative;transition:color var(--dur-quick) var(--ease);}
.info-btn:hover{color:var(--forest);}
.info-popover{position:absolute;left:0;top:calc(100% + 10px);width:280px;background:var(--cream);border:1px solid var(--line);border-radius:8px;padding:16px 18px;box-shadow:0 6px 20px rgba(26,25,22,.13);font-family:var(--sans);font-size:14px;line-height:1.6;color:var(--ink-mid);z-index:200;display:none;}
.info-popover b{color:var(--ink);}
.info-popover p{margin:0 0 10px;}
.info-popover p:last-child{margin:0;}
.info-popover::before{content:'';position:absolute;top:-6px;left:14px;width:10px;height:10px;background:var(--cream);border-left:1px solid var(--line);border-top:1px solid var(--line);transform:rotate(45deg);}
@media(hover:hover){.info-btn:hover .info-popover,.info-btn:focus-within .info-popover{display:block;}}
.info-btn.pop-open .info-popover{display:block;}

@media(max-width:768px){
  .m-nav__badge{display:none;}
  .hub-hero__grid{grid-template-columns:1fr;gap:32px;}
  .tools-grid{grid-template-columns:1fr;}
  .hero-aside{display:none;}
  .info-btn{display:inline;}
}

/* Hero and tools read as one continuous cream region on the hub, matching the
   export. The band keeps its horizontal gutter and rhythm; only the seam closes. */
.band--flush-top{padding-top:0;}

/* BUYER ROLE PROMPT (hub only).
   Sits BELOW the tool grid, inside the tools band, and is deliberately quiet:
   no filled card, no serif heading, small type on a hairline rule. It should
   read as a footnote to the tools, never as a section competing with them.
   If this ever starts looking like a card again, it has drifted. */
.hub-role{display:block;margin:44px 0 0;padding:18px 0 0;border-top:1px solid var(--line);}
.hub-role[hidden]{display:none;}
.hub-role__card{max-width:560px;}
.hub-role__q{font-family:var(--sans);font-size:14px;font-weight:600;line-height:1.4;color:var(--ink-mid);margin:0 0 2px;}
.hub-role__help{font-family:var(--sans);font-size:12.5px;line-height:1.5;color:var(--ink-soft);margin:0 0 12px;}
/* One option per row at every width. The labels are full sentences and must
   stay verbatim to pool with the Diagnostic, so they cannot be shortened into
   chips - wrapping pills of uneven length read ragged. A single column also
   means there is no separate mobile stacking rule to keep in step. */
.hub-role__opts{display:flex;flex-direction:column;gap:6px;}
.hub-role__opt{display:block;width:100%;text-align:left;font-family:var(--sans);font-size:13.5px;line-height:1.4;color:var(--ink-mid);background:transparent;border:1px solid var(--line);border-radius:6px;padding:11px 14px;min-height:42px;cursor:pointer;transition:border-color var(--dur-quick) var(--ease),color var(--dur-quick) var(--ease),background var(--dur-quick) var(--ease);}
.hub-role__opt:hover{border-color:var(--forest);color:var(--forest);background:var(--cream);}
.hub-role__other{display:flex;gap:6px;margin-top:6px;}
.hub-role__other[hidden]{display:none;}
.hub-role__input{flex:1;min-width:0;height:42px;font-family:var(--sans);font-size:13.5px;color:var(--ink);background:var(--cream);border:1px solid var(--line);border-radius:6px;padding:0 12px;}
.hub-role__continue{flex-shrink:0;font-family:var(--sans);font-size:13.5px;font-weight:600;color:var(--cream);background:var(--forest);border:0;border-radius:6px;padding:0 18px;height:42px;min-height:0;cursor:pointer;transition:background var(--dur-quick) var(--ease);}
.hub-role__continue:hover{background:#163329;}
.hub-role__skip{display:inline-block;margin-top:12px;padding:4px 0;min-height:0;font-family:var(--sans);font-size:12.5px;color:var(--ink-soft);background:none;border:0;text-decoration:underline;text-underline-offset:3px;cursor:pointer;}
.hub-role__skip:hover{color:var(--ink-mid);}
@media(max-width:768px){
  .hub-role{margin-top:32px;}
  .hub-role__other{flex-direction:column;}
  .hub-role__continue{width:100%;padding:0;}
}
}
}
