/* ==========================================================================
   TYPEFACES — Geist and Geist Mono, SIL OFL 1.1, self-hosted as woff2.
   font-display:swap so text is never invisible while they load.
   ========================================================================== */
@font-face{font-family:Geist;src:url("../fonts/geist-400.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:Geist;src:url("../fonts/geist-500.woff2") format("woff2");
  font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:Geist;src:url("../fonts/geist-600.woff2") format("woff2");
  font-weight:600;font-style:normal;font-display:swap}
@font-face{font-family:"Geist Mono";src:url("../fonts/geistmono-400.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap}

/* ==========================================================================
   MAPE — website v2
   Light + dark are both first-class; the toggle in the nav is authoritative
   and persists. Structure from mape-saas-landing v2 (§2 colour zoning,
   §4 hero anatomy, §6 pinned discrete-slide story, §8 CTA slab).
   Token discipline from Dub; spacious rhythm from Mercury.
   Green = one primary action per surface + just-happened state.
   ========================================================================== */
:root{
  --canvas:#fff; --paper:#f7f8f7; --wash:#f2f7f3; --ash:#e5e7e5; --smoke:#d3d6d4;
  --fog:#767b78; --steel:#535855; --charcoal:#161917; --ink:#0a0c0b;
  --mape:#00f550; --mape-2:#00a838; --mape-ink:#04240f; --tint:#dcfce7; --tint-ink:#0f6b34;
  --cyan:#2aa7d8; --violet:#7b6cf6; --amber:#e0951f; --rose:#ef6f7b;
  --disp:Geist,ui-sans-serif,system-ui,-apple-system,sans-serif;
  --body:Geist,ui-sans-serif,system-ui,-apple-system,sans-serif;
  --mono:"Geist Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  --pill:9999px; --r-lg:16px; --r-card:12px; --r-btn:8px;
  --sh-btn:rgba(0,0,0,.05) 0 1px 2px 0;
  --sh-ring:rgba(0,0,0,.07) 0 0 0 4px;
  --sh-show:rgba(16,24,20,.12) 0 24px 50px -16px, rgba(16,24,20,.06) 0 8px 16px -8px;
  --sh-sat:rgba(16,24,20,.11) 0 10px 26px -10px;
  --max:1200px; --nav:60px;
  --atmo-a:rgba(0,245,80,.20); --atmo-b:rgba(42,167,216,.15); --atmo-c:rgba(123,108,246,.09);
  /* A deliberately dark panel that stays dark in BOTH themes — the case-study
     outcomes band, the ink cards, the case hero. These were referenced 10
     times and never defined, so every one of them resolved to an invalid
     var() and painted transparent: the outcomes band had simply lost its
     background. Values track the dark theme's own surface ramp. */
  --night:#101413; --night-l:#242927; --night-m:#89908c; --night-t:#eef1ef;
  /* --mape is a signal colour, not a reading colour: #00f550 and #e5e7e5 sit at
     almost the same luminance (1.01:1), so brand green on a light surface is
     invisible as a bar and fails AA as small text. --green-read is the green to
     use whenever it has to be SEEN rather than just noticed. */
  --green-read:var(--tint-ink);
}
html[data-theme="dark"]{
  --canvas:#0b0d0c; --paper:#121514; --wash:#0e1311; --ash:#242927; --smoke:#343a37;
  --fog:#89908c; --steel:#a7aeaa; --charcoal:#eef1ef; --ink:#fff;
  --mape-2:#4dff8f; --tint:#0f2e1a; --tint-ink:#5cf58f;
  --cyan:#5cc4ec; --violet:#a99cff; --amber:#f0b658; --rose:#ff9aa4;
  --sh-ring:rgba(255,255,255,.05) 0 0 0 4px;
  --sh-show:rgba(0,0,0,.55) 0 24px 50px -16px;
  --sh-sat:rgba(0,0,0,.5) 0 10px 26px -10px;
  --atmo-a:rgba(0,245,80,.16); --atmo-b:rgba(42,167,216,.13); --atmo-c:rgba(123,108,246,.10);
  --green-read:var(--mape-2);
  /* the night panel must stay distinguishable from the page in dark too —
     dark --canvas is #0b0d0c, so the light-theme value would vanish here */
  --night:#1b201e; --night-l:#333a37;
}

*{box-sizing:border-box}
html{scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{margin:0;background:var(--canvas);color:var(--charcoal);font-family:var(--body);
     font-size:16px;line-height:1.5;-webkit-font-smoothing:antialiased;overflow-x:hidden;
     transition:background .25s ease,color .25s ease}
:focus-visible{outline:2px solid var(--mape-2);outline-offset:3px;border-radius:4px}
.shell{max-width:var(--max);margin:0 auto;padding:0 32px}
@media(max-width:640px){.shell{padding:0 20px}}
img{max-width:100%}

h1,h2{margin:0;font-family:var(--disp);font-weight:500;text-wrap:balance}
h1{font-size:clamp(2.9rem,7.2vw,4.6rem);line-height:.97;letter-spacing:-.038em}
h2{font-size:clamp(2.05rem,4.6vw,2.95rem);line-height:1.04;letter-spacing:-.03em}
h3{margin:0;font-family:var(--body);font-size:1.0625rem;font-weight:600;line-height:1.35;letter-spacing:-.01em}
p{margin:0}
.eyebrow{font-family:var(--mono);font-size:11px;letter-spacing:.15em;text-transform:uppercase;
         color:var(--fog);margin:0 0 16px}
.lead{font-size:1.22rem;line-height:1.5;color:var(--steel);letter-spacing:-.011em}
.muted{color:var(--steel);font-size:1.0625rem;line-height:1.6}
.sm{font-size:.875rem;line-height:1.5;color:var(--steel)}
.mono{font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;color:var(--fog)}

.btn{display:inline-flex;align-items:center;gap:8px;font-size:15px;font-weight:500;line-height:1;
     padding:13px 21px;border-radius:var(--pill);border:1px solid transparent;text-decoration:none;
     cursor:pointer;white-space:nowrap;color:var(--charcoal);font-family:var(--body)}
.btn-p{background:var(--mape);color:#04240f;font-weight:600;box-shadow:var(--sh-btn)}
.btn-d{background:var(--ink);color:var(--canvas);box-shadow:var(--sh-btn)}
.btn-g{background:var(--canvas);border-color:var(--ash)}
.btn-sm{padding:9px 16px;font-size:14px}

/* nav + theme toggle */
.nav{position:sticky;top:0;z-index:90;height:var(--nav);display:flex;align-items:center;
     background:color-mix(in srgb,var(--canvas) 82%,transparent);backdrop-filter:blur(11px);
     border-bottom:1px solid var(--ash)}
.nav-in{max-width:var(--max);margin:0 auto;width:100%;padding:0 32px;display:flex;
        align-items:center;justify-content:space-between;gap:18px}
@media(max-width:640px){.nav-in{padding:0 20px}}
.brand{display:flex;align-items:center;gap:9px;font-weight:600;font-size:16.5px;
       letter-spacing:-.022em;color:var(--charcoal);text-decoration:none}
.brand img{width:23px;height:23px;display:block}
.nlinks{display:flex;gap:2px}
/* Direct children only. As `.nlinks a` this also matched every link inside the
   two mega panels — and at (0,1,1) it outranked `.mlink`, `.mega-foot` and
   `.mfeat`, so it was quietly forcing pill corners and its own padding onto
   the whole dropdown. */
.nlinks > a{color:var(--steel);text-decoration:none;font-size:14.5px;font-weight:500;
          padding:8px 13px;border-radius:var(--pill)}
.nlinks > a:hover{color:var(--charcoal);background:var(--paper)}
.nact{display:flex;gap:8px;align-items:center}
@media(max-width:1000px){.nlinks{display:none}}
@media(max-width:560px){.nact .btn-g{display:none}}
/* At 390 the actions row ran 3px past the right edge. The drawer already
   carries an EN/NL switch, so the pill goes rather than the CTA. */
@media(max-width:640px){.nact .lang{display:none}}
/* "Start a conversation" is 169px wide. With the brand, the theme toggle and
   the burger that put the row 34px past the edge of a 360px phone — the CTA
   was being cut in half. The button keeps its full label as the accessible
   name; only the visible text shortens. */
.nact .cta-s{display:none}
@media(max-width:640px){.nact .cta-l{display:none}.nact .cta-s{display:inline}}
.themebtn{width:34px;height:34px;border-radius:var(--pill);border:1px solid var(--ash);
  background:var(--canvas);display:flex;align-items:center;justify-content:center;cursor:pointer;
  color:var(--steel);flex:none}
.themebtn:hover{color:var(--charcoal)}
.themebtn .sun{display:none}
html[data-theme="dark"] .themebtn .sun{display:block}
html[data-theme="dark"] .themebtn .moon{display:none}

section{padding:96px 0}
@media(min-width:900px){section{padding:120px 0}}
.band{background:var(--paper);border-top:1px solid var(--ash);border-bottom:1px solid var(--ash)}
.head{max-width:56ch}
.head.mid{margin:0 auto;text-align:center}
.head h2+p{margin-top:20px}

/* ---------- ZONE 1 · hero atmosphere ---------- */
.hero{position:relative;padding:84px 0 0;text-align:center;overflow:hidden;
      perspective:1600px;perspective-origin:50% 0%}
.atmo{position:absolute;inset:-10% -20% auto;height:760px;z-index:0;pointer-events:none;
  background:
    radial-gradient(46% 40% at 74% 12%, var(--atmo-a), transparent 70%),
    radial-gradient(40% 38% at 22% 4%, var(--atmo-b), transparent 72%),
    radial-gradient(34% 30% at 52% 30%, var(--atmo-c), transparent 72%);
  filter:blur(6px)}
.gridfield{position:absolute;inset:0;z-index:0;pointer-events:none;
  background-image:radial-gradient(circle,var(--smoke) 1px,transparent 1px);background-size:26px 26px;
  opacity:.45;
  -webkit-mask-image:radial-gradient(ellipse 74% 52% at 50% 0%,#000,transparent 74%);
  mask-image:radial-gradient(ellipse 74% 52% at 50% 0%,#000,transparent 74%)}
.marklayer{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.marklayer img{display:none}
.marklayer::before{content:"";position:absolute;top:6%;right:-5%;width:min(600px,46vw);
  aspect-ratio:1;background:var(--mark-url) center/contain no-repeat;
  opacity:.42;transform:translate3d(0,var(--m1,0),0);will-change:transform}
html[data-theme="dark"] .marklayer::before{opacity:.30}
.marklayer::after{content:"";position:absolute;left:-1%;bottom:8%;width:min(180px,16vw);
  aspect-ratio:1;background:var(--mark-url) center/contain no-repeat;
  opacity:.22;transform:translate3d(0,var(--m2,0),0);will-change:transform;
  filter:drop-shadow(0 0 24px color-mix(in srgb,var(--mape) 55%,transparent))
         drop-shadow(0 0 58px color-mix(in srgb,var(--mape) 28%,transparent))}
html[data-theme="dark"] .marklayer::after{opacity:.30}
/* On a phone the headline is four lines deep and full width, so the mark at
   .42 stopped being a watermark and started sitting ON the first line. Bigger
   and much fainter reads as texture instead of a collision. */
@media(max-width:820px){
  .marklayer::before{opacity:.15;top:0;right:-14%;width:min(430px,64vw)}
  html[data-theme="dark"] .marklayer::before{opacity:.22}
}
html[data-theme="dark"] .marklayer{opacity:.075}
.hero .shell{position:relative;z-index:3}
.tagpill{display:inline-flex;align-items:center;gap:9px;background:var(--canvas);
  border:1px solid var(--ash);border-radius:var(--pill);padding:6px 16px 6px 7px;
  font-size:13.5px;font-weight:500;margin-bottom:30px}
.tagpill em{font-style:normal;background:var(--tint);color:var(--tint-ink);border-radius:var(--pill);
  padding:3px 10px;font-size:11.5px;font-weight:600;font-family:var(--mono);letter-spacing:.04em}
.hero h1{margin:0 auto 24px;max-width:17ch}
.hero .lead{margin:0 auto;max-width:52ch}
.hcta{display:flex;gap:11px;justify-content:center;margin-top:34px;flex-wrap:wrap}
.hnote{margin-top:18px;font-size:13.5px;color:var(--fog)}
/* preserve-3d sorts children by their position in 3D space, not by z-index —
   so the satellites need a real translateZ or the tilted card renders over
   them however high their z-index is. */
.stage{position:relative;margin-top:56px;perspective:1600px;width:min(1460px,calc(100vw - 24px));margin-left:50%;transform:translateX(-50%)}
.showcase{max-width:920px;margin:0 auto}
.showcase{max-width:832px;margin:0 auto}
.showcase{position:relative;z-index:4;border-radius:var(--r-lg);overflow:hidden;
  box-shadow:var(--sh-show);transform:rotateX(9deg);transform-origin:50% 0%;will-change:transform}
.showcase img{display:block;width:100%;height:auto}
.sat{position:absolute;z-index:30;background:var(--canvas);border:1px solid var(--ash);
  border-radius:var(--r-card);box-shadow:var(--sh-sat);padding:12px 14px;text-align:left;
  will-change:transform}
.sat .k{font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;
        color:var(--fog);display:block;margin-bottom:7px}
.sat-a{left:max(8px,calc(50% - 606px));top:6%;width:196px;animation:bob1 6.5s ease-in-out infinite}
.sat-b{right:max(8px,calc(50% - 610px));top:32%;width:200px;animation:bob2 7.4s ease-in-out infinite .5s}
.sat-c{left:max(8px,calc(50% - 612px));bottom:8%;width:202px;animation:bob1 8s ease-in-out infinite 1.1s}
@keyframes bob1{0%,100%{translate:0 0}50%{translate:0 -15px}}
@keyframes bob2{0%,100%{translate:0 0}50%{translate:0 -14px}}
.chart{display:flex;align-items:flex-end;gap:4px;height:38px}
.chart i{flex:1;border-radius:2px;display:block}
.sat .row2{display:flex;align-items:center;gap:8px;font-size:12.5px;font-weight:500}
.sat .d{width:7px;height:7px;border-radius:var(--pill);flex:none}
.sat .sub{font-family:var(--mono);font-size:10.5px;color:var(--fog);margin-top:6px}
@media(max-width:1240px){.stage{width:100%;margin-left:0;transform:none}
  .sat-a,.sat-b,.sat-c{left:auto;right:auto;top:auto;bottom:auto;position:static;
  transform:none;animation:none;width:auto;margin-top:10px;box-shadow:var(--sh-btn)}
  .stage{perspective:none}
  .sats-inline{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:14px}}
@media(max-width:760px){.sat{display:none}.showcase{transform:none}}

.proof{border-bottom:1px solid var(--ash);background:var(--canvas)}
.proof-in{max-width:var(--max);margin:0 auto;display:grid;grid-template-columns:repeat(4,1fr)}
@media(max-width:880px){.proof-in{grid-template-columns:1fr 1fr}}
.pi{padding:34px 28px;border-left:1px solid var(--ash)}
.pi:first-child{border-left:0}
@media(max-width:880px){.pi:nth-child(3){border-left:0}.pi:nth-child(n+3){border-top:1px solid var(--ash)}}
.pi .n{font-family:var(--disp);font-size:2.05rem;font-weight:500;letter-spacing:-.032em;
       line-height:1;display:block;margin-bottom:9px}
.pi .l{font-size:13.5px;color:var(--steel);line-height:1.45}

/* ==========================================================================
   RECOGNITION — the reader's own week, before a word about Mape.
   A numbered ledger on hairlines, deliberately NOT cards: this is a list of
   symptoms to scan, and six bordered boxes would turn it into a feature grid.
   The number is the only ornament, and it is set in the same mono as the beat
   ladder and the case reel so the page keeps one voice for indices.
   ========================================================================== */
.recog{background:var(--canvas);padding:clamp(64px,8vw,104px) 0;
  border-bottom:1px solid var(--ash)}
.recog-top{max-width:none}
.recog h2{font-size:clamp(1.9rem,4.2vw,3rem);line-height:1.06;letter-spacing:-.035em;
  max-width:19ch;margin:0 0 20px}
.recog .lead{max-width:56ch;margin:0}
.recog-list{list-style:none;margin:clamp(38px,5vw,58px) 0 0;padding:0;
  display:grid;grid-template-columns:1fr 1fr;gap:0 clamp(36px,5vw,72px)}
@media(max-width:860px){.recog-list{grid-template-columns:1fr}}
.recog-list li{display:grid;grid-template-columns:auto 1fr;gap:16px;align-items:start;
  padding:20px 0;border-top:1px solid var(--ash)}
.recog-list .rn{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;
  color:var(--green-read);line-height:1.9}
.recog-list .rt{font-size:1.02rem;line-height:1.5;color:var(--charcoal)}
.recog-foot{margin-top:clamp(38px,5vw,58px);padding-top:26px;
  border-top:1px solid var(--ash);display:grid;grid-template-columns:1.35fr .65fr;
  gap:clamp(24px,4vw,56px);align-items:end}
@media(max-width:860px){.recog-foot{grid-template-columns:1fr;align-items:start}}
.recog-foot p{margin:0;color:var(--steel);font-size:1.02rem;line-height:1.6;max-width:62ch}
.recog-cta a{font-family:var(--mono);font-size:11px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--charcoal);text-decoration:none;
  display:inline-flex;align-items:center;gap:10px;padding-bottom:6px;
  border-bottom:1px solid var(--ash);transition:border-color .3s var(--ease),color .3s var(--ease)}
.recog-cta a::after{content:"\2193";font-family:var(--body);font-size:13px}
.recog-cta a:hover{color:var(--green-read);border-bottom-color:var(--green-read)}

/* ---------- ZONE 3 · pinned story ---------- */
/* No border-bottom: the story dissolves into the section below instead of
   being ruled off from it, and its own surface fades wash -> canvas over the
   last stretch so there is no colour step at the seam either. --story-bleed is
   how far the closing halo may run past the bottom edge into the next section.
   .story must NEVER be given overflow/transform/filter/contain: it is an
   ancestor of .story-pin and any of those silently disables the pinning. */
.story{background:linear-gradient(180deg,var(--wash) 0%,var(--wash) 82%,var(--story-end) 100%);
       border-top:1px solid var(--ash);
       position:relative;padding:0;
       --story-bleed:clamp(260px,46vh,520px);
       /* The tail has to land on whatever the NEXT section is painted, or the
          fade just swaps one hard step for another. Home's story is followed by
          a canvas-backed section; the security page's by a --paper .band. */
       --story-end:var(--canvas)}
#audit-story{--story-end:var(--paper)}
/* ...and that band's own rule is the horizontal line, so it goes too. */
#audit-story + .band{border-top:0}
/* The bleed only works when the next section is transparent and the halo can
   continue THROUGH it — true on the homepage, where #working has no background
   of its own. On the security page the next section is an opaque --paper band
   sitting above the halo, so a bleed would tint the story side of the edge and
   nothing below it: a bigger step than the border it replaced. Here the halo
   fades out INSIDE the section instead, so both sides of the boundary are
   plain --paper. */
#audit-story.is-pinning .story-wash > i:last-child{
  bottom:0;
  -webkit-mask-image:linear-gradient(180deg,#000 0%,#000 58%,transparent 94%);
  mask-image:linear-gradient(180deg,#000 0%,#000 58%,transparent 94%)}
.story-track{position:relative}
/* Top-aligned, not centred. Centring meant a longer beat pushed the whole block
   upward, so the tab rail drifted 88px in English and 143px in Dutch — far
   enough that the Dutch build put it flush against the top edge. Anchored to
   the top, the rail sits at a constant y and longer beats simply run further
   down into space that is already reserved. */
.story-pin{min-height:calc(100vh - var(--nav));display:flex;align-items:flex-start;
  padding:104px 0 40px;width:100%}
/* A full-width head, then two balanced columns. The old single narrow column
   ran the copy down the whole left half and left the bottom-right quarter of
   the section empty. */
.story-in{max-width:var(--max);margin:0 auto;width:100%;padding:0 32px;display:block}
.story-head{width:100%}
.story-h{font-size:clamp(1.6rem,3.1vw,2.35rem);line-height:1.1;letter-spacing:-.03em;
  margin:10px 0 30px;max-width:26ch}
/* stretch, not start: the card then matches whatever the copy comes to on that
   beat, instead of being guessed at a fixed height and coming up short on the
   longest one */
.story-cols{display:grid;grid-template-columns:.88fr 1.12fr;gap:clamp(32px,4.5vw,64px);
  align-items:stretch;margin-top:clamp(30px,4vw,48px)}
@media(max-width:980px){.story-cols{grid-template-columns:1fr;gap:28px}}
.story-copy{min-width:0}
.story-art{min-width:0;display:flex}
/* The card is the tall element, not the copy. Left to its natural height it
   came out ~340px against ~515px of copy, which is what left the bottom right
   of the section empty. */
.story-art .slides{min-height:clamp(400px,46vh,560px);display:flex;width:100%}
.story-art .slide{display:flex}
.story-art .slide > .mk{flex:1;display:flex;flex-direction:column}
.story-art .slide > .mk > .mk-body{flex:1}
/* the step caption above the beat heading */
.scap{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--green-read);margin:0 0 10px}
.story-copy h3{font-size:clamp(1.45rem,2.5vw,1.95rem);line-height:1.12;letter-spacing:-.028em;
  margin:0 0 14px;font-weight:600}
@media(max-width:980px){.story-in{grid-template-columns:1fr;gap:30px}}
@media(max-width:640px){.story-in{padding:0 20px}}
/* The three specifics under each beat. A list, not a paragraph: joined into
   prose they ran to twenty lines in the pinned column, which is unreadable at
   a glance and the opposite of what the section is for. */
.sdet{list-style:none;margin:16px 0 0;padding:0;border-top:1px solid var(--ash)}
.sdet li{display:grid;grid-template-columns:auto 1fr;gap:11px;align-items:start;
  padding:9px 0;border-bottom:1px solid var(--ash);
  font-size:13.5px;line-height:1.5;color:var(--steel)}
.sdet li::before{content:"";width:10px;height:6px;margin-top:5px;flex:none;
  border-left:2px solid var(--green-read);border-bottom:2px solid var(--green-read);
  transform:rotate(-45deg)}
@media(max-width:1023px){.sdet li{font-size:14.5px}}

/* ---------- the beat ladder ----------
   Was: six full-bleed rows (.rtab{width:100%}), a fixed 20px number column and
   a dot flushed right by margin-left:auto, with the active row filled in
   --canvas. That is a data table with a selected row — and at a 44px row pitch
   it rhymed exactly with the tables inside the mockup card beside it, which is
   why the two read as one spreadsheet.
   Now nothing spans the column: each beat is content-width in a flex-start
   column, so the right edge is ragged by construction and no row edge can line
   up with the card. State is carried by the accent and a three-step text
   colour, never by a neutral panel.
   What makes it a progress indicator rather than a list is .meter — a 2px
   hairline that CSS grid sizes to exactly the width of that beat's own label,
   scrubbed live while you are inside the beat and left filled-but-dimmed once
   you are past it. It replaces the separate 3px .progress bar outright: two
   stacked progress affordances were the other half of the table-plus-footer
   read. Same hairline-drawing-in language as .eyebrow::after. */
/* HORIZONTAL, and above the copy. It used to be a vertical column beneath the
   title, lead and three specifics — which put the last tab at ~1126px against
   viewports of 720-1000, so steps 04-06 were never visible at any desktop
   height. Sitting under the eyebrow its position is constant by construction,
   it cannot be pushed off by copy length, and the whole journey is legible
   before you start reading. */
.rail{display:flex;flex-direction:row;align-items:stretch;gap:0;width:100%;margin:0}
.rtab{flex:1 1 0;min-width:0;display:grid;grid-template-rows:auto auto 2px;row-gap:6px;
      align-items:start;padding:0 16px 0 0;border:0;border-radius:0;
      background:transparent;text-align:left;cursor:pointer;font:inherit;color:var(--fog)}
.rtab .num{grid-row:1;font-family:var(--mono);font-size:10.5px;
      letter-spacing:.14em;line-height:1;color:var(--smoke);
      transition:color .3s var(--ease)}
/* labels are back: six of them fit comfortably across the full measure, and
   they are what makes the whole journey legible before you start reading */
.rtab .lbl{grid-row:2;font-size:14px;font-weight:500;line-height:1.3;letter-spacing:-.008em;
      color:var(--steel);transition:color .3s var(--ease)}
.rtab[aria-selected="true"] .lbl{color:var(--charcoal)}
.rtab[data-state="past"] .lbl{color:var(--fog)}
/* grid column 2 is auto-sized and .meter has no intrinsic width, so the meter
   is always exactly as wide as the label sitting above it. */
.rtab .meter{grid-row:3;position:relative;height:2px;background:var(--ash);margin-top:10px}
.rtab .meter::after{content:"";position:absolute;left:0;top:0;bottom:0;width:var(--f,0%);
      background:var(--green-read);transition:opacity .3s var(--ease)}
.rtab[data-state="past"] .num{color:var(--fog)}
.rtab[data-state="past"] .lbl{color:var(--steel)}
.rtab[data-state="past"] .meter::after{opacity:.4}
.rtab[aria-selected="true"] .num{color:var(--green-read)}
.rtab[aria-selected="true"] .lbl{color:var(--charcoal)}
.rtab[aria-selected="true"] .meter{background:var(--smoke)}
.rtab:not([aria-selected="true"]):hover .lbl{color:var(--charcoal)}
.rtab:not([aria-selected="true"]):hover .num{color:var(--steel)}
.rtab:focus-visible{outline:2px solid var(--mape-2);outline-offset:3px}

/* A LONG LADDER. Eleven beats is the whole engagement, and at the default pitch
   the last two ran off the bottom of the pinned viewport at every desktop
   height — the reader could not see the step the section builds toward.
   Compact the rows and tighten the copy above them so all eleven fit. */
.rail[data-long="1"]{gap:5px;margin-top:24px}
.rail[data-long="1"] .rtab{grid-template-rows:auto 2px;row-gap:4px;padding:2px 0}
.rail[data-long="1"] .lbl{font-size:12.5px}
.rail[data-long="1"] .num{font-size:9.5px}
.story:has(.rail[data-long="1"]) .story-in h2{font-size:clamp(1.4rem,2.35vw,1.72rem);
  margin-bottom:12px}
.story:has(.rail[data-long="1"]) #sbody{font-size:14.5px;line-height:1.5}
/* shorter screens give up a little more */
@media (max-height:820px){
  .rail[data-long="1"]{gap:3px;margin-top:18px}
  .rail[data-long="1"] .lbl{font-size:12px}
  .story:has(.rail[data-long="1"]) .story-pin{padding:24px 0}
  .story:has(.rail[data-long="1"]) .story-in h2{font-size:clamp(1.3rem,2vw,1.5rem)}
  .story:has(.rail[data-long="1"]) #sbody{font-size:13.5px}
}
@media (prefers-reduced-motion:reduce){
  .rtab .num,.rtab .lbl,.rtab .meter::after{transition:none}
}
.slides{position:relative;width:100%;border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--sh-show);
        background:var(--canvas);aspect-ratio:16/9}
.slide{position:absolute;inset:0;opacity:0;transition:opacity .25s linear}
.slide[data-on="1"]{opacity:1}
.slide img{width:100%;height:100%;object-fit:cover;display:block}
.stepcap{margin-top:16px;font-family:var(--mono);font-size:11.5px;color:var(--fog);letter-spacing:.05em}
.story-fallback{display:none}
.story-fallback .fb{padding:56px 0;border-top:1px solid var(--ash)}
.story-fallback .fb:first-child{border-top:0}
.story-fallback .shell{padding-top:8px}
.story-fallback .fb .eyebrow{margin-bottom:12px}
.story-fallback .fb h2{font-size:clamp(1.45rem,5.4vw,1.9rem);line-height:1.16;
  letter-spacing:-.02em;margin:0 0 12px;max-width:22ch}
.story-fallback .fb .muted{margin:0;max-width:62ch}
.story-fallback .fb .sdet{margin:18px 0 0;padding:0;list-style:none}
.story-fallback .fb .sdet li{font-size:14px;line-height:1.55;color:var(--steel);
  padding:11px 0 11px 18px;border-top:1px solid var(--ash);position:relative}
.story-fallback .fb .sdet li::before{content:"";position:absolute;left:0;top:19px;
  width:6px;height:6px;border-radius:var(--pill);background:var(--mape-2)}
.story-fallback .slides{margin-top:24px;box-shadow:none;min-height:0;height:auto}
.story-fallback .slide{position:static;opacity:1;pointer-events:auto}
/* the global reset zeroes heading margins and every other section restores
   its own; the pinned story never did, so the beat title butted straight
   into its body copy */
.story-in h2{margin-bottom:18px}
.story-in .eyebrow{margin-bottom:14px}
/* the switch lives with the pin threshold, further down */

.split{display:grid;grid-template-columns:.82fr 1.18fr;gap:64px;align-items:center}
.split.rev{grid-template-columns:1.18fr .82fr}
@media(max-width:980px){.split,.split.rev{grid-template-columns:1fr;gap:40px}
  .split.rev .txt{order:-1}}
/* Grid items are min-width:auto by default, so a single unshrinkable child
   inflates the whole track. Nothing in a split needs to be wider than its
   column. */
.split > *{min-width:0}
.txt h2{margin-bottom:18px}
.txt .muted{max-width:42ch}
/* The tick hangs in a padding gutter rather than sitting in a flex row.
   As `display:flex` the item's text was NOT one flex item: every <b> and each
   run of text around it became its own item, and flex items do not wrap. The
   row's min-content was therefore the SUM of all of them — 413px on a 350px
   column, which is what pushed /method/ to a 433px page at 390px wide. As a
   block the text is ordinary inline flow again and wraps at any word. */
.flist{margin:26px 0 0;padding:0;list-style:none}
.flist li{font-size:14.5px;color:var(--steel);padding:11px 0 11px 26px;
          border-top:1px solid var(--ash);position:relative}
.flist li:first-child{border-top:0}
.flist svg{position:absolute;left:0;top:14px;flex:none}
.flist li:first-child svg{top:3px}
.shot{border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--sh-show)}
.shot img{display:block;width:100%;height:auto}

.grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:56px}
@media(max-width:880px){.grid3{grid-template-columns:1fr}}
.g3c{border:1px solid var(--ash);border-radius:var(--r-lg);padding:26px 24px;background:var(--canvas);
     display:flex;flex-direction:column;gap:11px}
.g3c p{font-size:14.5px;color:var(--steel);line-height:1.55}
.g3c .ic{width:32px;height:32px;border-radius:var(--r-btn);display:flex;align-items:center;
         justify-content:center;margin-bottom:3px}
.g3c .mono{display:block}

/* portfolio */
.work{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:56px}
@media(max-width:940px){.work{grid-template-columns:1fr 1fr}}
@media(max-width:660px){.work{grid-template-columns:1fr}}
.wcard{border:1px solid var(--ash);border-radius:var(--r-lg);padding:26px 24px;background:var(--canvas);
       display:flex;flex-direction:column;gap:12px;text-decoration:none;color:inherit}
.wcard:hover{border-color:var(--smoke)}
.wcard .sector{font-family:var(--mono);font-size:10.5px;letter-spacing:.11em;text-transform:uppercase;
               color:var(--fog)}
.wcard .metric{font-family:var(--disp);font-size:1.55rem;font-weight:500;letter-spacing:-.028em;
               line-height:1.05}
.wcard p{font-size:14px;color:var(--steel);line-height:1.55}
.wcard .go{margin-top:auto;padding-top:8px;font-size:13.5px;font-weight:500;color:var(--charcoal)}
.stackrow{display:flex;gap:6px;flex-wrap:wrap;margin-top:2px}
.chipx{font-family:var(--mono);font-size:10.5px;border:1px solid var(--ash);border-radius:var(--pill);
       padding:3px 9px;color:var(--fog)}

/* quote */
.quote{max-width:840px;margin:0 auto;text-align:center}
.quote blockquote{margin:0;font-family:var(--disp);font-weight:500;
  font-size:clamp(1.45rem,3.1vw,2rem);line-height:1.3;letter-spacing:-.022em}
.qwho{display:flex;align-items:center;justify-content:center;gap:13px;margin-top:30px}
.qav{width:40px;height:40px;border-radius:var(--pill);border:1px solid var(--ash);background:var(--paper);
     display:flex;align-items:center;justify-content:center;font-size:13.5px;font-weight:600;color:var(--steel)}
.qwho .qn{text-align:left;font-size:14px;font-weight:500;line-height:1.35}
.qwho .qn span{display:block;color:var(--fog);font-weight:400;font-size:13px}

.pills{display:flex;gap:8px;flex-wrap:wrap;margin-top:26px}
.pill{display:inline-flex;align-items:center;gap:8px;background:var(--canvas);border:1px solid var(--ash);
      border-radius:var(--pill);padding:7px 15px;font-size:13.5px;font-weight:500}
.pill .d{width:6px;height:6px;border-radius:var(--pill);flex:none}

.fgrid{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin-top:56px}
@media(max-width:820px){.fgrid{grid-template-columns:1fr}}
.panel{background:var(--canvas);border:1px solid var(--ash);border-radius:var(--r-lg);padding:30px 28px}
.panel>.mono{display:block;margin-bottom:18px}
.fi{display:flex;gap:13px;align-items:flex-start;padding:15px 0;border-top:1px solid var(--ash)}
.fi:first-of-type{border-top:0;padding-top:0}
.fi svg{flex:none;margin-top:3px}
.fi span{font-size:15.5px;line-height:1.45}
.fi.no span{color:var(--steel)}
.fi.yes span{color:var(--charcoal);font-weight:500}

/* ZONE 2 · CTA slab straddling footer */
.closer{position:relative;padding-top:120px}
.slabwrap{padding:0 32px}
@media(max-width:640px){.slabwrap{padding:0 20px}}
.slab{max-width:var(--max);margin:0 auto;position:relative;z-index:3;
      background:linear-gradient(135deg,#00f550 0%,#22e07a 58%,#12d0c0 100%);
      border-radius:24px;padding:56px 48px;color:#04240f;
      display:grid;grid-template-columns:1.3fr .7fr;gap:36px;align-items:center;
      box-shadow:rgba(0,120,50,.20) 0 22px 44px -18px}
@media(max-width:900px){.slab{grid-template-columns:1fr;padding:40px 28px;text-align:center}}
.slab h2{color:#04240f;max-width:15ch;margin-bottom:14px}
.slab p{color:rgba(4,36,15,.78);font-size:1.06rem;max-width:40ch}
@media(max-width:900px){.slab p{margin:0 auto}}
.slab .acts{display:flex;gap:11px;flex-wrap:wrap;justify-content:flex-end}
@media(max-width:900px){.slab .acts{justify-content:center}}
.slab .btn-solid{background:#04240f;color:#eafff1;font-weight:600}
.slab .btn-clear{background:rgba(255,255,255,.55);color:#04240f;font-weight:600}

/* No border-top: the CTA slab deliberately straddles the footer, so a full-width
   rule here draws a hard streak straight across the middle of it. The change of
   background already reads as the boundary everywhere the slab is not. */
.foot{background:var(--paper);padding:120px 0 44px;margin-top:-64px}
.fcols{display:grid;grid-template-columns:1.6fr repeat(4,1fr);gap:32px}
@media(max-width:960px){.fcols{grid-template-columns:1fr 1fr 1fr}}
@media(max-width:620px){.fcols{grid-template-columns:1fr 1fr}}
.fcol h4{margin:0 0 14px;font-size:13px;font-weight:600}
.fcol a{display:block;color:var(--steel);text-decoration:none;font-size:14px;padding:5px 0}
.fcol a:hover{color:var(--charcoal)}
.fbrand p{font-size:14px;color:var(--steel);line-height:1.6;max-width:30ch;margin-top:14px}
.fbot{margin-top:52px;padding-top:26px;border-top:1px solid var(--ash);display:flex;
      justify-content:space-between;gap:18px;flex-wrap:wrap;align-items:center}
.fbadges{display:flex;gap:8px;flex-wrap:wrap}
.fbadge{font-family:var(--mono);font-size:11px;border:1px solid var(--ash);border-radius:var(--pill);
        padding:5px 12px;color:var(--fog)}

@media (prefers-reduced-motion:reduce){
  .sat{animation:none!important}.showcase{transform:none!important}
  .story-track{display:none}.story-fallback{display:block}
}

/* ==========================================================================
   PAGE FURNITURE — added for the multi-page build
   ========================================================================== */

/* page hero (non-home) */
.phero{padding:76px 0 56px;border-bottom:1px solid var(--ash);position:relative;overflow:hidden}
.phero .atmo{height:420px}
.phero .shell{position:relative;z-index:2}
.phero h1{font-size:clamp(2.3rem,5.4vw,3.4rem);max-width:19ch;margin:0 0 20px}
.phero .lead{max-width:56ch}
.phero .crumb{font-family:var(--mono);font-size:11px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--fog);margin:0 0 18px}
.phero .crumb a{color:var(--fog);text-decoration:none}
.phero .crumb a:hover{color:var(--charcoal)}

/* prose — legal + article bodies */
/* MEASURE. `max-width:72ch` computed to 774px here, which is 98 characters —
   far outside the 45-75 band. `ch` is the advance of the "0" glyph (0.672em in
   Geist) while the average text advance is ~0.47em, so ch overstates a line by
   about 40%. The cap is set in px against a measured average instead, and it
   moves onto the CHILDREN: markdown.py emits every block as a direct child of
   .prose, so capping the children lets tables and pull-quotes break out past
   the text column without a single negative margin. */
.prose{max-width:52rem;--measure:37.5rem}
.prose > *{max-width:var(--measure)}
/* Break out to the full .prose width — NOT to none: a wide table with
   max-width:none grows past its own container and takes the page with it,
   which is exactly what it did on /cookies/ at 390px. 100% here is the
   832px break-out, and .tablewrap keeps its own overflow-x:auto so a table
   too wide for that scrolls inside itself. */
.prose > .tablewrap,.prose > blockquote,.prose > figure,.prose > hr{max-width:100%}
.prose h2{font-size:clamp(1.5rem,2.8vw,1.9rem);margin:54px 0 16px;letter-spacing:-.024em;
  line-height:1.18}
/* h3 was 1.06rem against a 1.0425rem body — a 1.7% step, which is no hierarchy
   at all. These are real steps. */
.prose h3{font-size:1.25rem;margin:38px 0 10px;letter-spacing:-.015em;line-height:1.3}
.prose h4{font-size:11px;margin:30px 0 8px;font-family:var(--mono);font-weight:500;
  letter-spacing:.13em;text-transform:uppercase;color:var(--fog)}
.prose p{margin:0 0 20px;color:var(--steel);font-size:1.125rem;line-height:1.7}
.prose ul,.prose ol{margin:0 0 22px;padding-left:1.15em}
.prose li{color:var(--steel);font-size:1.125rem;line-height:1.62;margin-bottom:10px}
.prose li::marker{color:var(--fog)}
/* The lede: articles all open with an h2, so this targets the first paragraph
   of the piece without touching .prose > p:first-child, which is what the
   policy pages actually use. */
.prose > h2:first-child + p{font-size:1.28rem;line-height:1.55;color:var(--charcoal);
  margin-bottom:26px}
.prose a{color:var(--charcoal);text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:var(--smoke)}
.prose a:hover{text-decoration-color:var(--mape-2)}
.prose strong{color:var(--charcoal);font-weight:600}
.prose hr{border:0;border-top:1px solid var(--ash);margin:44px 0}
.prose table{width:100%;border-collapse:collapse;font-size:.9rem;margin:0 0 20px}
.prose th{text-align:left;font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--fog);font-weight:500;padding:0 14px 10px 0;
  border-bottom:1px solid var(--ash)}
.prose td{padding:12px 14px 12px 0;border-bottom:1px solid var(--ash);color:var(--steel);
  vertical-align:top;line-height:1.6}
.prose td:first-child{color:var(--charcoal);font-weight:500}
.updated{font-family:var(--mono);font-size:11.5px;color:var(--fog);letter-spacing:.05em;
  padding:9px 14px;border:1px solid var(--ash);border-radius:var(--pill);display:inline-block}

/* two-column doc layout with a sticky index */
/* min-width:0 on the items is load-bearing. A grid item defaults to
   min-width:auto, so the min-content of a wide <table> deep inside .prose
   propagates up and forces the 1fr track wider than the grid itself — which is
   how /cookies/ ended up 101px wider than the viewport at 390px even though
   .tablewrap already had overflow-x:auto. */
.doc{display:grid;grid-template-columns:220px 1fr;gap:56px;align-items:start}
.doc > *{min-width:0}
/* An article with two or fewer h2s gets no index — and then the <article> was
   the only child and rendered inside the 220px index track, roughly a fifth of
   the page. Span the whole grid when there is nothing beside it. */
.doc > *:only-child{grid-column:1 / -1}
@media(max-width:900px){.doc{grid-template-columns:1fr;gap:28px}.doc .toc{position:static}}
.toc{position:sticky;top:calc(var(--nav) + 28px)}
.toc h4{margin:0 0 12px;font-family:var(--mono);font-size:10.5px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--fog);font-weight:500}
/* The index carries its own reading progress: --p is written by site.js as the
   share of the article scrolled past, and the hairline fills to match. No left
   accent stripe — the numerals carry the structure. */
.toc{--p:0%}
.toc-rail{position:relative;height:1px;background:var(--ash);margin:0 0 14px}
.toc-rail::after{content:"";position:absolute;left:0;top:0;height:1px;width:var(--p,0%);
  background:var(--green-read);transition:width .18s linear}
/* flex, NOT grid: the policy pages emit a plain <a>label</a> with no <b>/<span>,
   and an `auto 1fr` grid sized that auto track to the whole label — which blew
   the sidebar out to 471px inside a 350px column on /cookies/ at 390px.
   min-width:0 + overflow-wrap keep a long Dutch heading from doing the same. */
.toc a{display:flex;gap:10px;align-items:baseline;min-width:0;overflow-wrap:anywhere;
  font-size:13.5px;color:var(--fog);text-decoration:none;padding:7px 0;
  transition:color .25s var(--ease)}
.toc a > span{min-width:0}
.toc a b{flex:none;font-family:var(--mono);font-size:10px;font-weight:500;letter-spacing:.1em;
  color:var(--smoke);transition:color .25s var(--ease)}
.toc a:hover{color:var(--charcoal)}
.toc a[aria-current="true"]{color:var(--charcoal)}
.toc a[aria-current="true"] b{color:var(--green-read)}

/* Keep reading — two neighbours, as plain typographic blocks rather than
   another set of bordered cards. The rule above each is the only chrome. */
.nxwrap{margin-top:64px;padding-top:30px;border-top:1px solid var(--ash);max-width:none}
.nxRow{display:grid;grid-template-columns:1fr 1fr;gap:34px;margin-top:20px}
@media(max-width:760px){.nxRow{grid-template-columns:1fr;gap:22px}}
/* .prose a wins on specificity (0,1,1 vs 0,1,0), so the cards inherited the
   body-copy underline and read as a wall of links. */
.prose .nx,.prose .nx:hover{text-decoration:none}
.nx{display:block;text-decoration:none;padding-top:16px;border-top:1px solid var(--ash);
  transition:border-color .3s var(--ease)}
.nx:hover{border-top-color:var(--green-read)}
.nx-k{display:block;font-family:var(--mono);font-size:10px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--fog);margin-bottom:9px}
.nx-t{display:block;font-family:var(--disp);font-size:1.1rem;font-weight:500;
  letter-spacing:-.02em;line-height:1.28;color:var(--charcoal);
  transition:color .3s var(--ease)}
.nx:hover .nx-t{color:var(--green-read)}

/* document request list (trust center) */
.docs{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:26px}
@media(max-width:760px){.docs{grid-template-columns:1fr}}
.docitem{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1px solid var(--ash);
  border-radius:var(--r-card);font-size:14.5px;background:var(--canvas)}
.docitem.open{border-color:color-mix(in srgb,var(--mape-2) 40%,var(--ash))}
.docitem .lockicon{flex:none;color:var(--fog)}
.docitem a{color:var(--charcoal);text-decoration:none;font-weight:500}
.docitem a:hover{text-decoration:underline}
.docitem .tagline{margin-left:auto;font-family:var(--mono);font-size:10.5px;color:var(--fog);
  letter-spacing:.06em;white-space:nowrap}

/* contact grid */
.cgrid{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin-top:48px}
@media(max-width:820px){.cgrid{grid-template-columns:1fr}}
.ccard{border:1px solid var(--ash);border-radius:var(--r-lg);padding:30px 28px;background:var(--canvas)}
.ccard h3{margin-bottom:10px}
.ccard p{font-size:14.5px;color:var(--steel);line-height:1.6}
.ccard .big{display:block;font-family:var(--disp);font-size:1.3rem;font-weight:500;
  letter-spacing:-.024em;margin:14px 0 4px;color:var(--charcoal);text-decoration:none;word-break:break-word}
.ccard .big:hover{text-decoration:underline}

/* team */
.team{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin-top:52px}
@media(max-width:820px){.team{grid-template-columns:1fr}}
.person{border:1px solid var(--ash);border-radius:var(--r-lg);padding:30px 28px;background:var(--canvas)}
.person .who{display:flex;align-items:center;gap:14px;margin-bottom:16px}
.person .ini{width:46px;height:46px;border-radius:var(--pill);border:1px solid var(--ash);
  background:var(--paper);display:flex;align-items:center;justify-content:center;
  font-weight:600;font-size:15px;color:var(--steel);flex:none}
.person .pic{width:64px;height:64px;border-radius:14px;object-fit:cover;flex:none;
  border:1px solid var(--ash);background:var(--paper)}
.person .nm{font-size:1.06rem;font-weight:600;line-height:1.3}
.person .rl{font-family:var(--mono);font-size:11px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--fog);margin-top:3px}
.person p{font-size:14.5px;color:var(--steel);line-height:1.62;margin-bottom:14px}
.person a{font-size:13.5px;color:var(--charcoal);text-decoration:none;font-weight:500}
.person a:hover{text-decoration:underline}

/* cookie banner */
.cookie{position:fixed;left:0;right:0;bottom:0;z-index:120;padding:16px;
  transform:translateY(120%);transition:transform .4s cubic-bezier(.4,0,.2,1)}
.cookie[data-show="1"]{transform:translateY(0)}
.cookie-in{max-width:760px;margin:0 auto;background:var(--canvas);border:1px solid var(--ash);
  border-radius:var(--r-lg);padding:20px 22px;box-shadow:var(--sh-show);
  display:flex;gap:20px;align-items:center;flex-wrap:wrap}
.cookie-in p{font-size:13.5px;color:var(--steel);line-height:1.55;flex:1;min-width:240px}
.cookie-in p a{color:var(--charcoal)}
.cookie-in .acts{display:flex;gap:8px;flex-wrap:wrap}
@media (prefers-reduced-motion:reduce){.cookie{transition:none}}

/* mobile nav */
.burger{display:none;width:34px;height:34px;border-radius:var(--pill);border:1px solid var(--ash);
  background:var(--canvas);align-items:center;justify-content:center;cursor:pointer;color:var(--steel)}
@media(max-width:1000px){.burger{display:flex}}
.mobnav{position:fixed;inset:var(--nav) 0 auto;z-index:85;background:var(--canvas);
  border-bottom:1px solid var(--ash);padding:14px 20px 20px;display:none;
  max-height:calc(100dvh - var(--nav));overflow-y:auto;
  box-shadow:0 24px 48px -28px rgba(10,12,10,.45)}
.mobnav[data-open="1"]{display:block}
/* The drawer only covers the top of the screen, so without a scrim the page
   carries on underneath it — the hero's own green CTA sat directly below the
   drawer's, which reads as a rendering fault.
   The scrim hangs off body, NOT off .mobnav. As a pseudo-element of the drawer
   it tinted the drawer too: .mobnav has z-index:85 so it forms a stacking
   context, and inside one a negative-z-index child still paints ABOVE the
   root element's own background. On body it simply sits at z-index 80 —
   under the drawer (85) and the nav, over everything else. */
html[data-nav-open="1"]{overflow:hidden}
html[data-nav-open="1"] body::after{content:"";position:fixed;inset:0;z-index:80;
  background:color-mix(in srgb,var(--ink) 45%,transparent);
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}
.mobnav a{display:block;padding:12px 4px;font-size:16px;color:var(--charcoal);text-decoration:none;
  border-bottom:1px solid var(--ash);font-weight:500}
.mobnav a:last-of-type{border-bottom:0}
.mobnav .mobcta{display:flex;gap:8px;margin-top:16px;flex-wrap:wrap}

/* language switch */
.lang{display:inline-flex;border:1px solid var(--ash);border-radius:var(--pill);overflow:hidden;flex:none}
.lang a{font-family:var(--mono);font-size:11px;letter-spacing:.07em;padding:8px 11px;
  color:var(--fog);text-decoration:none;line-height:1}
.lang a[aria-current]{background:var(--charcoal);color:var(--canvas)}
@media(max-width:620px){.lang{display:none}}

/* 404 */
.nf{text-align:center;padding:140px 0}
.nf .code{font-family:var(--mono);font-size:12px;letter-spacing:.16em;color:var(--fog);
  margin-bottom:20px;text-transform:uppercase}

/* generic section headers on inner pages */
.inner-head{max-width:58ch;margin-bottom:14px}
.stack-lg > * + *{margin-top:20px}
.note-box{border:1px solid var(--ash);border-left:2px solid var(--mape-2);border-radius:var(--r-card);
  padding:18px 20px;background:var(--paper)}
.note-box p{font-size:14.5px;color:var(--steel);line-height:1.6;margin:0}
.note-box p + p{margin-top:10px}

/* ==========================================================================
   ATMOSPHERE + BRAND PRESENCE
   The mark appears three times at different scales and opacities: behind the
   hero (parallax), behind the story band (static watermark), and behind the
   closing slab. It is the only decorative element on the site.
   ========================================================================== */
.story[data-watermark="1"]{position:relative}
/* The atmosphere lives in its own clipped layer. It must NOT be an ancestor
   of .story-pin: overflow:hidden anywhere above a sticky element silently
   disables the stickiness, which is exactly what broke this section. */
.story-bg{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0}
.story-bg .wm{position:absolute;right:-9%;top:8%;width:min(660px,58vw);aspect-ratio:1;
  background-image:var(--mark-url);background-size:contain;background-repeat:no-repeat;
  opacity:.05;filter:grayscale(1)}
html[data-theme="dark"] .story-bg .wm{opacity:.075;filter:none}
/* THE BEAT HALO — one layer per beat, cross-dissolved on opacity.
   The old single .wash swapped its background-IMAGE and declared
   `transition:background`, which does nothing: CSS cannot interpolate two
   radial-gradients with different positions and stops, so every beat change
   was a hard cut however long the duration. Opacity IS interpolable, so each
   beat owns a layer and site.js blends them straight off the scrub.
   Like .story-bg this is a SIBLING of .story-track and so never an ancestor of
   .story-pin — but unlike .story-bg it is deliberately NOT clipped, which is
   what lets the closing halo run past the section edge. */
.story-wash{position:absolute;left:0;right:0;top:0;bottom:0;pointer-events:none;z-index:0}
.story-wash > i{position:absolute;left:0;right:0;top:0;bottom:0;display:block;
  font-style:normal;opacity:0}
.story .story-track,.story .story-fallback{position:relative;z-index:1}


/* proof strip: give each figure its own hue, so the numbers carry colour */
.pi:nth-child(1) .n{color:var(--mape-2)}
.pi:nth-child(2) .n{color:var(--cyan)}
.pi:nth-child(3) .n{color:var(--violet)}
.pi:nth-child(4) .n{color:var(--amber)}

/* section eyebrows get a hairline rule that draws in on reveal */
.eyebrow{position:relative;display:inline-block;padding-bottom:8px}
.eyebrow::after{content:"";position:absolute;left:0;bottom:0;height:1px;width:0;
  background:linear-gradient(90deg,var(--mape),transparent);
  transition:width .8s cubic-bezier(.4,0,.2,1)}
.eyebrow[data-seen="1"]::after{width:100%}

/* reveal-on-scroll for section heads and cards — restrained, one move only */
[data-reveal]{opacity:0;transform:translateY(14px);
  transition:opacity .6s cubic-bezier(.4,0,.2,1),transform .6s cubic-bezier(.4,0,.2,1)}
[data-reveal][data-seen="1"]{opacity:1;transform:none}

/* the closing slab gets the mark too, bleeding off the edge */
.slab{position:relative;overflow:hidden}
.slab::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(120% 90% at 85% 105%,rgba(6,14,9,.30),transparent 62%)}
.slab::after{content:"";position:absolute;right:-30px;bottom:-58px;width:290px;aspect-ratio:1;
  background-image:var(--mark-url);background-size:contain;background-repeat:no-repeat;
  opacity:.42;pointer-events:none;filter:brightness(1.9) saturate(.5)}
.slab > *{position:relative;z-index:1}

@media (prefers-reduced-motion:reduce){
  [data-reveal]{opacity:1!important;transform:none!important}
  .eyebrow::after{transition:none;width:100%}
}

/* ==========================================================================
   ARTICLES — case studies and journal entries
   ========================================================================== */
.artmeta{display:flex;flex-wrap:wrap;gap:0;margin-top:28px;border-top:1px solid var(--ash);
  border-bottom:1px solid var(--ash)}
.artmeta .am-k{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--fog);display:block;padding:16px 22px 0 0}
.artmeta .am-v{font-size:15px;font-weight:500;display:block;padding:5px 22px 16px 0;
  border-right:1px solid var(--ash);margin-right:22px}
.artmeta > :last-child{border-right:0;margin-right:0}
.artmeta .am-hi{color:var(--mape-2)}
@media(max-width:600px){
  .artmeta{flex-direction:column}
  .artmeta .am-v{border-right:0;margin-right:0;padding-bottom:14px}
  .artmeta .am-k{padding-top:14px}
}

/* No left accent stripe. A rule above and below and a bigger face does the
   same job without the stock "callout card" signature. */
.prose blockquote{margin:44px 0;padding:26px 0 0;border:0;border-top:1px solid var(--ash);
  position:relative}
.prose blockquote::after{content:"";position:absolute;left:0;top:-1px;width:44px;height:1px;
  background:var(--mape)}
.prose blockquote p{font-family:var(--disp);font-size:1.24rem;line-height:1.42;
  letter-spacing:-.018em;color:var(--charcoal);margin:0 0 12px}
.prose blockquote cite{font-style:normal;font-size:.9rem;color:var(--fog);
  font-family:var(--mono);letter-spacing:.03em}
.prose code{font-family:var(--mono);font-size:.88em;background:var(--paper);
  border:1px solid var(--ash);border-radius:5px;padding:2px 6px}
.prose .tablewrap{overflow-x:auto;margin:0 0 22px}
.prose h3{margin-top:34px}
.prose > p:first-child{font-size:1.12rem;color:var(--steel)}

/* article cards reuse .wcard; give the journal a lighter weight */
.wcard .sector{color:var(--fog)}

/* ==========================================================================
   HEADER — transparent over the hero, frosted floating pill on scroll
   (mape-saas-landing §9). The fill is deliberately light: heavier values
   read as a solid bar and lose the floating quality.
   ========================================================================== */
.nav{position:fixed;top:0;left:0;right:0;z-index:90;background:transparent;
  border-bottom:1px solid transparent;transition:background .3s var(--ease),
  border-color .3s var(--ease),padding .3s var(--ease)}
.nav-in{max-width:var(--max);margin:0 auto;padding:14px 32px;display:flex;
  align-items:center;justify-content:space-between;gap:18px;
  border:1px solid transparent;border-radius:0;background:transparent;
  transition:max-width .34s var(--ease),padding .34s var(--ease),
    background .34s var(--ease),border-color .34s var(--ease),
    border-radius .34s var(--ease),box-shadow .34s var(--ease),
    backdrop-filter .34s var(--ease)}
.nav[data-float="1"]{border-bottom-color:transparent}
.nav[data-float="1"] .nav-in{
  max-width:calc(var(--max) - 132px);
  margin-top:11px;padding:9px 11px 9px 20px;
  border-radius:var(--pill);
  background:color-mix(in srgb,var(--canvas) 62%,transparent);
  border-color:color-mix(in srgb,var(--ash) 74%,transparent);
  -webkit-backdrop-filter:blur(11px) saturate(160%);
  backdrop-filter:blur(11px) saturate(160%);
  box-shadow:0 8px 28px -14px rgba(10,12,10,.30),0 1px 2px rgba(10,12,10,.05)}
@media(max-width:1100px){.nav[data-float="1"] .nav-in{max-width:calc(100% - 28px)}}
@media(max-width:640px){.nav-in{padding:11px 20px}
  .nav[data-float="1"] .nav-in{padding:8px 9px 8px 16px;margin-top:8px}}

/* wordmark replaces the typed brand name */
.brand{display:flex;align-items:center;gap:10px;text-decoration:none;flex:none;
  flex-wrap:nowrap;white-space:nowrap}
.brand .mark{width:26px;height:26px;display:block}
.brand .wordmark{height:17px;width:auto;display:block}
.brand .wordmark.on-light{display:block}
.brand .wordmark.on-dark{display:none}
html[data-theme="dark"] .brand .wordmark.on-light{display:none}
html[data-theme="dark"] .brand .wordmark.on-dark{display:block}
@media(max-width:420px){.brand .wordmark{height:15px}}

/* ---------------- mega menu ---------------- */
.nlinks{display:flex;gap:2px;align-items:center}
@media(max-width:1000px){.nlinks{display:none}}
.nitem{position:relative}
.ntrig{display:inline-flex;align-items:center;gap:6px;border:0;background:transparent;
  font:inherit;font-size:14.5px;font-weight:500;color:var(--steel);cursor:pointer;
  padding:9px 13px;border-radius:var(--pill);text-decoration:none;
  transition:color .18s var(--ease),background .18s var(--ease)}
.ntrig:hover,.nitem[data-open="1"] .ntrig{color:var(--charcoal);
  background:color-mix(in srgb,var(--paper) 80%,transparent)}
.ntrig .chev{transition:transform .2s var(--ease)}
.nitem[data-open="1"] .chev{transform:rotate(180deg)}

.mega{position:absolute;top:calc(100% + 12px);left:50%;transform:translateX(-50%) translateY(-6px);
  width:min(940px,94vw);background:var(--canvas);border:1px solid var(--ash);
  border-radius:var(--r-lg);box-shadow:0 24px 60px -24px rgba(10,12,10,.28),
  0 2px 6px rgba(10,12,10,.05);padding:18px;opacity:0;visibility:hidden;
  transition:opacity .18s var(--ease),transform .22s var(--ease),visibility .18s;
  z-index:95}
.nitem[data-open="1"] .mega{opacity:1;visibility:visible;transform:translateX(-50%) translateY(0)}
/* Links on the left, one picture panel down the right. The panel is a real
   destination, not decoration — it is the only place in the nav that shows
   what the work looks like. */
.mega-body{display:grid;grid-template-columns:1fr 268px;gap:16px;align-items:start}
.mega-grid{display:grid;grid-template-columns:1fr 1fr;gap:6px}
.mfeat{display:block;padding:10px 10px 12px;border-radius:var(--r-card);
  border:1px solid var(--ash);background:var(--paper);text-decoration:none;
  transition:border-color .18s var(--ease),background .18s var(--ease)}
.mfeat:hover{border-color:color-mix(in srgb,var(--mape) 40%,var(--ash));
  background:color-mix(in srgb,var(--mape) 5%,var(--paper))}
.mfeat-img{display:block;border-radius:8px;overflow:hidden;background:var(--night);
  border:1px solid var(--ash);aspect-ratio:5/3}
.mfeat-img img{display:block;width:100%;height:100%;object-fit:cover;
  transition:transform .5s var(--ease)}
.mfeat:hover .mfeat-img img{transform:scale(1.04)}
.mfeat-k{display:block;margin:11px 0 5px;font-family:var(--mono);font-size:10px;
  letter-spacing:.13em;text-transform:uppercase;color:var(--green-read)}
.mfeat-t{display:block;font-size:13.5px;font-weight:600;line-height:1.3;color:var(--charcoal)}
.mfeat-go{display:block;margin-top:7px;font-family:var(--mono);font-size:11px;color:var(--fog);
  transition:color .18s var(--ease)}
.mfeat:hover .mfeat-go{color:var(--mape-2)}
@media(max-width:1080px){
  .mega-body{grid-template-columns:1fr}
  .mfeat{display:flex;gap:13px;align-items:center}
  .mfeat-img{width:138px;flex:none}
  .mfeat-k{margin-top:0}
}
.mfeat-txt{display:block;min-width:0}
@media (prefers-reduced-motion:reduce){.mfeat-img img{transition:none}
  .mfeat:hover .mfeat-img img{transform:none}}
.mega-col h5{margin:0 0 8px;padding:0 10px;font-family:var(--mono);font-size:10px;
  letter-spacing:.13em;text-transform:uppercase;color:var(--fog);font-weight:500}
.mlink{display:flex;gap:12px;align-items:flex-start;padding:10px;border-radius:var(--r-card);
  text-decoration:none;transition:background .16s var(--ease)}
.mlink:hover{background:var(--paper)}
.mlink .mi{width:32px;height:32px;flex:none;border-radius:9px;border:1px solid var(--ash);
  background:var(--paper);display:flex;align-items:center;justify-content:center;
  color:var(--steel);transition:border-color .16s var(--ease),color .16s var(--ease)}
.mlink:hover .mi{border-color:var(--mape);color:var(--mape-2)}
.mlink .mt{font-size:13.5px;font-weight:600;color:var(--charcoal);display:block;line-height:1.3}
.mlink .md{font-size:12px;color:var(--steel);display:block;margin-top:3px;line-height:1.45}
.mega-foot{display:flex;align-items:center;justify-content:space-between;gap:12px;
  margin-top:12px;padding:12px 14px;border-radius:var(--r-card);
  background:color-mix(in srgb,var(--mape) 7%,transparent);
  border:1px solid color-mix(in srgb,var(--mape) 22%,transparent);text-decoration:none}
.mega-foot span{font-size:13px;font-weight:600;color:var(--charcoal)}
.mega-foot em{font-style:normal;font-family:var(--mono);font-size:11px;color:var(--fog)}
.mega-foot:hover em{color:var(--mape-2)}
@media (prefers-reduced-motion:reduce){
  .nav,.nav-in,.mega,.ntrig .chev{transition:none}
}





/* ==========================================================================
   CLIENT WALL — seven marks, one ink.
   The logos arrive as a mixed set: three pure-white wordmarks, one near-black
   mark, one navy+olive SVG. Painting them as images means half the set is
   invisible in one theme or the other, and a shared grayscale/invert filter
   cannot fix that because it moves every logo in the same direction. Each file
   is therefore used as an alpha MASK over a single theme-aware ink.
   Spacing is margin-right, not gap — see the note in the marquee below.
   ========================================================================== */
/* padding:0 is load-bearing: the generic `section` rule sets 120px 0, which
   turns a 52px row into a 410px band of empty page. */
.logos{border-top:1px solid var(--ash);border-bottom:1px solid var(--ash);
  background:var(--wash);overflow:hidden;padding:0;--logo-ink:var(--fog)}
html[data-theme="dark"] .logos{--logo-ink:var(--steel)}
.logos-in{max-width:var(--max);margin:0 auto;padding:38px 32px 42px}
.logos-cap{margin:0 0 24px;text-align:center;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--fog)}
.logo-view{overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}
/* two identical copies drifting to -50%. The trailing margin belongs to EVERY
   item including the last, so half the track is exactly one copy wide and the
   seam is invisible; flex `gap` puts no space after the last item and the loop
   jumps by half a gap every lap. */
.logo-track{display:flex;align-items:center;width:max-content;
  animation:logodrift 52s linear infinite}
.lg{flex:none;display:block;width:var(--lw);height:var(--lh);
  margin-right:clamp(44px,6vw,86px);
  background-color:var(--logo-ink);
  -webkit-mask:var(--ls) no-repeat center/contain;
  mask:var(--ls) no-repeat center/contain;
  opacity:.72;transition:opacity .22s var(--ease),background-color .22s var(--ease)}
.lg:hover,.lg:focus-visible{opacity:1;background-color:var(--charcoal)}
.logos:hover .logo-track,.logo-track:focus-within{animation-play-state:paused}
@keyframes logodrift{from{transform:translate3d(0,0,0)}to{transform:translate3d(-50%,0,0)}}
@media(max-width:640px){
  .logos-in{padding:30px 20px 34px}
  .logos-cap{margin-bottom:18px}
  .lg{margin-right:30px;transform:scale(.76);transform-origin:left center}
  /* a 7% fade is 27px on a 390px screen and was swallowing a whole mark */
  .logo-view{-webkit-mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent);
    mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent)}
}
/* No motion means no marquee, so the duplicate copy would simply print the set
   twice. Drop it and centre what is left. */
@media (prefers-reduced-motion:reduce){
  .logo-track{animation:none;flex-wrap:wrap;justify-content:center;width:auto;
    row-gap:26px}
  .lg.dup{display:none}
  .logo-view{-webkit-mask-image:none;mask-image:none}
}

/* ==========================================================================
   MARQUEE — full-bleed continuous drift (mape-saas-landing §8). Variable
   widths, one height, mixed card types. Never pauses on hover; drag works.
   ========================================================================== */
.marquee{padding:0;border-top:1px solid var(--ash);border-bottom:1px solid var(--ash);
  background:var(--wash);overflow:hidden;position:relative}
.marquee-head{max-width:var(--max);margin:0 auto;padding:56px 32px 0}
@media(max-width:640px){.marquee-head{padding:44px 20px 0}}
.mq-view{overflow:hidden;padding:30px 0 56px;cursor:grab}
.mq-view[data-drag="1"]{cursor:grabbing}
.mq-track{display:flex;gap:14px;width:max-content;will-change:transform}
.mq-card{flex:none;height:230px;border-radius:var(--r-lg);border:1px solid var(--ash);
  background:var(--canvas);padding:22px;display:flex;flex-direction:column;
  justify-content:space-between;user-select:none}
.mq-card .mq-k{font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--fog)}
.mq-card .mq-t{font-family:var(--disp);font-size:1.32rem;font-weight:500;letter-spacing:-.026em;
  line-height:1.16}
.mq-card .mq-d{font-size:13px;color:var(--steel);line-height:1.5}
.mq-w-s{width:300px}.mq-w-m{width:400px}.mq-w-l{width:520px}
.mq-num{font-family:var(--disp);font-size:2.7rem;font-weight:500;letter-spacing:-.04em;
  line-height:1}
/* tinted variants — colour arrives through the cards, not a background wash */
.mq-card[data-tone="violet"]{background:color-mix(in srgb,var(--violet) 9%,var(--canvas));
  border-color:color-mix(in srgb,var(--violet) 24%,transparent)}
.mq-card[data-tone="amber"]{background:color-mix(in srgb,var(--amber) 10%,var(--canvas));
  border-color:color-mix(in srgb,var(--amber) 26%,transparent)}
.mq-card[data-tone="cyan"]{background:color-mix(in srgb,var(--cyan) 9%,var(--canvas));
  border-color:color-mix(in srgb,var(--cyan) 24%,transparent)}
.mq-card[data-tone="accent"]{background:var(--mape);border-color:transparent;color:#04240f}
.mq-card[data-tone="accent"] .mq-k{color:#04240f;opacity:.62}
.mq-card[data-tone="accent"] .mq-d{color:#04240f;opacity:.8}
.mq-card[data-tone="ink"]{background:var(--night);border-color:var(--night-l);color:var(--night-t)}
.mq-card[data-tone="ink"] .mq-k{color:var(--night-m)}
.mq-card[data-tone="ink"] .mq-d{color:var(--night-m)}
.mq-card.mq-link{text-decoration:none}
.mq-card.mq-link .mq-go{font-size:12.5px;font-weight:600;color:var(--mape-2)}
.mq-card[data-tone="ink"] .mq-go{color:var(--mape)}
@media (prefers-reduced-motion:reduce){
  .mq-view{overflow-x:auto}
  .mq-track{animation:none!important;transform:none!important}
}

/* ==========================================================================
   Footer brand block — the mark was disappearing into the page. Give the
   brand column its own slightly recessed surface so the logo sits ON
   something rather than floating on the canvas.
   ========================================================================== */
/* Unboxed. The bordered panel read as a stray black rectangle in the footer,
   especially in dark theme where the border is the lightest thing in the row. */
.fbrand{align-self:start}
.fbrand .brand{margin-bottom:4px}
.fbrand .mark{width:30px;height:30px}
.fbrand .wordmark{height:19px}
@media(max-width:940px){.fbrand{grid-column:1 / -1}}

/* Marquee palette: the pale-green and cold-blue cards fought each other.
   Reduced to one accent card, dark anchors, and neutral surfaces. */
.mq-card[data-tone="cyan"],.mq-card[data-tone="violet"]{background:var(--canvas);
  border-color:var(--ash)}
.mq-card[data-tone="amber"]{background:var(--wash);
  border-color:color-mix(in srgb,var(--amber) 20%,var(--ash))}
.mq-card[data-tone="violet"] .mq-k{color:var(--violet)}
.mq-card[data-tone="cyan"] .mq-k{color:var(--cyan)}
.mq-card[data-tone="amber"] .mq-k{color:var(--amber)}

/* ==========================================================================
   PINNED STORY — snap each beat into place
   The band spacers are the snap targets. Proximity (not mandatory) means the
   rest of the page is unaffected: with no snap points outside these sections
   the browser has nothing to snap to elsewhere.
   ========================================================================== */
/* Snapping is JS-driven (site.js) — CSS scroll-snap put its targets in a
   different coordinate system to the slide logic, making middle beats bistable. */
.story-bands{position:absolute;inset:0;pointer-events:none;z-index:0}
.story-band{display:block}

/* marquee image card — photography carries the warmth, a dark scrim carries
   the type. The grade is applied to the file; the scrim keeps text legible. */
.mq-card.mq-photo{position:relative;overflow:hidden;border-color:transparent;
  background-size:cover;background-position:center}
.mq-card.mq-photo::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(6,10,8,.34) 0%,rgba(6,10,8,.72) 62%,rgba(6,10,8,.86) 100%)}
.mq-card.mq-photo > *{position:relative;z-index:1;color:#f4f6f5}
.mq-card.mq-photo .mq-k{color:rgba(244,246,245,.66)}
.mq-card.mq-photo .mq-d{color:rgba(244,246,245,.82)}
.mq-card.mq-photo .mq-go{color:var(--mape)}

/* ==========================================================================
   WORK CARDS — each carries a small code-native glimpse of the system rather
   than a block of type. Built from the same primitives as the full mockups so
   the vocabulary stays consistent.
   ========================================================================== */
.wcard{position:relative;overflow:hidden;display:flex;flex-direction:column}
.wshot{margin:16px 0 0;border:1px solid var(--ash);border-radius:var(--r-card);
  background:var(--canvas);overflow:hidden;transition:transform .5s var(--ease),
  border-color .3s var(--ease)}
.wcard:hover .wshot{transform:translateY(-3px);border-color:color-mix(in srgb,var(--mape) 34%,var(--ash))}
.wshot-bar{display:flex;align-items:center;gap:6px;padding:7px 10px;border-bottom:1px solid var(--ash)}
.wshot-bar i{width:5px;height:5px;border-radius:var(--pill);background:var(--ash);display:block}
.wshot-bar span{font-family:var(--mono);font-size:9px;letter-spacing:.06em;color:var(--fog);
  margin-left:4px}
.wshot-body{padding:10px;display:grid;gap:5px}
.wsrow{display:grid;grid-template-columns:1fr auto;gap:10px;align-items:center;
  padding:7px 9px;border:1px solid var(--ash);border-radius:7px;font-size:11.5px}
.wsrow b{font-weight:500}
.wsp{font-family:var(--mono);font-size:8.5px;letter-spacing:.05em;padding:2px 7px;
  border-radius:var(--pill);border:1px solid var(--ash);color:var(--fog)}
.wsp[data-ok="1"]{background:var(--tint);color:var(--tint-ink);border-color:transparent}
.wbars{display:flex;align-items:flex-end;gap:3px;height:26px;padding:2px 9px 0}
.wbars i{flex:1;border-radius:2px;background:var(--ash);display:block}
.wbars i[data-on="1"]{background:var(--mape)}

/* ==========================================================================
   THE FILTER — a decision, not two lists. The "not a fit" side is deliberately
   quieter and struck through; the fit side carries the accent.
   ========================================================================== */
.filter{display:grid;grid-template-columns:1fr auto 1fr;gap:0;margin-top:56px;align-items:stretch}
@media(max-width:900px){.filter{grid-template-columns:1fr}}
.fcol2{border:1px solid var(--ash);border-radius:var(--r-lg);padding:28px 26px;background:var(--canvas)}
.fcol2[data-side="no"]{background:var(--wash)}
.fcol2[data-side="yes"]{border-color:color-mix(in srgb,var(--mape) 40%,var(--ash));
  box-shadow:0 0 0 4px color-mix(in srgb,var(--mape) 9%,transparent)}
.fhead{display:flex;align-items:center;gap:10px;margin-bottom:18px}
.fhead .fk{font-family:var(--mono);font-size:10px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--fog)}
.fcol2[data-side="yes"] .fhead .fk{color:var(--mape-2)}
.fitem{display:flex;gap:12px;align-items:flex-start;padding:13px 0;border-top:1px solid var(--ash)}
.fitem:first-of-type{border-top:0}
.fitem svg{flex:none;margin-top:2px}
.fitem span{font-size:15px;line-height:1.45}
.fcol2[data-side="no"] .fitem span{color:var(--fog);text-decoration:line-through;
  text-decoration-color:color-mix(in srgb,var(--fog) 45%,transparent);text-decoration-thickness:1px}
.fcol2[data-side="yes"] .fitem span{color:var(--charcoal);font-weight:500}
.fvs{display:flex;align-items:center;justify-content:center;padding:0 20px}
.fvs span{font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--fog);writing-mode:vertical-rl;transform:rotate(180deg)}
@media(max-width:900px){.fvs{padding:14px 0}.fvs span{writing-mode:horizontal-tb;transform:none}}
.fclose{margin-top:22px;padding:16px 18px;border-radius:var(--r-card);
  background:color-mix(in srgb,var(--mape) 8%,transparent);
  border:1px solid color-mix(in srgb,var(--mape) 24%,transparent);font-size:14.5px;line-height:1.55}
.fclose b{font-weight:600}

/* ==========================================================================
   STATEMENT BAND — one full-bleed accent moment between the story and the
   proof. The page needs a beat that is loud on purpose.
   ========================================================================== */
.statement{position:relative;color:#eef3f0;overflow:hidden;
  background:linear-gradient(155deg,#0c1410 0%,#0a1a12 46%,#08120e 100%);
  padding:clamp(64px,9vw,128px) 0}
/* The mark is no longer a watermark here. It is presented: a real element to
   the right of the title, at full strength, lit from the upper left so it has
   some material to it. Nothing in the background of this section any more. */
.statement .shell{display:grid;grid-template-columns:minmax(0,1fr) auto;
  gap:clamp(32px,6vw,88px);align-items:start}
.statement .srow{grid-column:1 / -1}
@media(max-width:900px){
  .statement .shell{grid-template-columns:1fr}
  .statement .smark{justify-self:start;margin-top:8px}
}
.statement .smark{width:clamp(150px,17vw,236px);aspect-ratio:1;flex:none;
  position:relative;isolation:isolate;
  /* Sit ~100px from the viewport's right edge rather than at the shell edge.
     The shell stops (100vw - --max)/2 + 32px short of the right, so pull back
     by whatever that exceeds 100px — and never by a negative amount, so on
     narrower screens the mark simply stays inside the shell and nothing can
     overflow. 100svw, not 100vw: vw includes the scrollbar. */
  /* ...then 100px further left again, capped at 7vw so the push cannot eat
     the heading column on narrower screens. */
  margin-right:calc(min(100px, 7vw) - max(0px, (100svw - var(--max)) / 2 + 32px - 100px))}
.statement .smark img{width:100%;height:100%;object-fit:contain;display:block;
  filter:drop-shadow(0 18px 34px rgba(0,0,0,.5))}
/* the shine: a soft highlight raked across the mark from the upper left,
   clipped to the artwork itself so it reads as light on a surface */
.statement .smark::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(128deg,rgba(255,255,255,.52) 0%,rgba(255,255,255,.14) 26%,
    transparent 46%,transparent 100%);
  -webkit-mask-image:var(--mark-url);mask-image:var(--mark-url);
  -webkit-mask-size:contain;mask-size:contain;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-position:center;mask-position:center;
  mix-blend-mode:screen}
/* and a low green bloom behind it, so it sits in the section rather than on it */
.statement .smark::before{content:"";position:absolute;inset:-18%;z-index:-1;
  background:radial-gradient(50% 50% at 50% 50%,
    color-mix(in srgb,var(--mape) 26%,transparent),transparent 70%);
  filter:blur(6px)}
@media (prefers-reduced-motion:reduce){.statement .smark::after{transition:none}}
.statement .shell{position:relative;z-index:1}
.statement .sk{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--mape);opacity:.9;display:block;margin-bottom:22px}
.statement h2{font-size:clamp(2.2rem,5.6vw,4rem);line-height:1.0;letter-spacing:-.04em;
  max-width:17ch;margin:0 0 26px;color:#f4f8f6}
.statement p{font-size:clamp(1.05rem,1.6vw,1.3rem);line-height:1.5;max-width:52ch;
  color:#9fb2a8;margin:0}
/* Each figure gets its OWN short rule above it instead of sitting in a shared
   ruled grid. Before, .si carried padding on the right only and a border on the
   right, so every word started exactly on the previous item's rule and touched
   it — the columns read as a cheap table and the type looked misaligned. Now
   the rule belongs to the item, sits above it, and starts where the word
   starts. Nothing overlaps because nothing shares an edge. */
.statement .srow{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(28px,4vw,64px);
  margin-top:52px}
@media(max-width:760px){.statement .srow{grid-template-columns:1fr;gap:30px}}
.statement .si{padding:20px 0 0;border:0;position:relative}
.statement .si::before{content:"";position:absolute;left:0;top:0;width:34px;height:2px;
  background:var(--mape)}
.statement .si::after{content:"";position:absolute;left:34px;right:0;top:0;height:1px;
  background:rgba(160,200,180,.16)}
.statement .si b{display:block;font-family:var(--disp);font-size:1.7rem;font-weight:500;
  letter-spacing:-.03em;margin-bottom:6px;color:var(--mape)}
.statement .si span{font-size:13.5px;color:#9fb2a8;line-height:1.5}
@media(max-width:760px){.statement .si{padding-right:0}}

/* ==========================================================================
   FLAIR BELOW THE PIN
   Motion that carries meaning: figures that count, cards that lift toward the
   cursor, section heads that arrive with their rule, and an asymmetric offset
   so the lower half stops reading as a stack of equal boxes.
   ========================================================================== */

/* counters */
.pi .n[data-count]{font-variant-numeric:tabular-nums}

/* work + feature cards: lift and tilt very slightly toward the pointer */
.g3c,.wcard,.mq-card,.ccard,.person{transition:transform .45s var(--ease),
  border-color .3s var(--ease),box-shadow .45s var(--ease)}
.g3c:hover,.ccard:hover,.person:hover{transform:translateY(-4px);
  border-color:color-mix(in srgb,var(--mape) 32%,var(--ash));
  box-shadow:0 18px 40px -26px rgba(10,14,11,.4)}
.wcard:hover{transform:translateY(-5px);
  border-color:color-mix(in srgb,var(--mape) 40%,var(--ash));
  box-shadow:0 22px 50px -28px rgba(10,14,11,.45)}

/* the accent rule under an eyebrow now sweeps rather than appearing */
.eyebrow::after{transition:width .9s cubic-bezier(.16,1,.3,1)}

/* stagger cards in a grid so a section arrives rather than snapping on */
.grid3 > *,.work > *,.fgrid > *,.team > *,.cgrid > *{transition-delay:var(--d,0ms)}
.grid3 > *:nth-child(2),.work > *:nth-child(2),.fgrid > *:nth-child(2),
.team > *:nth-child(2),.cgrid > *:nth-child(2){--d:70ms}
.grid3 > *:nth-child(3),.work > *:nth-child(3),.cgrid > *:nth-child(3){--d:140ms}
.grid3 > *:nth-child(4),.cgrid > *:nth-child(4){--d:210ms}
.grid3 > *:nth-child(5){--d:280ms}
.grid3 > *:nth-child(6){--d:350ms}

/* asymmetry: alternate sections pull their heading off the grid */
section.band .head.mid{position:relative}
section.band .head.mid::before{content:"";position:absolute;left:50%;top:-26px;
  translate:-50% 0;width:34px;height:2px;border-radius:2px;background:var(--mape);
  opacity:0;transition:opacity .6s var(--ease),width .8s var(--ease)}
section.band .head.mid[data-seen="1"]::before{opacity:1;width:64px}

/* the work grid becomes deliberately uneven */
@media(min-width:1000px){
  .work{grid-template-columns:1.25fr .95fr .95fr}
  .work > *:first-child{grid-row:span 1}
}

/* quote gets a mark behind it instead of sitting on nothing */
/* No mark behind the quote. This one sat directly under the words and, stacked
   with the field mark, put two logos behind a single pull-quote. The band's
   green halo carries the atmosphere on its own now. */
.quote{position:relative}

@media (prefers-reduced-motion:reduce){
  .g3c,.wcard,.mq-card,.ccard,.person{transition:none}
  .g3c:hover,.ccard:hover,.person:hover,.wcard:hover{transform:none}
  .grid3 > *,.work > *,.fgrid > *,.team > *,.cgrid > *{transition-delay:0ms}
  section.band .head.mid::before{opacity:1;width:64px;transition:none}
}

/* One halo per beat, in beat order. The gradients themselves never change —
   only which layer is opaque — which is the whole point (see .story-wash).
   Consecutive beats never share a position, so the cross-dissolve reads as
   the halo travelling rather than one blob dying and another being born.
   Eleven, because the homepage story is the whole engagement; the three-beat
   stories on /security/ and /suite/ use the first three. */
.story-wash > i:nth-child(1){background:
  radial-gradient(52% 44% at 18% 16%, color-mix(in srgb,var(--violet) 16%,transparent), transparent 72%)}
.story-wash > i:nth-child(2){background:
  radial-gradient(52% 44% at 82% 20%, color-mix(in srgb,var(--cyan) 16%,transparent), transparent 72%)}
.story-wash > i:nth-child(3){background:
  radial-gradient(56% 46% at 24% 78%, color-mix(in srgb,var(--amber) 15%,transparent), transparent 74%)}
.story-wash > i:nth-child(4){background:
  radial-gradient(54% 46% at 76% 74%, color-mix(in srgb,var(--mape) 15%,transparent), transparent 74%)}
.story-wash > i:nth-child(5){background:
  radial-gradient(50% 42% at 50% 12%, color-mix(in srgb,var(--rose) 13%,transparent), transparent 72%)}
.story-wash > i:nth-child(6){background:
  radial-gradient(54% 44% at 14% 46%, color-mix(in srgb,var(--cyan) 15%,transparent), transparent 73%)}
.story-wash > i:nth-child(7){background:
  radial-gradient(52% 46% at 86% 52%, color-mix(in srgb,var(--violet) 15%,transparent), transparent 73%)}
.story-wash > i:nth-child(8){background:
  radial-gradient(56% 44% at 34% 18%, color-mix(in srgb,var(--mape) 14%,transparent), transparent 74%)}
.story-wash > i:nth-child(9){background:
  radial-gradient(52% 44% at 70% 84%, color-mix(in srgb,var(--amber) 14%,transparent), transparent 73%)}
.story-wash > i:nth-child(10){background:
  radial-gradient(50% 44% at 22% 60%, color-mix(in srgb,var(--rose) 13%,transparent), transparent 72%)}
.story-wash > i:nth-child(11){background:
  radial-gradient(58% 48% at 50% 86%, color-mix(in srgb,var(--mape) 17%,transparent), transparent 74%)}

/* ==========================================================================
   CASE REEL — a tilted, continuously drifting band of case creatives.
   Greyscale at rest so the row reads as one material; full colour on hover,
   which makes the hovered card the only thing in the room.
   ========================================================================== */
.reel{position:relative;padding:0;overflow:hidden;background:var(--wash);
  border-top:1px solid var(--ash);border-bottom:1px solid var(--ash)}
.reel-head{max-width:var(--max);margin:0 auto;padding:72px 32px 0}
.reel-hint{font-family:var(--mono);font-size:10.5px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--fog);margin-top:20px;display:flex;
  align-items:center;gap:9px}
.reel-hint::before{content:"";width:26px;height:1px;background:var(--mape);flex:none}
@media(max-width:640px){.reel-head{padding:52px 20px 0}}
/* touch-action:pan-y hands vertical scrolling back to the page: without it the
   drag handler swallows the gesture and the reel traps the reader on mobile. */
.reel-view{overflow:hidden;padding:52px 0 78px;cursor:grab;touch-action:pan-y;
  --tilt:-3.8deg}
.reel-view[data-drag="1"]{cursor:grabbing;user-select:none;-webkit-user-select:none}
/* belt-and-braces with the dragstart handler in site.js */
.reel-card,.reel-card .shot{-webkit-user-drag:none;user-drag:none}
/* transform-origin is pinned to the middle of the VIEWPORT, not of the track.
   The track is far wider than the screen, so its own centre sits well off to
   the side; rotating about that pivot swings the visible band vertically out
   of the padding that was reserved for it — and would swing it further every
   time a card is added. Pinning to 50vw makes the band's vertical placement
   independent of how long the row is. */
.reel-track{display:flex;gap:26px;width:max-content;will-change:transform;
  transform:rotate(var(--tilt));transform-origin:50vw 50%;padding:26px 0}
/* --c is a small per-card scatter set inline by the generator, so the row reads
   as a laid-down stack rather than one rigid plank. */
.reel-card{flex:none;width:300px;position:relative;text-decoration:none;display:block;
  border-radius:var(--r-lg);overflow:hidden;background:var(--night);
  border:1px solid var(--ash);rotate:var(--c,0deg);
  transition:transform .5s var(--ease),rotate .5s var(--ease),
             box-shadow .5s var(--ease),border-color .4s var(--ease)}
.reel-card .shot{display:block;width:100%;height:auto;aspect-ratio:4/5;object-fit:cover;
  filter:grayscale(1) contrast(1.06) brightness(.82);
  transition:filter .55s var(--ease),transform .8s var(--ease)}
/* Hover levels the card exactly square to the page — it cancels both the track
   tilt and its own scatter — so the one card you are looking at is upright
   while the rest of the row stays laid down. */
.reel-card:hover,.reel-card:focus-visible{
  transform:translateY(-12px) rotate(calc(-1 * var(--tilt))) scale(1.03);
  rotate:0deg;z-index:3;   /* NOT -c: own rotation must be exactly -tilt to
                              cancel the track, so the scatter is dropped */
  border-color:color-mix(in srgb,var(--mape) 46%,transparent);
  box-shadow:0 30px 60px -30px rgba(6,12,8,.65)}
.reel-card:focus-visible{outline:2px solid var(--mape-2);outline-offset:3px}
.reel-card:hover .shot,.reel-card:focus-visible .shot{filter:none;transform:scale(1.05)}
.reel-meta{position:absolute;left:0;right:0;bottom:0;padding:18px 18px 16px;
  background:linear-gradient(180deg,transparent,rgba(5,10,7,.86) 52%);color:#f2f6f3}
.reel-sector{font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;
  color:rgba(242,246,243,.66);display:block;margin-bottom:7px}
.reel-t{font-family:var(--disp);font-size:1.05rem;font-weight:500;letter-spacing:-.02em;
  line-height:1.22;display:block}
.reel-metric{display:block;margin-top:9px;font-size:12px;color:var(--mape);opacity:0;
  transform:translateY(5px);transition:opacity .4s var(--ease),transform .4s var(--ease)}
.reel-card:hover .reel-metric,.reel-card:focus-visible .reel-metric{opacity:1;transform:none}
/* Inside .reel-view, not the section. As a child of .reel these spanned
   top:0 to bottom:0 of the WHOLE section at z-index 4 — so the 120px gradient
   was painting over the left and right of the heading and lead as well, which
   is why the first word of each line read washed out. */
.reel-view{position:relative}
.reel-fade{position:absolute;top:0;bottom:0;width:120px;z-index:4;pointer-events:none}
.reel-fade.l{left:0;background:linear-gradient(90deg,var(--wash),transparent)}
.reel-fade.r{right:0;background:linear-gradient(270deg,var(--wash),transparent)}
@media(max-width:700px){.reel-card{width:230px}.reel-view{--tilt:-2.4deg}}
@media (prefers-reduced-motion:reduce){
  .reel-view{overflow-x:auto}
  .reel-track{transform:none;animation:none!important}
  .reel-card .shot{filter:none}
}

/* ==========================================================================
   CASE STUDY — art hero, outcomes before the story, and an honest section
   about what was hard. A case study has to argue, not just recount.
   ========================================================================== */
.csHero{position:relative;padding:132px 0 64px;overflow:hidden;isolation:isolate;
  background:var(--night)}
.csArt{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:-2;
  opacity:.55}
.csScrim{position:absolute;inset:0;z-index:-1;
  background:linear-gradient(180deg,rgba(6,10,8,.62) 0%,rgba(6,10,8,.80) 55%,rgba(6,10,8,.94) 100%)}
.csHero .crumb,.csHero .crumb a{color:rgba(240,246,242,.62)}
.csHero .crumb a:hover{color:#fff}
.csHero h1{color:#f4f8f6;max-width:20ch}
.csHero .lead{color:#b9c7c0;max-width:58ch}
.csHero .chipx{border-color:rgba(240,246,242,.24);color:rgba(240,246,242,.78)}

.csOutcomes{background:var(--night);border-bottom:1px solid var(--night-l)}
.coRow{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:0}
.co{padding:26px 26px 26px 0;border-right:1px solid rgba(240,246,242,.14);
  display:flex;flex-direction:column;justify-content:flex-start}
.co:last-child{border-right:0}
.co b{display:block;font-family:var(--disp);font-size:clamp(1.5rem,2.4vw,2.1rem);font-weight:500;
  letter-spacing:-.032em;color:var(--mape);margin-bottom:8px;line-height:1.05}
.co span{font-size:13.5px;color:#9fb2a8;line-height:1.5}
@media(max-width:760px){.co{border-right:0;border-bottom:1px solid rgba(240,246,242,.14);
  padding:20px 0}.co:last-child{border-bottom:0}}

.csHard .hdGrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px;
  margin-top:44px}
.hd{border:1px solid var(--ash);border-left:2px solid var(--amber);border-radius:var(--r-lg);
  padding:26px 24px;background:var(--canvas)}
.hd h3{font-size:1.02rem;margin-bottom:10px}
.hd p{font-size:14.5px;color:var(--steel);line-height:1.6;margin:0}
.csWhy{margin-top:32px;padding:26px 28px;border-radius:var(--r-lg);
  background:color-mix(in srgb,var(--mape) 8%,transparent);
  border:1px solid color-mix(in srgb,var(--mape) 26%,transparent)}
.csWhy .mono{display:block;margin-bottom:10px;color:var(--mape-2);font-size:10px;
  letter-spacing:.14em;text-transform:uppercase}
.csWhy p{font-size:1.06rem;line-height:1.6;margin:0;color:var(--charcoal);max-width:66ch}

/* ==========================================================================
   PIN STATES
   Slides only become absolute while ScrollTrigger is actually pinning; below
   the gate they lay out normally and stack, which is what the fallback path
   depends on.
   ========================================================================== */
.story .slides{position:relative}
.story.is-pinning .slides{position:relative;min-height:inherit}
/* ...but the art column sets its own floor. The rule above is more specific
   than .story-art .slides and lands later in the file, so it was resetting the
   card back to its natural ~338px against ~600px of copy — which is what left
   the bottom right of the section empty. */
.story.is-pinning .story-art .slides{min-height:340px}
.story.is-pinning .slide{position:absolute;inset:0;opacity:0;pointer-events:none;
  transition:opacity 250ms cubic-bezier(.4,0,.2,1)}
.story.is-pinning .slide[data-on="1"]{opacity:1;pointer-events:auto}

/* not pinning: every beat is visible and stacks */
.story:not(.is-pinning) .story-pin{display:block;min-height:0;padding:0}
.story:not(.is-pinning) .story-in{grid-template-columns:1fr;gap:26px}
.story:not(.is-pinning) .slide{position:static;opacity:1;margin-bottom:34px}
.story:not(.is-pinning) .rail{display:none}

/* PINNING — one halo fills the whole band and only its opacity moves. The LAST
   halo's box runs --story-bleed PAST the section's bottom edge and is masked to
   nothing there, so the same gradient continues into the next section rather
   than being cut off at a border. One gradient continuing, not a second blob
   butted against the first, so there is no brightness step and no line. The
   masked element is a leaf and a sibling of .story-track — never an ancestor
   of .story-pin. */
.story.is-pinning .story-wash > i{top:0;bottom:0;height:auto;
  -webkit-mask-image:none;mask-image:none}
.story.is-pinning .story-wash > i:last-child{
  bottom:calc(var(--story-bleed) * -1);
  -webkit-mask-image:linear-gradient(180deg,#000 0%,
    #000 calc(100% - var(--story-bleed) * 2.1),
    rgba(0,0,0,.58) calc(100% - var(--story-bleed) * 1.05),
    transparent 100%);
  mask-image:linear-gradient(180deg,#000 0%,
    #000 calc(100% - var(--story-bleed) * 2.1),
    rgba(0,0,0,.58) calc(100% - var(--story-bleed) * 1.05),
    transparent 100%)}
@supports not ((mask-image:linear-gradient(#000,#000)) or (-webkit-mask-image:linear-gradient(#000,#000))){
  .story.is-pinning .story-wash > i:last-child{bottom:0}
}

/* NOT PINNING (below 1024px, reduced motion, or GSAP absent) — the beats are a
   stack, so the halos become a column: one behind each beat, each fading into
   the next, the last running past the bottom. Same hand-off, no scrub. */
.story:not(.is-pinning) .story-wash > i{opacity:1;bottom:auto;
  top:calc(var(--i) * 100% / var(--n));height:calc(150% / var(--n));
  -webkit-mask-image:linear-gradient(180deg,transparent 0%,#000 20%,#000 62%,transparent 100%);
  mask-image:linear-gradient(180deg,transparent 0%,#000 20%,#000 62%,transparent 100%)}

/* The closing halo paints over the top of whatever follows the story, so that
   section has to sit above it. NOTE: this matches a direct sibling <section>
   only — a wrapper <div> after a story would need the same treatment. */
.story + section{position:relative;z-index:1}
/* Below the pin threshold the track is the wrong shape: one shared copy block
   driven by a scrub that never runs, and six mockups stacked inside a clipped
   400px window. The fallback stack is what phones get, and build.py now
   derives it from these same six beats so the two cannot say different things.
   1023px matches the gsap.matchMedia() query in site.js exactly — a gap
   between the two leaves a width with neither. */
@media(max-width:1023px){
  .story-track{display:none}
  .story-fallback{display:block}
}

/* ==========================================================================
   ONE CONTINUOUS FIELD
   The tilted reel sat between hard-ruled sections, which framed it like a box
   and fought the tilt. Security, the reel and the testimonial now share a
   gradient field with no rules between them, and a very large mark drifts
   behind the whole run to tie it together.
   ========================================================================== */
/* overflow:hidden is safe here — the field wraps security, the reel and the
   testimonial, and deliberately NOT the pinned story, so it cannot disable
   ScrollTrigger's pinning the way an overflow ancestor would. */
.field{position:relative;isolation:isolate;overflow:hidden;
  background:linear-gradient(180deg,
    var(--canvas) 0%,
    var(--wash) 14%,
    var(--wash) 62%,
    var(--canvas) 100%)}
.field > section,.field > .reel{background:transparent!important;
  border-top:0!important;border-bottom:0!important}
.field .reel-fade.l{background:linear-gradient(90deg,var(--wash),transparent)}
.field .reel-fade.r{background:linear-gradient(270deg,var(--wash),transparent)}
/* ONE mark in the field, and it belongs to "what we have built". Offset from the
   TOP in px rather than a percentage of the field: the field's height changes
   with the copy and the viewport, and a percentage let the mark drift down until
   it ghosted straight through the testimonial quote. 800px + its own 880px
   height lands it over the reel and stops it short of the last band. */
.field::before{content:"";position:absolute;left:-14%;top:800px;width:min(880px,72vw);
  aspect-ratio:1;background:var(--mark-url) center/contain no-repeat;
  opacity:.05;filter:grayscale(1);pointer-events:none;z-index:-1}
html[data-theme="dark"] .field::before{opacity:.07;filter:none}

/* The testimonial gets a green halo instead of a logo. Two marks stacked behind
   a pull-quote was overkill and the large one sat directly behind the words. */
.field > section:last-child{position:relative}
.field > section:last-child::before{content:"";position:absolute;inset:0;
  pointer-events:none;z-index:-1;background:radial-gradient(44% 54% at 50% 44%,
    color-mix(in srgb,var(--mape) 13%,transparent), transparent 70%)}
html[data-theme="dark"] .field > section:last-child::before{
  background:radial-gradient(44% 54% at 50% 44%,
    color-mix(in srgb,var(--mape) 17%,transparent), transparent 70%)}
