/* ═══════════════════════════════════════════════════════════════════
   'corePHP' v6 — components
   Everything luminous from v3 became structural here: glows are
   hairlines, additive blend is multiply, white borders are --line.
   ═══════════════════════════════════════════════════════════════════ */

/* ── Buttons ────────────────────────────────────────────────────── */
.btn{
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 15px 28px; border-radius: var(--r-pill);
  font-family: var(--f-display); font-size: .8125rem; font-weight: 800;
  letter-spacing: .07em; text-transform: uppercase; white-space: nowrap;
  transition: transform .2s var(--ease-snap), box-shadow .2s var(--ease-snap),
              background .25s var(--ease-out), color .25s var(--ease-out), border-color .25s var(--ease-out);
}
.btn--primary{ background: var(--brand); color: #fff; box-shadow: 0 3px 0 0 var(--brand-deep), 0 12px 26px -12px rgba(20,16,15,.5); }
.btn--primary:hover{ background: var(--brand-deep); transform: translateY(-2px); box-shadow: 0 5px 0 0 var(--brand-shadow), 0 20px 38px -14px rgba(20,16,15,.55); }
.btn--primary:active{ transform: translateY(1px); box-shadow: 0 1px 0 0 var(--brand-deep); }
.btn--ghost{ background: transparent; color: var(--ink-1); border: 1px solid var(--line); }
.btn--ghost:hover{ border-color: var(--brand); color: var(--brand); }
.btn svg{ width: 15px; height: 15px; }

/* ── Chips ──────────────────────────────────────────────────────── */
.chips{ display: flex; flex-wrap: wrap; gap: 8px; }
.chip{
  display: inline-flex; align-items: center; padding: 7px 14px;
  border: 1px solid var(--line); border-radius: var(--r-pill);
  font-family: var(--f-body); font-size: .8125rem; font-weight: 500;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-2);
  background: var(--paper);
}
a.chip:hover{ border-color: var(--brand); color: var(--brand); }
.chip--solid{ background: var(--brand-wash); border-color: var(--brand-hair); color: var(--brand); }

/* ── Cards ──────────────────────────────────────────────────────── */
.card{
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: clamp(22px, 2.6vw, 32px); min-width: 0;
  transition: border-color .25s var(--ease-out), transform .25s var(--ease-out), box-shadow .25s var(--ease-out);
}
a.card:hover, .card--hover:hover{
  border-color: var(--brand-hair); transform: translateY(-3px);
  box-shadow: 0 26px 50px -34px rgba(20,16,15,.5);
}
.card__n{ font-family: var(--f-body); font-size: .8125rem; font-weight: 600; letter-spacing: .085em; color: var(--brand); }
.card h3{ margin-top: 10px; }
.card p{ margin-top: 10px; color: var(--ink-2); }
/* The card CTAs were uppercase text with no edge, sitting wherever the copy
   above them happened to end, so the three cards' actions landed at three
   different heights and none of them read as pressable. The card is a flex
   column now and the action is pushed to its floor. */
.card{ display: flex; flex-direction: column; }
.card > p{ flex: 1 1 auto; }
.card__go{
  align-self: flex-start; display: inline-flex; align-items: center; gap: 9px;
  margin-top: 22px; padding: 11px 18px;
  border: 1px solid var(--line); border-radius: var(--r-pill);
  font-family: var(--f-body); font-size: .8125rem; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--brand);
  transition: gap .22s var(--ease-snap), border-color .22s var(--ease-out),
              background .22s var(--ease-out);
}
.card__go svg{ width: 15px; height: 15px; flex: none; }
.card__go:hover{ gap: 13px; border-color: var(--brand); background: var(--brand-wash); }
a.card:hover .card__go{ gap: 12px; }

/* ── Section heading block ──────────────────────────────────────── */
.shead{ display: grid; gap: 18px; }
.shead__n{ font-family: var(--f-body); font-size: .75rem; font-weight: 600; letter-spacing: .085em; text-transform: uppercase; color: var(--brand); }
@media (min-width: 900px){
  /* Top-aligned, and the headline is sized for a half-width column
     rather than a full-width one. align-items:end sank the deck to the
     foot of a seven line headline and left the top right of the section
     empty; the h2 was also still running at full section scale inside a
     column half as wide, which is what made it seven lines. */
  .shead--split{ grid-template-columns: minmax(0,1.15fr) minmax(0,.85fr); gap: clamp(28px,4vw,64px); align-items: start; }
  .shead--split h2{ font-size: clamp(2rem, 3.3vw, 3.15rem); }
  .shead--split .lead{ margin-top: .35rem; }
}

/* ── Stats ──────────────────────────────────────────────────────── */
.stats{ display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: clamp(18px,3vw,40px); }
@media (max-width: 860px){ .stats{ grid-template-columns: repeat(2, minmax(0,1fr)); } }
.stat__n{ font-family: var(--f-display); font-weight: 900; font-size: clamp(2.5rem, 5vw, 4rem); line-height: 1; letter-spacing: -.04em; color: var(--ink-1); font-variant-numeric: tabular-nums; }
.stat__n .suf{ color: var(--brand); }
.stat__l{ margin-top: 8px; font-family: var(--f-body); font-size: .8125rem; font-weight: 500; letter-spacing: .075em; text-transform: uppercase; color: var(--ink-3); }

/* ── Breadcrumb ─────────────────────────────────────────────────── */
.crumb{ display: flex; flex-wrap: wrap; align-items: center; gap: 9px; font-family: var(--f-body); font-size: .8rem; font-weight: 500; letter-spacing: .075em; text-transform: uppercase; color: var(--ink-3); }
.crumb a{ color: var(--ink-3); }
.crumb a:hover{ color: var(--brand); }
.crumb .sep{ opacity: .5; }
.crumb .here{ color: var(--brand); }

/* ── Checklist ──────────────────────────────────────────────────── */
/* The attribute means do not render this, so it has to beat a component's
   own display. .fset sets display:grid and won it, which is why step 2 of
   the intake form drew as an empty grey panel with the hidden attribute
   still on it. Two components had already patched this one at a time
   (.hero-alt[hidden], .tterm[hidden]) rather than fixing it once. */
[hidden]{ display: none !important; }

.ticks{ display: grid; gap: 12px; margin: 0; padding: 0; list-style: none; }
.ticks li{ display: flex; align-items: flex-start; gap: 12px; line-height: 1.55; color: var(--ink-2); }
/* A rotated square repeated down a list is a bullet wearing a costume.
   A short rule reads as structure and matches the section heads. */
.ticks li::before{
  content: ""; flex: none; width: 14px; height: 2px; margin-top: 11px;
  background: var(--brand); border-radius: 2px;
}
.ticks li b{ color: var(--ink-1); font-weight: 600; }

/* ── Page hero ──────────────────────────────────────────────────── */
/* The pennant is 130px tall and hangs over the page, so the first line
   of content has to clear it even on a short viewport. */
.phero{ padding-top: calc(var(--pennant-h) + clamp(26px, 3vh, 42px)); padding-bottom: clamp(24px, 3vh, 44px); position: relative; }
.phero__in{ display: grid; gap: 22px; }
.phero h1{ margin-top: 6px; }
.phero .lead{ max-width: 62ch; }
.phero__cta{ display: flex; flex-wrap: wrap; gap: 12px; margin-top: 10px; }
[id]{ scroll-margin-top: calc(var(--flag-h) + 18px); }

/* ── Domain capture ─────────────────────────────────────────────── */
.capture{ display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.capture input{
  flex: 1 1 260px; min-width: 0; padding: 15px 20px;
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--paper); color: var(--ink-1); font-family: var(--f-body); font-size: 1rem;
  transition: border-color .2s var(--ease-out);
}
.capture input::placeholder{ color: var(--ink-3); }
.capture input:focus{ border-color: var(--brand); outline: none; }
.capture__note{ margin-top: 14px; font-size: .9rem; color: var(--ink-3); max-width: 56ch; }

/* ── FAQ ────────────────────────────────────────────────────────── */
.faq{ border-top: 1px solid var(--line); }
.faq details{ border-bottom: 1px solid var(--line); }
/* The card carries its own edge, so the last row's rule drew a line
   floating above the bottom padding with nothing under it. Rules separate
   rows; they do not close the box. */
.faq details:last-child{ border-bottom: 0; }
.faq summary{
  display: flex; align-items: flex-start; justify-content: space-between; gap: 20px;
  padding: 20px 0; cursor: pointer; list-style: none;
  font-family: var(--f-display); font-weight: 700; font-size: 1.0625rem; color: var(--ink-1);
}
.faq summary::-webkit-details-marker{ display: none; }
.faq summary::after{ content: "+"; flex: none; font-family: var(--f-body); font-size: 1.3rem; line-height: 1; color: var(--brand); transition: transform .25s var(--ease-snap); }
.faq details[open] summary::after{ transform: rotate(45deg); }
.faq details p{ padding: 0 0 22px; color: var(--ink-2); max-width: 68ch; }

/* ── Process strip ──────────────────────────────────────────────── */
.steps{ display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; }
@media (max-width: 760px){ .steps{ grid-template-columns: repeat(2, minmax(0,1fr)); } }
.steps > div{ background: var(--paper); padding: 22px; }
.steps b{ display: block; font-family: var(--f-body); font-size: .8rem; letter-spacing: .085em; color: var(--brand); font-weight: 600; }
.steps strong{ display: block; margin-top: 8px; font-family: var(--f-display); font-weight: 700; font-size: 1.05rem; color: var(--ink-1); }
.steps p{ margin-top: 6px; font-size: .9rem; color: var(--ink-3); }

/* ── Logo wall ──────────────────────────────────────────────────── */
.logos{ display: flex; flex-wrap: wrap; align-items: center; gap: clamp(24px, 5vw, 64px); }
.logos span{ font-family: var(--f-display); font-weight: 800; font-size: clamp(1rem,1.6vw,1.3rem); letter-spacing: -.01em; color: var(--ink-3); opacity: .8; }

/* ── Footer ─────────────────────────────────────────────────────── */
.foot{ background: var(--paper-2); border-top: 1px solid var(--line); padding-block: clamp(48px,7vh,86px) 28px; }
.foot__top{ display: grid; gap: clamp(28px,4vw,48px); grid-template-columns: minmax(0,1.4fr) repeat(3, minmax(0,1fr)); }

/* The three footer columns used to be three sibling <nav> elements, which put
   five landmarks in a screen reader's list on every page. Collapsing them into
   one <nav> fixed that and broke the layout: .foot__top is a four-column grid
   that was counting on three nav children, so all three columns landed in one
   cell. The wrapper spans those three columns and lays them out itself. */
.foot__top > nav{
  grid-column: span 3;
  display: grid; gap: inherit;
  grid-template-columns: repeat(3, minmax(0,1fr));
  min-width: 0;
}
.foot__top > nav > .foot__col{ min-width: 0; }
@media (max-width: 900px){
  .foot__top > nav{ grid-column: span 2; grid-template-columns: repeat(2, minmax(0,1fr)); }
}
@media (max-width: 560px){
  .foot__top > nav{ grid-column: span 1; grid-template-columns: minmax(0,1fr); }
}
@media (max-width: 980px){ .foot__top{ grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 560px){ .foot__top{ grid-template-columns: minmax(0,1fr); } }
/* On a phone the footer sitemap is a second copy of the menu: 20 of its 22
   links are already in the nav sheet, which is pinned to the top of every
   screen. Stacked in one column it ran 1313px, 1.9 screens, and buried the
   things people actually reach a footer for. Hidden rather than removed, so
   the links stay in the document. The contact pair is promoted into the
   first column, since the phone and email live inside the Company block. */
.foot__contact{ display: none; }
.foot__more{ display: none; }
@media (max-width: 560px){
  .foot__top nav{ display: none; }
  .foot.is-open .foot__top nav{ display: block; }
  .foot__contact{ display: grid; gap: 9px; margin-top: 24px; }
  .foot__contact a{ font-size: 1rem; color: var(--ink-2); }
  /* The sitemap is collapsed, not gone, so there has to be a way back to
     it. One control, not three: the whole map opens at once. */
  .foot__more{
    display: inline-flex; align-items: center; gap: 9px;
    margin-top: 22px; padding: 11px 17px;
    border: 1px solid var(--line); border-radius: 999px;
    background: transparent; color: var(--ink-2); cursor: pointer;
    font-family: var(--f-body); font-size: .78rem; font-weight: 700;
    letter-spacing: .1em; text-transform: uppercase;
  }
  .foot__more::after{
    content: ""; width: 7px; height: 7px; border-right: 1.6px solid currentColor;
    border-bottom: 1.6px solid currentColor; transform: translateY(-2px) rotate(45deg);
    transition: transform .25s var(--ease-out);
  }
  .foot.is-open .foot__more::after{ transform: translateY(1px) rotate(225deg); }
}
.foot h2{ font-variation-settings: normal; line-height: 1.35; font-family: var(--f-body); font-size: .8rem; font-weight: 600; letter-spacing: .085em; text-transform: uppercase; color: var(--brand); margin-bottom: 14px; }
.foot__links{ display: grid; gap: 9px; }
.foot__links a{ font-size: .92rem; color: var(--ink-2); }
.foot__links a:hover{ color: var(--brand); }
.foot__mark img{ width: 150px; }
.foot__belief{ margin-top: 16px; max-width: 34ch; font-size: .92rem; color: var(--ink-3); }
.foot__legal{ margin-top: clamp(34px,5vh,56px); padding-top: 22px; border-top: 1px solid var(--line); display: flex; flex-wrap: wrap; gap: 6px 14px; font-family: var(--f-body); font-size: .8rem; letter-spacing: .06em; color: var(--ink-3); }

/* ── Canvas set pieces ──────────────────────────────────────────── */
.stage{ position: relative; width: 100%; }
.stage canvas{ display: block; width: 100%; height: 100%; }
.stage__poster{ position: absolute; inset: 0; display: grid; place-items: center; }
.hero-core{ position: relative; aspect-ratio: 1 / 1; max-width: 560px; margin-inline: auto; width: 100%; }

/* ── Live-site preview cards ────────────────────────────────────── */
.live{ position: relative; border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; background: var(--paper-3); transform-style: preserve-3d; transition: transform .3s var(--ease-out), border-color .25s var(--ease-out), box-shadow .3s var(--ease-out); }
.live:hover{ border-color: var(--brand-hair); box-shadow: 0 34px 60px -38px rgba(20,16,15,.55); }
.live__chrome{ display: flex; align-items: center; gap: 7px; padding: 11px 14px; border-bottom: 1px solid var(--line); background: var(--paper-2); }
.live__chrome i{ width: 9px; height: 9px; border-radius: 50%; background: var(--line); display: block; }
.live__url{ margin-left: 8px; font-family: var(--f-body); font-size: .78rem; letter-spacing: .04em; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.live__view{ position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: var(--paper-3); }
.live__view img{ width: 100%; height: 100%; object-fit: cover; object-position: 50% 0; display: block; }
.live__view iframe{ position: absolute; top: 0; left: 0; width: 1440px; height: 900px; border: 0; transform-origin: 0 0; pointer-events: none; }
.live__meta{ padding: 16px 18px 20px; }
.live__meta b{ display: block; font-family: var(--f-display); font-weight: 800; font-size: 1.05rem; color: var(--ink-1); }
.live__meta span{ display: block; margin-top: 4px; font-size: .88rem; color: var(--ink-3); }

/* ── Node graph ─────────────────────────────────────────────────── */
.nodes{ position: relative; display: grid; gap: 10px; }
.node{ position: relative; display: flex; align-items: center; gap: 14px; padding: 15px 18px; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--paper); transition: border-color .25s var(--ease-out), background .25s var(--ease-out); }
.node:hover, .node.is-lit{ border-color: var(--brand); background: var(--brand-wash); }
.node__i{ font-family: var(--f-body); font-size: .8rem; font-weight: 600; letter-spacing: .07em; color: var(--brand); flex: none; }
.node__t{ font-family: var(--f-display); font-weight: 700; font-size: 1rem; color: var(--ink-1); }
.node__d{ font-size: .84rem; color: var(--ink-3); }

/* ── Utility ────────────────────────────────────────────────────── */
.flow > * + *{ margin-top: 18px; }
.hr-brand{ width: 56px; height: 3px; background: var(--brand); border: 0; border-radius: 2px; }

/* The CTA card sits in its own section, so it inherits a full section's padding
   on top of the one above it: 180px of empty ground with nothing to say the
   page has changed subject. A hairline is the site's own separator idiom, the
   same one .section--band draws. Selected with :has() rather than a class on
   every page, because the pattern repeats across the byCORE and case study
   pages and a modifier would have to be added to each. Bands already draw
   their own rule, so they are excluded to avoid doubling it. */
.section:not(.section--band):has(> .wrap > .ctab){
  box-shadow: inset 0 1px 0 var(--line);
}

/* ── B1 · The Handover ──────────────────────────────────────────────
   A tall section whose canvas is sticky. The browser does the
   scrolling; we only read progress off the bounding rect. */
/* Its own ground. On the light side this ran on --ground, the same ivory
   as the enterprise section directly above it, so the two read as one
   undifferentiated block. Left transparent in red mode, where painting it
   opaque would cut the ambient rain out of a 340vh stretch of page. */
.handover{ position: relative; height: 340vh; background: var(--paper); }
:root[data-pill="red"] .handover{ background: transparent; }
.handover__sticky{ position: sticky; top: 0; height: 100vh; display: grid; align-content: center; overflow: hidden; }
.handover__grid{ display: grid; gap: clamp(20px,3vw,44px); align-items: center; }
@media (min-width: 1000px){ .handover__grid{ grid-template-columns: minmax(0,.85fr) minmax(0,1.15fr); } }
/* Four discrete states sharing one grid cell, so the stage is as tall as
   its tallest state. With a fixed aspect-ratio the stage set the height
   and the transfer state overflowed it, clipping its own closing line. */
.handover__stage{
  display: grid; width: 100%; min-height: clamp(300px, 28vw, 440px); max-height: 66vh;
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--paper); box-shadow: var(--lift-2); overflow: hidden;
}
.hst{
  grid-area: 1/1; display: flex; flex-direction: column; min-width: 0;
  opacity: 0; transform: translateY(var(--hst-shift, 18px)) scale(.99); pointer-events: none;
  transition: opacity var(--hst-dur, 620ms) var(--ease-snap),
              transform var(--hst-dur, 620ms) var(--ease-snap);
}
.hst[data-on]{ opacity: 1; transform: none; pointer-events: auto; }
.hst__bar{
  flex: none; display: flex; align-items: center; gap: 7px; padding: 11px 15px;
  background: var(--paper-3); border-bottom: 1px solid var(--line-soft);
}
.hst__bar i{ width: 9px; height: 9px; border-radius: 50%; background: var(--line); }
.hst__bar span{ margin-left: 8px; font: 600 .72rem/1 var(--f-body); color: var(--ink-3); }
.hst__body{ flex: 1 1 auto; position: relative; min-height: 0; padding: clamp(18px,2.4vw,30px); }
.hst__k{
  font: 700 .68rem/1 var(--f-body); letter-spacing: .14em; text-transform: uppercase;
  color: var(--brand); margin-bottom: 14px;
}
@keyframes hstIn{ to{ opacity: 1; transform: none; } }

/* 01 discovery */
.hstq ul{ margin: 0; padding: 0; list-style: none; }
.hstq li{
  display: flex; gap: 12px; align-items: flex-start; padding: 11px 0;
  border-bottom: 1px solid var(--line-soft); color: var(--ink-1); font-size: .95rem;
  opacity: 0; transform: translateY(8px);
}
.hst[data-on] .hstq li{ animation: hstIn var(--hst-dur, 620ms) var(--ease-snap) forwards; }
.hstq li:nth-child(2){ animation-delay: 70ms; }
.hstq li:nth-child(3){ animation-delay: 140ms; }
.hstq li:nth-child(4){ animation-delay: 210ms; }
.hstq li b{ color: var(--ink-3); font-weight: 700; min-width: 1.4em; }

/* 02 wireframe */
.hstw{ color: var(--line); display: grid; }
.hstw svg{ display: block; width: 100%; height: 100%; }
.hstw rect{ opacity: 0; transform-box: fill-box; transform-origin: left center; transform: scaleX(.6); }
.hst[data-on] .hstw rect{ animation: hstIn 520ms var(--ease-snap) forwards; }
.hstw rect:nth-of-type(2){ animation-delay: 70ms; }
.hstw rect:nth-of-type(3){ animation-delay: 140ms; }
.hstw rect:nth-of-type(4){ animation-delay: 210ms; }
.hstw rect:nth-of-type(5){ animation-delay: 280ms; }
.hstw rect:nth-of-type(6){ animation-delay: 350ms; }
.hstw rect:nth-of-type(7){ animation-delay: 420ms; }

/* 03 staging. The old piece desaturated this to near grey, so the one
   moment the page shows real work looked dead. It runs in full colour. */
.hst[data-s="2"] .hst__body{ padding: 0; }
.hst__shot{ position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: top center; }
.hst__pin{
  position: absolute; left: 21%; top: 36%; width: 26px; height: 26px; border-radius: 50%;
  background: var(--brand); color: #fff; display: grid; place-items: center;
  font: 800 .7rem/1 var(--f-body); box-shadow: 0 0 0 6px var(--brand-hair);
}
.hst__note{
  position: absolute; left: 27%; top: 32%; max-width: 250px;
  background: var(--paper); border: 1px solid var(--line); border-radius: 12px;
  padding: 13px 16px; box-shadow: var(--lift); font-size: .86rem; line-height: 1.45;
  color: var(--ink-1);
}
.hst__note b{
  display: block; font-size: .68rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-3); margin-bottom: 5px;
}
/* The pin is a pointer to the note. With the note gone there is nothing
   for it to point at, so the pair goes together. */
@media (max-width: 640px){ .hst__note, .hst__pin{ display: none; } }

/* 04 transfer */
.hst__r{
  display: flex; align-items: center; gap: 14px; padding: 13px 0;
  border-bottom: 1px solid var(--line-soft); opacity: 0; transform: translateY(8px);
}
.hst[data-on] .hst__r{ animation: hstIn var(--hst-dur, 620ms) var(--ease-snap) forwards; }
.hst__r:nth-of-type(2){ animation-delay: 70ms; }
.hst__r:nth-of-type(3){ animation-delay: 140ms; }
.hst__r:nth-of-type(4){ animation-delay: 210ms; }
.hst__tick{
  width: 20px; height: 20px; border-radius: 50%; background: #1F7A46; flex: none;
  display: grid; place-items: center; color: #fff; font-size: .7rem; font-weight: 800;
}
.hst__t{ font-size: .96rem; color: var(--ink-1); }
.hst__s{ margin-left: auto; font: 600 .74rem/1 var(--f-body); color: var(--ink-3); }
.hst__done{
  margin: 18px 0 0; font-family: var(--f-display); font-weight: 800;
  font-size: clamp(1.2rem, 2.1vw, 1.7rem); letter-spacing: -.02em; color: var(--ink-1);
  opacity: 0; transform: translateY(8px);
}
.hst[data-on] .hst__done{ animation: hstIn var(--hst-dur, 620ms) var(--ease-snap) forwards;
  animation-delay: 280ms; }
.hst__done em{ font-style: normal; color: var(--brand); }

@media (prefers-reduced-motion: reduce){
  .hst, .hstq li, .hstw rect, .hst__r, .hst__done{ transition: none; animation: none;
    opacity: 1; transform: none; }
  .hst:not([data-on]){ opacity: 0; }
}
/* A stage rail, not one caption at a time. Every step was absolutely
   positioned at opacity 0 except the active one, so the column showed a
   single heading over a reserved 13em of nothing, and the scroll
   mechanic was invisible: you could not tell there were four beats or
   which one you were on. */
.handover__caps{
  position: relative; counter-reset: hc;
  display: grid; gap: clamp(6px, 1vw, 14px);
}
.hcap{
  position: relative; counter-increment: hc;
  padding: 10px 0 10px 44px; opacity: 1; pointer-events: auto;
  border-left: 2px solid var(--line-soft);
  transition: border-color .4s var(--ease-out);
}
.hcap::before{
  content: counter(hc, decimal-leading-zero);
  position: absolute; left: 16px; top: 14px;
  font-family: var(--f-body); font-weight: 700; font-size: .72rem;
  letter-spacing: .06em; color: var(--ink-3);
  transition: color .4s var(--ease-out);
}
/* Reveal on grid-template-rows, not max-height.

   max-height eases toward an arbitrary ceiling rather than the content's real
   height, so every transition ran fast at the start and then hit the ceiling
   and stopped early. 0fr to 1fr resolves to the true height, so the curve you
   write is the curve you get.

   The content also rises as it lands, which gives the beat an edge rather
   than a fade. Both animated properties are on the grid container, and the
   transform is composited. */
.hcap__n{
  font-family: var(--f-body); font-size: .8125rem; font-weight: 600;
  letter-spacing: .085em; text-transform: uppercase; color: var(--brand);
  display: grid; grid-template-rows: 0fr; opacity: 0;
  transition: grid-template-rows .42s var(--ease-snap), opacity .26s var(--ease-out);
}
.hcap__n > span{ min-height: 0; overflow: hidden; }
.hcap h3{
  margin-top: 0; font-weight: 800; letter-spacing: -.02em; line-height: 1.12;
  font-size: clamp(1.02rem, 1.5vw, 1.3rem); color: var(--ink-3);
  transition: font-size .42s var(--ease-snap), letter-spacing .42s var(--ease-snap),
              color .3s var(--ease-out), margin-top .42s var(--ease-snap);
}
.hcap__fold{
  display: grid; grid-template-rows: 0fr; opacity: 0;
  transition: grid-template-rows .46s var(--ease-snap), opacity .3s var(--ease-out);
}
.hcap__fold > div{
  min-height: 0; overflow: hidden;
  transform: translateY(-7px);
  transition: transform .46s var(--ease-snap);
}
.hcap p{ margin-top: 12px; max-width: 46ch; color: var(--ink-2); }
.hcap.is-on{ border-left-color: var(--brand); }
.hcap.is-on::before{ color: var(--brand); }
.hcap.is-on .hcap__n{ grid-template-rows: 1fr; opacity: 1; }
.hcap.is-on h3{ font-size: clamp(1.5rem, 3vw, 2.5rem); color: var(--ink-1); letter-spacing: -.03em; margin-top: 8px; }
.hcap.is-on .hcap__fold{ grid-template-rows: 1fr; opacity: 1; }
.hcap.is-on .hcap__fold > div{ transform: none; }

/* Reduced motion gets every step open, since nothing will scrub. */
.handover[data-static] .hcap .hcap__n,
.handover[data-static] .hcap .hcap__fold{ grid-template-rows: 1fr; opacity: 1; }
.handover[data-static] .hcap .hcap__fold > div{ transform: none; }
.handover[data-static] .hcap h3{ font-size: clamp(1.2rem, 2vw, 1.6rem); color: var(--ink-1); }
@media (prefers-reduced-motion: reduce){
  .hcap, .hcap::before, .hcap h3, .hcap p, .hcap__n,
  .hcap__fold, .hcap__fold > div{ transition: none; }
}
.handover[data-static]{ height: auto; }
.handover[data-static] .handover__sticky{ position: static; height: auto; padding-block: clamp(64px,9vh,120px); }

/* ── B2 · Five systems into one ─────────────────────────────────── */
.converge{ position: relative; }
/* Pin below the masthead, not behind it. At top:0 the stage centred its
   content in the full viewport, so the top of it sat under the fixed
   nav bar and the eyebrow was covered. This is what was actually wrong;
   the overflow clipping was a second, smaller fault on top of it. */
.converge__sticky{ display: block; }
.converge__stage{ position: relative; width: 100%; aspect-ratio: 16 / 7; max-height: 460px; }
.converge__stage canvas{ position: absolute; inset: 0; }
.converge[data-static]{ height: auto; }
.converge[data-static] .converge__sticky{ position: static; height: auto; padding-block: clamp(64px,9vh,120px); }

/* ── B4 · The 800 constellation ─────────────────────────────────── */
.constel{ position: relative; width: 100%; aspect-ratio: 2.55; }
.constel canvas{ position: absolute; inset: 0; }

/* ── coreAssist L1-L4 slider ────────────────────────────────────── */
.cover{ display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; margin-top: 26px; }
.cover__row{ display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 15px 20px; background: var(--paper); transition: opacity .3s var(--ease-out), background .3s var(--ease-out); }
.cover__row[data-on="false"]{ opacity: .34; }
/* Same translucent-over-grid-gap problem as .ptable__row:hover. */
.cover__row[data-on="true"]{
  background-color: var(--paper);
  background-image: linear-gradient(var(--brand-wash), var(--brand-wash));
}
.cover__row b{ font-family: var(--f-body); font-weight: 600; color: var(--ink-1); font-size: .96rem; }
.cover__tier{ font-family: var(--f-body); font-size: .8rem; font-weight: 600; letter-spacing: .075em; color: var(--brand); flex: none; }

/* ── Problem selector ("Which one is you?") ─────────────────────── */
/* Options and panels are interleaved in the DOM, one option then its own
   panel, so mobile is an accordion with no extra markup: the content opens
   directly under the option that was tapped instead of being dumped at the
   bottom of the list. Desktop re-forms the same DOM into two columns with
   grid placement. */
.picker{ display: grid; gap: 8px; }

.picker__panel{ display: none; }
.picker__panel.is-active{ display: block; animation: pickerIn .3s var(--ease-out) both; }
@keyframes pickerIn{ from{ opacity: 0; transform: translateY(-6px); } to{ opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce){ .picker__panel.is-active{ animation: none; } }

@media (min-width: 940px){
  .picker{
    position: relative;
    grid-template-columns: minmax(0,.9fr) minmax(0,1.1fr);
    column-gap: clamp(18px,3vw,34px);
    row-gap: 8px;
    /* Rows size to the options and stop. Without this they stretch to fill
       the min-height set below and the six options spread out down the
       column instead of stacking at the top. */
    align-content: start;
  }
  .picker__opt{ grid-column: 1; }

  /* The panels are taken out of the row flow.

     In flow, a panel spanning the option rows inflates every row it spans:
     six 62px options became six 78px rows and the list spread down the
     column. Absolutely positioned, a grid child is still laid into its grid
     area, so column two positions it exactly, but it no longer sizes any
     row. home.js then holds the container at the height of the tallest
     panel, so choosing a different problem cannot change the page height. */
  .picker__panel,
  .picker__panel.is-active{
    display: block;
    position: absolute;
    grid-column: 2;
    grid-row: 1 / -1;
    top: 0; left: 0; right: 0; bottom: auto;
    animation: none;
    opacity: 0;
    visibility: hidden;
    transition: opacity .26s var(--ease-out);
  }
  .picker__panel.is-active{ opacity: 1; visibility: visible; }
}
.picker__opt{
  text-align: left; padding: 17px 20px; border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--paper); font-family: var(--f-body); font-size: 1rem; font-weight: 600; color: var(--ink-2);
  display: flex; align-items: center; gap: 13px;
  transition: border-color .22s var(--ease-snap), background .22s var(--ease-snap), color .22s var(--ease-snap);
}
.picker__opt::before{ content: ""; flex: none; width: 9px; height: 9px; background: var(--line); transform: rotate(45deg); transition: background .22s var(--ease-snap); }
.picker__opt:hover{ border-color: var(--brand-hair); color: var(--ink-1); }
.picker__opt[aria-expanded="true"]{ border-color: var(--brand); background: var(--brand-wash); color: var(--ink-1); }
.picker__opt[aria-expanded="true"]::before{ background: var(--brand); }
.picker__panel{ border: 1px solid var(--line); border-radius: var(--r-lg); padding: clamp(24px,3vw,36px); background: var(--paper); min-width: 0; }
.picker__panel .label{ color: var(--brand); }
.picker__panel h3{ margin-top: 12px; }
.picker__panel p{ margin-top: 14px; color: var(--ink-2); }

/* ── Two doors ──────────────────────────────────────────────────── */
.doors{ display: grid; gap: 18px; }
@media (min-width: 860px){ .doors{ grid-template-columns: repeat(2, minmax(0,1fr)); } }
.door{ display: block; padding: clamp(26px,3.2vw,40px); border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--paper); transition: border-color .25s var(--ease-out), transform .25s var(--ease-out); }
.door:hover{ border-color: var(--brand); transform: translateY(-3px); }
.door .label{ color: var(--brand); }
.door h3{ margin-top: 12px; }
.door p{ margin-top: 12px; color: var(--ink-2); }

/* ── Product table ──────────────────────────────────────────────── */
.ptable{ display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; }
.ptable__row{ display: grid; gap: 6px 20px; padding: 22px clamp(18px,2.4vw,28px); background: var(--paper); align-items: start; }
@media (min-width: 900px){ .ptable__row{ grid-template-columns: minmax(0,.8fr) minmax(0,2fr) minmax(0,.9fr); align-items: center; } }
.ptable__name{ font-family: var(--f-display); font-weight: 800; font-size: 1.15rem; color: var(--ink-1); }
.ptable__name em{ font-style: normal; color: var(--brand); }
.ptable__what{ color: var(--ink-2); font-size: .95rem; }
.ptable__terms{ font-family: var(--f-body); font-size: .8125rem; letter-spacing: .06em; color: var(--ink-3); }
/* These read as floating text: brand-coloured, no edge, no affordance, in a
   column the eye had no reason to treat as actionable. */
.ptable__terms a{
  display: inline-flex; align-items: center; gap: 7px;
  color: var(--brand); font-weight: 700;
  border-bottom: 1px solid var(--brand-hair); padding-bottom: 2px;
  transition: gap .2s var(--ease-snap), border-color .2s var(--ease-out);
}
.ptable__terms a::after{ content: "\2192"; font-weight: 600; }
.ptable__terms a:hover{ gap: 11px; border-bottom-color: var(--brand); }
/* On a phone this was a 24px target, which is half of what a thumb needs.
   The hit area grows past the underline rather than the underline growing
   with it, so the link still reads as a link. */
.ptable__terms a{ position: relative; }
@media (hover: none), (pointer: coarse){
  .ptable__terms a::before{
    content: ""; position: absolute; left: -6px; right: -6px;
    top: 50%; height: 44px; transform: translateY(-50%);
  }
}
.ptable__row{ transition: background-color .2s var(--ease-out); }
/* --brand-wash is translucent, and .ptable paints --line behind 1px grid
   gaps. Setting it as `background` replaced the row's opaque white and let
   that grey through, so the hover painted #BAB1AC instead of the intended
   #F2F1F1. The tint has to composite over paper, not replace it. */
.ptable__row:hover{
  background-color: var(--paper);
  background-image: linear-gradient(var(--brand-wash), var(--brand-wash));
}

/* ── Leadership ─────────────────────────────────────────────────── */
.leads{ display: grid; gap: 18px; grid-template-columns: repeat(4, minmax(0,1fr)); }
@media (max-width: 940px){ .leads{ grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 520px){ .leads{ grid-template-columns: minmax(0,1fr); } }
.lead-card{ padding: clamp(20px,2.4vw,28px); border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--paper); }
.lead-card .initials{ width: 52px; height: 52px; display: grid; place-items: center; border-radius: 50%; background: var(--brand-wash); color: var(--brand); font-family: var(--f-display); font-weight: 800; font-size: 1.05rem; letter-spacing: -.02em; }
.lead-card b{ display: block; margin-top: 16px; font-family: var(--f-display); font-weight: 800; font-size: 1.1rem; color: var(--ink-1); letter-spacing: -.02em; }
.lead-card span{ display: block; margin-top: 5px; font-size: .88rem; color: var(--ink-3); }
.headcount{ font-family: var(--f-display); font-weight: 800; font-size: clamp(1.3rem,2.6vw,1.9rem); letter-spacing: -.025em; color: var(--ink-1); }
.headcount mark{ background: var(--brand-wash); color: var(--brand); padding: 0 .2em; border-radius: 4px; }

/* ── B3 · coreDNA live composer ─────────────────────────────────── */
.dna[data-busy]{ opacity: 1; }

/* ── coreDNA build window ─────────────────────────────────────────
   A browser shell holding the three beats in order: the brief typed
   into the prompt bar, the build walking down its stages, then the
   site that brief became, running. One window, so the reader watches
   one object change rather than three panels take turns. */
.dnawin{
  border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden; background: var(--paper-2);
}
.dnawin__chrome{
  display: flex; align-items: center; gap: 7px;
  padding: 11px 15px; border-bottom: 1px solid var(--line);
}
.dnawin__chrome i{ width: 9px; height: 9px; border-radius: 50%; background: var(--line); flex: none; }
.dnawin__url{
  margin-left: 10px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--f-mono); font-size: .72rem; letter-spacing: .04em; color: var(--ink-3);
}
.dnawin__prompt{
  display: flex; gap: 10px; align-items: baseline; min-height: 54px;
  padding: 15px 16px; border-bottom: 1px solid var(--line);
  font-family: var(--f-mono); font-size: .8125rem; line-height: 1.5; color: var(--ink-1);
  word-break: break-word;
}
.dnawin__caret{ color: var(--brand); flex: none; font-weight: 700; }
.dnacur{
  display: inline-block; width: 7px; height: 1.05em; margin-left: 2px;
  background: var(--brand); vertical-align: -3px; animation: dnablink 1s steps(1, end) infinite;
}
@keyframes dnablink{ 50%{ opacity: 0; } }
.dnawin__foot{
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 14px; margin-top: 14px;
}
.dnawin__cap{ margin: 0; font-family: var(--f-mono); font-size: .74rem; color: var(--ink-3); }
.btn--sm{ padding: 9px 16px; font-size: .75rem; }

/* the stage: whatever beat is running fills the same box, so the
   window never changes height under the reader */
.dna{ position: relative; aspect-ratio: 16 / 10; min-height: 0; background: var(--paper); }
@media (max-width: 700px){ .dna{ aspect-ratio: 4 / 3; } }

/* the build: the stage list is drawn out and lit in turn, because the
   thing being demonstrated is the walk down the stages */
.dnabuild{
  position: absolute; inset: 0; display: grid; align-content: center; gap: 18px;
  padding: clamp(22px, 4vw, 46px); background: var(--paper); overflow: auto;
}
/* Held to a column and centred: left-aligned against the full width of
   the window it read as a stray list rather than a running process. */
.dnabuild__steps, .dnabuild__track{ width: min(420px, 100%); margin-inline: auto; }
.dnabuild__steps{ list-style: none; margin: 0 auto; padding: 0; display: grid; gap: 9px; }
.dnabuild__steps li{
  display: flex; align-items: center; gap: 11px;
  font-family: var(--f-mono); font-size: clamp(.72rem, 1.5vw, .84rem); letter-spacing: .03em;
  color: var(--ink-3); opacity: .45; transition: opacity .3s var(--ease-out), color .3s var(--ease-out);
}
.dnabuild__steps li i{
  width: 9px; height: 9px; border-radius: 50%; flex: none;
  border: 1px solid currentColor; transition: background .3s var(--ease-out);
}
.dnabuild__steps li.is-now{ opacity: 1; color: var(--brand); }
.dnabuild__steps li.is-now i{ background: var(--brand); }
.dnabuild__steps li.is-done{ opacity: .8; color: var(--ink-2); }
.dnabuild__steps li.is-done i{ background: var(--ink-2); }
.dnabuild__track{
  height: 3px; border-radius: 999px; background: var(--line); overflow: hidden;
}
.dnabuild__fill{
  display: block; height: 100%; width: 0; border-radius: 999px;
  background: var(--brand); transition: width 2.6s var(--ease-out);
}
:root[data-pill="red"] .dnabuild{ background: var(--paper); }
@media (prefers-reduced-motion: reduce){ .dnabuild__fill{ transition: none; width: 100%; } }

/* the reveal: the real site, running, over its own screenshot */
.dnashot{ position: absolute; inset: 0; overflow: hidden; background: var(--paper); }
.dnashot__poster{ position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: top center; }
.dnashot iframe{
  position: absolute; top: 0; left: 0; border: 0; transform-origin: 0 0;
  opacity: 0; transition: opacity .6s var(--ease-out); pointer-events: none;
}
.dnashot iframe.is-in{ opacity: 1; }
.dnashot__bar{
  position: absolute; inset: auto 0 0 0; z-index: 2;
  display: flex; align-items: flex-end; justify-content: space-between; gap: 12px;
  padding: 16px; color: #fff;
  background: linear-gradient(transparent, rgba(12,10,10,.92));
}
.dnashot__id b{ display: block; font-family: var(--f-display); font-weight: 800; font-size: 1.05rem; line-height: 1.15; }
.dnashot__id span{ display: block; font-family: var(--f-mono); font-size: .7rem; color: rgba(255,255,255,.66); }
.dnashot__plat{
  flex: none; align-self: flex-end; white-space: nowrap;
  font-family: var(--f-mono); font-size: .64rem; font-weight: 600; letter-spacing: .04em;
  padding: 5px 11px; border-radius: 999px; background: var(--brand); color: #fff;
}
.dnashot__bar:hover .dnashot__plat{ background: #fff; color: var(--brand); }
/* ── coreDNA: the brief building into the real site ───────────────
   Four phases and a bar, then the site that brief actually became.
   Carried over from the v5 page, rebuilt in this site's own type and
   palette rather than its Tailwind and Space Grotesk. */

/* the reveal: a real screenshot that opens the real address */
.dna__card--real .dna__bar{ justify-content: flex-start; }
.dna__plat{
  margin-left: auto; font-family: var(--f-mono); font-size: .64rem;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3);
}
.dna__real{ position: relative; display: block; overflow: hidden; }
.dna__real img{ display: block; width: 100%; height: auto; }
.dna__open{
  position: absolute; right: 12px; bottom: 12px;
  padding: 7px 13px; border-radius: 999px;
  background: rgba(20,16,15,.82); color: #fff;
  font-family: var(--f-mono); font-size: .7rem; letter-spacing: .06em;
}
@media (hover: hover){
  .dna__real:hover .dna__open{ background: var(--brand); }
}

.dna__card{ border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; background: var(--paper); opacity: 0; transform: translateY(10px); transition: opacity .4s var(--ease-out), transform .4s var(--ease-out); }
.dna__card.is-in{ opacity: 1; transform: none; }
.dna__bar{ display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--line); background: var(--paper-2); }
.dna__dot{ width: 10px; height: 10px; border-radius: 50%; display: block; flex: none; }
.dna__name{ font-family: var(--f-body); font-size: .8125rem; letter-spacing: .06em; color: var(--ink-3); }
.dna__body{ display: grid; gap: 0; }
@media (min-width: 860px){ .dna__body{ grid-template-columns: minmax(0,1.35fr) minmax(0,1fr); } }
.dna__preview{ padding: clamp(24px,3.4vw,44px); background: var(--d-paper); color: var(--d-ink); min-width: 0; }
.dna__eyebrow{ font-family: var(--f-body); font-size: .78rem; letter-spacing: .2em; text-transform: uppercase; color: var(--d-accent); }
.dna__h{ margin-top: 12px; font-family: var(--f-display); font-weight: 800; font-size: clamp(1.6rem,3.2vw,2.4rem); line-height: 1.04; letter-spacing: -.03em; color: var(--d-ink); }
.dna__p{ margin-top: 12px; max-width: 42ch; font-size: .95rem; line-height: 1.6; opacity: .78; }
.dna__row{ display: flex; flex-wrap: wrap; gap: 10px; margin-top: 22px; }
.dna__btn{ padding: 11px 20px; border-radius: var(--r-pill); background: var(--d-accent); color: #fff; font-family: var(--f-display); font-weight: 800; font-size: .8125rem; letter-spacing: .07em; text-transform: uppercase; }
.dna__ghost{ padding: 11px 20px; border-radius: var(--r-pill); border: 1px solid currentColor; font-family: var(--f-display); font-weight: 800; font-size: .8125rem; letter-spacing: .07em; text-transform: uppercase; opacity: .55; }
.dna__blocks{ display: grid; grid-template-columns: repeat(3,1fr); gap: 10px; margin-top: 26px; }
.dna__blocks i{ display: block; height: 54px; border-radius: 8px; background: var(--d-second); opacity: .16; }
.dna__spec{ margin: 0; padding: clamp(22px,2.6vw,32px); display: grid; gap: 16px; align-content: start; border-top: 1px solid var(--line); }
@media (min-width: 860px){ .dna__spec{ border-top: 0; border-left: 1px solid var(--line); } }
.dna__spec dt{ font-family: var(--f-body); font-size: .76rem; letter-spacing: .085em; text-transform: uppercase; color: var(--brand); }
.dna__spec dd{ margin: 6px 0 0; font-size: .92rem; color: var(--ink-2); display: flex; flex-wrap: wrap; gap: 6px; }
.dna__sw{ width: 26px; height: 26px; border-radius: 6px; border: 1px solid var(--line); display: block; }

/* Leaf-page section headings: sentence case, Quiet tier, and long
   service names run to four lines at full h2 scale. */
.h2--sm{ font-size: clamp(1.6rem, 2.8vw, 2.5rem); letter-spacing: -.025em; line-height: 1.08; }

/* Six leaders with real role descriptions, three across. Four columns
   left an orphan pair; three gives two clean rows. */
.leads{ grid-template-columns: repeat(4, minmax(0,1fr)); }
@media (max-width: 980px){ .leads{ grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 560px){ .leads{ grid-template-columns: minmax(0,1fr); } }
.lead-card__bio{ margin-top: 12px; font-size: .92rem; line-height: 1.55; color: var(--ink-2); }
h2 mark, .headcount mark{ background: var(--brand-wash); color: var(--brand); padding: 0 .12em; border-radius: 6px; }

/* ── Hero particle field ────────────────────────────────────────────
   The brief asks for a particle mark at the right of the hero. It
   assembles the real wordmark, then reforms into a key. */
.hero-grid{ display: grid; gap: clamp(28px, 4vw, 56px); grid-template-columns: minmax(0,1fr); align-items: center; }
/* Was 1.32/.68, which gave the field a 376px column. The particle field needs room to
   read: a compact glyph fits the box on its limiting axis, so the column width sets how
   large every beat can be. The headline still fits its longest line on one row here. */
@media (min-width: 1000px){ .hero-grid{ grid-template-columns: minmax(0,1.12fr) minmax(0,.88fr); } }
/* The headline is the hero and it wins the space. At the full h1 clamp
   it wrapped to five lines once the field took a column. */
/* Sized so the headline, the capture form and the toggle all clear
   a laptop fold. It was running about 940px tall. */
/* Measured, not guessed. At clamp(2.5rem, 4.5vw, 4.6rem) the headline ran
   73.6px inside a 729px column, about nine characters to a line, so it
   wrapped to seven lines and filled 55% of a 1728px screen before a word
   of body copy. On a phone it was eight lines and 39%.

   The column is what it is, so the size has to come down far enough to put
   a readable number of words on each line. This lands 3 lines plus 1 on
   desktop and 4 plus 2 on a phone. */
.phero .hero-grid h1{ font-size: clamp(2rem, 1.3rem + 1.9vw, 2.9rem); }
/* A square left 133px of the field's own grid cell empty, because the row is as tall as
   the headline column beside it. Filling the cell instead gives every beat that height
   back, and the figure beats gain the most: they are height-limited where the glyphs
   are width-limited. min-height keeps it sane if the copy beside it ever shortens. */
.hero-field{ position: relative; width: 100%; height: 100%; min-height: 360px; align-self: stretch;
  /* The colour the dust resolves into. Read by the hero script so the solid form
     follows the pill without the script knowing the palette. */
  --hf-solid: #A41E22; }
:root[data-pill="red"] .hero-field{ --hf-solid: #F0666A; }
.hero-field canvas{ position: absolute; inset: 0; width: 100%; height: 100%; }
/* The static mark, shown only when WebGL is gone or the context is lost. The field
   itself is a canvas with no fallback content, so without this the column is empty. */
.hero-field__fallback{ position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%);
  width: 88%; height: auto; opacity: 0; transition: opacity 240ms ease-out; pointer-events: none; }
:root[data-herofield-failed] .hero-field canvas{ display: none; }
:root[data-herofield-failed] .hero-field__fallback{ opacity: 1; }
/* On phones the headline leads. Putting the field first pushed the h1
   down and made a canvas the LCP candidate. */
@media (max-width: 999px){ .hero-field{ max-height: 30vh; min-height: 190px; } }

/* ═══════════════════════════════════════════════════════════════════
   DEPTH PASS
   The build read flat because every band was white with hairline
   boxes on it. Real imagery, layering and scale contrast carry it now,
   and all of it has to survive as a still.
   ═══════════════════════════════════════════════════════════════════ */

/* ── Live work cards: a real screenshot underneath, always ─────────
   The poster is the card. The iframe only layers over it when motion
   is allowed, so a still and a reduced-motion visitor see the work. */
.live__view img.live__poster{
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 0; display: block;
}
.live__view iframe{ opacity: 0; transition: opacity .5s var(--ease-out); }
.live__view iframe.is-in{ opacity: 1; }
.live{ background: var(--paper); }
.live__meta{ display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.live__meta .live__go{
  font-family: var(--f-body); font-size: .76rem; letter-spacing: .07em;
  text-transform: uppercase; color: var(--brand); flex: none;
}
.live--pan .live__poster{ animation: pan 22s var(--ease-in-out, ease-in-out) infinite alternate; }
@keyframes pan{ from{ transform: scale(1.02); } to{ transform: scale(1.14) translateY(-5%); } }
@media (prefers-reduced-motion: reduce){ .live--pan .live__poster{ animation: none; } }

/* ── The feature slab: one piece of work at full width ────────────── */
.slab__over{
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: clamp(24px,4vw,52px);
  background: linear-gradient(to top, rgba(12,9,8,.92) 12%, rgba(12,9,8,.55) 55%, rgba(12,9,8,0));
  color: #fff;
}
.slab__over .label{ color: #fff; opacity: .82; }
.slab__over h3{ color: #fff; margin-top: 10px; max-width: 22ch; }
.slab__over p{ color: rgba(255,255,255,.8); margin-top: 10px; max-width: 52ch; }
.slab__stats{ display: flex; flex-wrap: wrap; gap: clamp(20px,4vw,52px); margin-top: clamp(18px,2.4vw,28px); }
.slab__stats .stat__n{ color: #fff; font-size: clamp(1.6rem,3.2vw,2.6rem); }
.slab__stats .stat__n .suf{ color: #fff; opacity: .7; }
.slab__stats .stat__l{ color: rgba(255,255,255,.62); }

/* ── Leadership with real faces ───────────────────────────────────── */
.lead-card{ overflow: hidden; padding: 0; }
.lead-card__face{
  /* Portrait, not landscape: these are headshots and 4:3 was cropping
     them to a letterbox of forehead. */
  position: relative; aspect-ratio: 4 / 5; background: var(--paper-3); overflow: hidden;
}
.lead-card__face img{
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 18%;
  filter: none;
  transition: filter .4s var(--ease-out), transform .6s var(--ease-out);
}
/* Hover: the portrait comes up in colour behind a maroon wash that clears
   from the bottom, and a rule draws under the name. Same wipe language the
   red mode uses for its reveals, rather than a plain fade. */
.lead-card__body b{ position: relative; display: inline-block; }
.lead-card__body b::after{
  content: ""; position: absolute; left: 0; bottom: -3px; height: 2px; width: 0;
  background: var(--brand); transition: width .42s var(--ease-out);
}
@media (hover: hover) and (pointer: fine){
  /* One tone across two different shoots, until you hover. */
  .lead-card__face img{ filter: grayscale(1) contrast(1.06) brightness(1.02); }
  .lead-card:hover .lead-card__face img{ filter: none; transform: scale(1.045); }
  .lead-card:hover .lead-card__body b::after{ width: 100%; }
}
@media (prefers-reduced-motion: reduce){
  .lead-card__face img, .lead-card__body b::after{ transition: none; }
}
.lead-card__face .initials{
  position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 0;
  font-size: 2rem; background: var(--brand-wash);
}
.lead-card__body{ padding: clamp(18px,2.2vw,24px); }
.lead-card__body b{ margin-top: 0; }

/* ── Leadership on a phone ────────────────────────────────────────────
   Stacked, the 4:5 portrait made each card 673px, 435 of it face, so the
   four leaders ran 2,641px and you scrolled four screens to read four
   names. Side by side instead: the portrait becomes a column the height
   of the text beside it, which is the usual shape for a list of people
   and keeps the bio at a readable measure.

   object-fit is already cover with the focal point at 50% 18%, so the
   narrower column crops toward the face rather than squashing it. */
@media (max-width: 560px){
  .lead-card{
    display: grid;
    grid-template-columns: clamp(104px, 32vw, 132px) minmax(0, 1fr);
    align-items: stretch;
  }
  .lead-card__face{
    aspect-ratio: auto;   /* the text column sets the height now */
    height: 100%;
  }
  .lead-card__body{ padding: 16px 18px; min-width: 0; align-self: center; }
  .lead-card__bio{ margin-top: 9px; font-size: .88rem; line-height: 1.5; }
}

/* ── coreDNA real examples ────────────────────────────────────────── */
.exl{ display: grid; gap: 10px; align-content: start; }
.exb{
  text-align: left; padding: 15px 18px; border: 1px solid var(--line);
  border-radius: var(--r-md); background: var(--paper); cursor: pointer;
  transition: border-color .2s var(--ease-snap), background .2s var(--ease-snap);
}
.exb[aria-selected="true"]{ border-color: var(--brand); background: var(--brand-wash); }
.exb b{ display: block; font-family: var(--f-display); font-weight: 700; font-size: 1rem; color: var(--ink-1); }
.exb span{ display: block; margin-top: 3px; font-size: .84rem; color: var(--ink-3); }
.exwrap{ display: grid; gap: clamp(18px,3vw,32px); }
@media (min-width: 940px){ .exwrap{ grid-template-columns: minmax(0,.72fr) minmax(0,1.28fr); } }
.exview{
  position: relative; border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden; background: var(--paper-3); box-shadow: 0 30px 60px -40px rgba(20,16,15,.5);
}
.exview__chrome{ display: flex; align-items: center; gap: 7px; padding: 11px 14px; border-bottom: 1px solid var(--line); background: var(--paper-2); }
.exview__chrome i{ width: 9px; height: 9px; border-radius: 50%; background: var(--line); display: block; }
.exview__url{ margin-left: 8px; font-family: var(--f-body); font-size: .78rem; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.exview__stage{ position: relative; aspect-ratio: 16 / 10; overflow: hidden; }
.exview__stage img{ position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 0; }
.exview__stage iframe{ position: absolute; top: 0; left: 0; width: 1440px; height: 900px; border: 0; transform-origin: 0 0; pointer-events: none; opacity: 0; transition: opacity .55s var(--ease-out); }
.exview__stage iframe.is-in{ opacity: 1; }
.exview__tag{
  position: absolute; left: 14px; bottom: 14px; z-index: 3;
  font-family: var(--f-body); font-size: .8125rem; letter-spacing: .07em; text-transform: uppercase;
  background: rgba(255,255,255,.92); border: 1px solid var(--line); border-radius: 999px;
  padding: 6px 12px; color: var(--ink-2);
}

/* ── Full-bleed image band ────────────────────────────────────────── */
.bleed{ position: relative; width: 100%; overflow: hidden; }
.bleed img{ display: block; width: 100%; height: 100%; object-fit: cover; }
.bleed--tall{ aspect-ratio: 21 / 9; }
@media (max-width: 720px){ .bleed--tall{ aspect-ratio: 4 / 3; } }

/* ── Feature block: a real mark and real numbers, no borrowed image ── */
.feature{
  display: grid; gap: clamp(22px,3vw,44px); align-items: center;
  padding: clamp(26px,3.4vw,48px); border: 1px solid var(--line);
  border-radius: var(--r-lg); background: var(--paper);
  box-shadow: 0 30px 60px -46px rgba(20,16,15,.5);
}
@media (min-width: 900px){ .feature{ grid-template-columns: minmax(0,.34fr) minmax(0,1fr); } }
.feature__mark{
  display: grid; place-items: center; padding: clamp(20px,2.6vw,32px);
  background: var(--paper-2); border: 1px solid var(--line-soft); border-radius: var(--r-md);
}
.feature__mark img{ width: 100%; max-width: 340px; height: auto; display: block; }
.feature__body{ min-width: 0; }
.feature__stats .stat__n{ color: var(--ink-1); }
.feature__stats .stat__n:not(:has(.suf)){ font-variation-settings: "wdth" 96, "wght" 800; }
.feature__stats .stat__n .suf{ color: var(--ink-3); font-size: .58em; font-weight: 700; margin-left: .12em; }
.feature__stats .stat__l{ color: var(--ink-3); }

/* The caption lives beneath the plate, never over it. */
.slab__stats{ display: flex; flex-wrap: wrap; gap: clamp(18px,3vw,40px); }

/* Real marks come from seven eras at seven aspect ratios. Normalize the
   optical size so the row reads as one rank of clients. */

/* "Read the case study" was wrapping to three lines beside its arrow. */
.card__go{ flex-wrap: nowrap; white-space: nowrap; }

/* ── Full-bleed proof strip ─────────────────────────────────────────
   Real work, edge to edge, right under the headline. It breaks the
   1240px container deliberately: it is the only element on the page
   that does, which is what makes it read as a change of gear. */
.strip{ padding-block: 0 clamp(36px,5vh,64px); overflow: hidden; }
.strip__head{ display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 10px 20px; margin-bottom: clamp(16px,2.4vw,26px); }
.strip__rail{
  width: 100%; overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent);
}
.strip__rail::-webkit-scrollbar{ display: none; }
.strip__track{ display: flex; gap: 16px; width: max-content; padding-inline: clamp(20px,5vw,40px); }
@media (hover: hover){
  .strip__track{ animation: strip 94s linear infinite; }
  .strip:hover .strip__track{ animation-play-state: paused; }
}
@keyframes strip{ from{ transform: translateX(0); } to{ transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce){ .strip__track{ animation: none; } }
.strip__plate{
  position: relative; flex: none; width: clamp(300px, 38vw, 560px);
  aspect-ratio: 16 / 10; border-radius: var(--r-md); overflow: hidden;
  border: 1px solid var(--line); background: var(--paper-3);
  box-shadow: 0 20px 40px -30px rgba(20,16,15,.55);
  transition: transform .3s var(--ease-out), box-shadow .3s var(--ease-out);
}
.strip__plate img{ width: 100%; height: 100%; object-fit: cover; object-position: 50% 0; display: block; }
@media (hover: hover){ .strip__plate:hover{ transform: translateY(-4px); box-shadow: 0 30px 55px -32px rgba(20,16,15,.6); } }
.strip__cap{
  position: absolute; left: 10px; bottom: 10px;
  font-family: var(--f-body); font-size: .8125rem; letter-spacing: .06em; text-transform: uppercase;
  background: rgba(255,255,255,.94); border-radius: 999px; padding: 5px 11px; color: var(--ink-2);
}

/* ── Numerals ───────────────────────────────────────────────────────
   Set against the headline width, not with it. The display face runs
   expanded, which leaves figures wide and soft; the data voice wants
   the opposite, so the numerals are driven narrow and heavy on the
   same axis. Tabular so columns of them line up. */
.stat__n, .plan__fig, .headcount mark, .feature__stats .stat__n{
  font-variation-settings: "wdth" 74, "wght" 900;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.stat__n .suf, /* Word-valued stats are language, not data, so they keep the page width. */

/* ═══════════════════════════════════════════════════════════════════
   THE SOURCE LENS
   The one inverted moment on the site, and it is inside a 250px circle
   rather than across a band. #1A0E0F is the maroon-black the spec
   allows for an inverted moment, never neutral black.
   ═══════════════════════════════════════════════════════════════════ */
.haslens{ position: relative; }
.lens{
  position: absolute; inset: 0; z-index: 4; overflow: hidden;
  background: #1A0E0F; color: #F0E6E4; pointer-events: none;
  border-radius: inherit;
  clip-path: circle(var(--lens-r, 128px) at var(--lens-x, 52%) var(--lens-y, 72%));
  opacity: 0;
  transition: opacity .3s var(--ease-out);
}
.haslens.is-live .lens{ opacity: 1; }
.lens__code{
  /* Top anchored at its natural height rather than stretched to inset:0.
     Stretched, everything past the section's own height was clipped by the
     layer's overflow and simply could not be reached: 19 of 37 lines,
     including the whole closing ledger. The pointer now pans it. */
  position: absolute; top: 0; left: 0; right: 0; margin: 0;
  transform: translateY(var(--lens-scroll, 0px));
  padding: clamp(18px, 2.4vw, 38px) clamp(20px, 5vw, 40px);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* Set large and long rather than small and columnar: at 12px the
     lens showed unreadable fragments and a lot of dead ground. */
  font-size: clamp(12px, 1.16vw, 17px); line-height: 1.72;
  white-space: pre; tab-size: 2; color: #9A8C89;
  text-shadow: 0 0 18px rgba(0,0,0,.5);
}
.lens__code .t{ color: #F26D71; }        /* tag        */
.lens__code .a{ color: #E8B3A0; }        /* attribute  */
.lens__code .s{ color: #A8C7A0; }        /* string     */
.lens__code .x{ color: #FFFFFF; }        /* text node  */
/* The easter egg. A plate that reads as code, on its own layer inside the
   lens, so it holds one position in the blank upper right of the hero and
   does not travel with the panned source. Only the lens reveals it. */
.lens__egg{
  position: absolute; z-index: 2; margin: 0;
  /* Clear of the fixed masthead, which overlaps the top of the hero. */
  top: calc(var(--flag-h) + clamp(28px, 6vh, 84px));
  right: clamp(18px, 4.5vw, 54px);
  padding: 17px 24px 19px;
  border: 1px solid rgba(242,109,113,.55);
  border-radius: 10px;
  background: rgba(12,6,7,.86);
  box-shadow: 0 0 0 1px rgba(0,0,0,.5), 0 26px 60px -28px #000;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* Same clamp and leading as .lens__code, so the plate reads as part of
     the same file rather than a smaller widget sitting on top of it. */
  font-size: clamp(12px, 1.16vw, 17px); line-height: 1.72;
  white-space: pre; color: #C9BBB8; text-shadow: none;
}
.lens__egg-bar{
  position: absolute; top: -1px; left: 18px; transform: translateY(-50%);
  padding: 2px 9px; border-radius: 999px;
  background: var(--brand); color: #FFFFFF;
  font-size: 10.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
}
.lens__egg .c{ color: #7E706D; font-style: italic; }   /* comment  */
.lens__egg .k{ color: #F26D71; }                        /* keyword  */
.lens__egg .n{ color: #FFFFFF; font-weight: 700; }      /* binding  */
.lens__egg .a{ color: #E8B3A0; }                        /* key      */
.lens__egg .s{ color: #A8C7A0; }                        /* string   */
.lens__egg .p{ color: #9A8C89; }                        /* punct    */

@media (max-width: 900px){ .lens__egg{ display: none; } }

.lens__ring{
  position: absolute; z-index: 5; pointer-events: none;
  left: var(--lens-x, 52%); top: var(--lens-y, 72%);
  width: calc(var(--lens-r, 200px) * 2); height: calc(var(--lens-r, 200px) * 2);
  margin-left: calc(var(--lens-r, 200px) * -1); margin-top: calc(var(--lens-r, 200px) * -1);
  border-radius: 50%; border: 1px solid var(--brand);
  box-shadow: 0 0 0 1px rgba(255,255,255,.5) inset, 0 24px 60px -30px rgba(26,14,15,.8);
  opacity: 0;
}
.haslens.is-live .lens__ring{ opacity: 1; }
.lens__hint{
  position: absolute; z-index: 6; left: clamp(20px, 5vw, 40px); bottom: 14px;
  pointer-events: none;
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--f-body); font-weight: 700; font-size: .78rem;
  letter-spacing: .085em; text-transform: uppercase; color: var(--ink-3);
}
.lens__hint::before{
  content: ""; width: 9px; height: 9px; border-radius: 50%;
  background: var(--brand); flex: none;
}
.haslens.is-live .lens__hint{ opacity: 0; }
.lens__hint{ transition: opacity .25s var(--ease-out); }

/* No pointer, or reduced motion: the lens simply stays where it is. */
[data-lens-static] .lens__hint::before{ animation: none; }
@media (max-width: 720px){
  .lens{ clip-path: circle(var(--lens-r, 150px) at 62% 46%); }
  .lens__code{ font-size: 10px; }
}



/* Near anything clickable the lens stands down: it shrinks away and
   fades, so it is never covering the control you are reaching for. */
.haslens.is-clear .lens{ opacity: 0; }
.haslens.is-clear .lens__ring{ opacity: 0; transform: scale(.7); }
.lens__ring{ transition: opacity .28s var(--ease-out), transform .28s var(--ease-out); }

/* Service-hub child grid: seven items in a three-column grid left one
   card stranded on its own row. Four tracks at desktop reads 4 + 3. */
.svc-grid{ grid-template-columns: repeat(3, minmax(0,1fr)); }
@media (min-width: 1120px){ .svc-grid{ grid-template-columns: repeat(4, minmax(0,1fr)); } }
@media (max-width: 860px){ .svc-grid{ grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 560px){ .svc-grid{ grid-template-columns: minmax(0,1fr); } }
.svc-grid .card h3{ font-size: clamp(1.05rem, 1.5vw, 1.25rem); }

/* ═══════════════════════════════════════════════════════════════════
   WEIGHT PASS
   White cards on a white page separated by a 1px hairline is what read
   as sterile: nothing had mass. Surfaces now lift off a toned ground,
   rules that mark structure are brand coloured and thick enough to see,
   and running copy is larger and darker.
   ═══════════════════════════════════════════════════════════════════ */
.card, .feature, .lead-card, .live, .exview, .picker__panel, .door, .dna__card{
  background: var(--paper);
  box-shadow: var(--lift);
}
a.card:hover, .card--hover:hover, .door:hover{ box-shadow: var(--lift-2); }
.steps, .cover, .ptable{ background: var(--line); box-shadow: var(--lift); }
.steps > div, .cover__row, .ptable__row{ background: var(--paper); }
.faq{ background: var(--paper); border-radius: var(--r-lg); padding: 4px clamp(18px,2.4vw,30px); box-shadow: var(--lift); border-top: 0; }
.capture input{ background: var(--paper); box-shadow: var(--lift); border-color: transparent; }
.capture input:focus{ border-color: var(--brand); }

/* Section headings get a brand rule above them. Structure you can see
   beats a hairline you cannot. */
.shead__n{ position: relative; padding-top: 16px; }
.shead__n::before{
  content: ""; position: absolute; top: 0; left: 0;
  width: 42px; height: 3px; border-radius: 2px; background: var(--brand);
}

/* Running copy: bigger measure, darker ink, more air between lines. */
.card p, .feat p, .door p, .picker__panel p, .lead-card__bio{ font-size: 1.03rem; line-height: 1.6; }
.ticks li{ font-size: 1.08rem; }
.stat__l{ font-size: .82rem; color: var(--ink-3); }
.crumb{ font-size: .78rem; }
.chip{ font-size: .8rem; padding: 8px 15px; }
.live__meta b{ font-size: 1.12rem; }
.live__meta span{ font-size: .95rem; }
.foot__links a{ font-size: 1rem; }
.foot__legal{ font-size: .78rem; }
.mega__col a b{ font-size: 15.5px; }
.mega__col a span{ font-size: 13.5px; }
.lnk{ font-size: 15.5px; }

/* The strip sits on the toned ground; give its plates a real edge. */
.strip__plate{ box-shadow: var(--lift); border-color: var(--line); }

/* Alternating bands need to actually alternate now that the page ground
   is toned: plain sections show the ground, --band shows white. */
.section--band{ box-shadow: inset 0 1px 0 var(--line), inset 0 -1px 0 var(--line); }

/* ── coreCerebrum ───────────────────────────────────────────────────
   Carries the product's own content: a without/with pair, a real cost
   ledger, real interface captures and an honest comparison table. */
.vs{ display: grid; gap: 1px; background: var(--line); border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--lift); }
.vs + .vs{ margin-top: 18px; }
@media (min-width: 780px){ .vs{ grid-template-columns: repeat(2, minmax(0,1fr)); } }
.vs__col{ background: var(--paper); padding: clamp(22px,2.8vw,34px); }
.vs__col--no .label{ color: var(--ink-3); }
.vs__col--no h3, .vs__col--no p{ opacity: .72; }
.vs__col--yes{ background: var(--brand-wash); }
.vs__col--yes .label{ color: var(--brand); }
.vs__col h3{ margin-top: 10px; font-size: clamp(1.3rem,1.9vw,1.7rem); }
.vs__col p{ margin-top: 10px; }

.footnote{ font-size: .92rem; line-height: 1.6; color: var(--ink-3); max-width: 76ch; }

/* An aside, sized to what it is. A clarification about something you are NOT
   competing with does not deserve the same display headline as the argument
   itself: on the compare page that spent the largest type on the page telling
   people about a file format. A bordered note with a rule down the left reads
   as a margin comment, which is what it is. */
.aside{
  border: 1px solid var(--line); border-left: 3px solid var(--brand);
  border-radius: var(--r-md); padding: 26px 30px; max-width: 86ch;
  background: var(--paper-2);
}
.aside__k{
  font-family: var(--f-mono); font-size: .68rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--brand);
}
.aside h3{ margin-top: 8px; font-size: 1.32rem; }
.aside p{ margin-top: 12px; color: var(--ink-2); }
.aside p + p{ margin-top: 10px; }
@media (max-width: 640px){ .aside{ padding: 20px 22px; } }

.ledger{ background: var(--paper); border-radius: var(--r-lg); box-shadow: var(--lift); overflow: hidden; font-variant-numeric: tabular-nums; }
.ledger__head{
  padding: 13px 20px; background: var(--ink-1); color: #fff;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .8rem; letter-spacing: .04em;
}
.ledger__row{ display: flex; align-items: baseline; justify-content: space-between; gap: 16px; padding: 13px 20px; border-bottom: 1px solid var(--line-soft); }
.ledger__row span{ font-size: .92rem; color: var(--ink-3); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.ledger__row b{ font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .95rem; color: var(--ink-1); }
.ledger__row.is-total{ border-bottom: 0; background: var(--brand-wash); }
.ledger__row.is-total b{ color: var(--brand); font-size: 1.2rem; font-weight: 700; }

.shots{ display: grid; gap: clamp(18px,2.6vw,30px); }
.shotcard{ margin: 0; background: var(--paper); border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--lift-2); border: 1px solid var(--line); }
.shotcard img{ display: block; width: 100%; height: auto; }
.shotcard figcaption{ padding: 16px clamp(18px,2.2vw,26px); display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: baseline; border-top: 1px solid var(--line-soft); }
.shotcard figcaption b{ font-family: var(--f-display); font-weight: 800; font-size: 1.05rem; color: var(--ink-1); }
.shotcard figcaption span{ font-size: .95rem; color: var(--ink-3); }

.tablewrap{ overflow-x: auto; border-radius: var(--r-lg); box-shadow: var(--lift); background: var(--paper); }
.cmp{ width: 100%; border-collapse: collapse; min-width: 560px; }
.cmp th, .cmp td{ text-align: left; padding: 15px clamp(16px,2vw,24px); border-bottom: 1px solid var(--line-soft); font-size: 1rem; }
.cmp thead th{ background: var(--ink-1); color: #fff; font-family: var(--f-body); font-weight: 700; font-size: .85rem; letter-spacing: .06em; text-transform: uppercase; border-bottom: 0; }
.cmp tbody th{ font-weight: 600; color: var(--ink-1); }
.cmp td{ color: var(--ink-3); }
.cmp td.yes{ color: var(--brand); font-weight: 700; }
.cmp tbody tr:last-child th, .cmp tbody tr:last-child td{ border-bottom: 0; }

/* The lead proof gets a bigger mark plate than the secondary one. */
.feature--lead{ padding: clamp(30px,4vw,60px); }
@media (min-width: 900px){ .feature--lead{ grid-template-columns: minmax(0,.42fr) minmax(0,1fr); } }
.feature__mark--lg{ padding: clamp(28px,3.4vw,48px); background: var(--brand-wash); border-color: var(--brand-hair); }
.feature__mark--lg img{ width: 100%; max-width: 100%; max-height: none; height: auto; filter: grayscale(1) brightness(0) opacity(.92); }
.feature--lead .feature__body h3{ font-size: clamp(1.75rem,2.9vw,2.6rem); }

/* ═══════════════════════════════════════════════════════════════════
   THE PILLS
   A choice, not a gate. Both capsules are real canvas with liquid in
   them; the page is fully readable whether or not anyone touches them.
   ═══════════════════════════════════════════════════════════════════ */
.pills{ padding-block: clamp(60px,9vh,120px); background: var(--paper); box-shadow: inset 0 1px 0 var(--line), inset 0 -1px 0 var(--line); }
.pills .shead{ display: block; }
.pills .shead__n::before{ left: 50%; transform: translateX(-50%); }
.pills__row{ display: grid; gap: clamp(20px,3vw,40px); }
@media (min-width: 820px){ .pills__row{ grid-template-columns: repeat(2, minmax(0,1fr)); } }
.pills__note{ text-align: center; font-size: .95rem; color: var(--ink-3); }

.pill{
  display: grid; justify-items: center; text-align: center; gap: 4px;
  padding: clamp(28px,3.4vw,44px) clamp(22px,3vw,36px) clamp(24px,3vw,36px);
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--paper); box-shadow: var(--lift);
  cursor: pointer; font: inherit; color: inherit;
  transition: transform .3s var(--ease-out), box-shadow .3s var(--ease-out), border-color .3s var(--ease-out);
}
@media (hover: hover){ .pill:hover{ transform: translateY(-5px); box-shadow: var(--lift-2); border-color: var(--brand-hair); } }
.pill:focus-visible{ outline: 2px solid var(--brand); outline-offset: 4px; }
.pill[aria-pressed="true"]{ border-color: var(--brand); box-shadow: var(--lift-2), 0 0 0 2px var(--brand-hair); }

/* The capsules are real photographic plates from the coreStudio asset
   stage: horizontal, filled edge to edge, internally lit, with the
   colour spilling onto the surface under them. They keep their own dark
   studio ground, which is what makes them read as objects rather than
   as clip art, so they sit in a tile rather than being blended out. */
.pill__glass{
  position: relative; display: block; width: 100%;
  aspect-ratio: 4 / 3; border-radius: var(--r-md); overflow: hidden;
  background: #7B7A7E;
  box-shadow: inset 0 0 0 1px rgba(20,16,15,.14), 0 18px 40px -26px rgba(20,16,15,.55);
}
.pill__shot{
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: transform .6s var(--ease-out), filter .4s var(--ease-out);
  will-change: transform;
}
@media (hover: hover){
  .pill:hover .pill__shot{ transform: scale(1.06); }
  .pill--red:hover .pill__shot{ filter: saturate(1.14) brightness(1.06); }
  .pill:not(.pill--red):hover .pill__shot{ filter: saturate(1.1) brightness(1.05); }
}
/* The mark, printed on the capsule rather than pasted over the photo. */
.pill__mark{
  position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%) rotate(-8deg);
  width: 34%; opacity: .34; pointer-events: none;
  mix-blend-mode: overlay; filter: brightness(0) invert(1);
}
.pill__mark img{ display: block; width: 100%; height: auto; }

.pill__label{
  margin-top: clamp(18px,2.4vw,28px);
  font-family: var(--f-display); font-weight: 900; letter-spacing: -.02em;
  font-size: clamp(1.5rem,2.4vw,2rem); color: var(--ink-1);
  font-variation-settings: "wdth" 108, "wght" 900;
}
.pill--red .pill__label{ color: var(--brand); }
.pill__line{ margin-top: 8px; max-width: 34ch; font-size: 1.02rem; line-height: 1.55; color: var(--ink-2); }
.pill__go{
  margin-top: 18px; display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--f-body); font-weight: 700; font-size: .82rem;
  letter-spacing: .075em; text-transform: uppercase; color: var(--brand);
}
.pill__go::after{ content: ""; width: 16px; height: 1px; background: currentColor; transition: width .3s var(--ease-out); }
@media (hover: hover){ .pill:hover .pill__go::after{ width: 28px; } }

/* ═══════════════════════════════════════════════════════════════════
   HERO ALTERNATIVE  ·  behind ?hero=real, for judgement against the dust
   A real client site in browser chrome, whose screen peels back to the
   source underneath. The beat is ownership, not construction.
   ═══════════════════════════════════════════════════════════════════ */
@media (min-width: 1000px){
  :root[data-hero="real"] .hero-grid{ grid-template-columns: minmax(0,1.15fr) minmax(0,.85fr); }
}
:root[data-hero="real"] .hero-field{ display: none; }
.hbuild{ margin: 0; display: grid; gap: 14px; align-content: center; min-width: 0; }
.hbuild__chrome{
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px; border: 1px solid var(--line); border-bottom: 0;
  border-radius: var(--r-md) var(--r-md) 0 0; background: var(--paper-2);
}
.hbuild__chrome i{ width: 9px; height: 9px; border-radius: 50%; background: var(--line); flex: none; }
.hbuild__url{
  margin-left: 6px; font-family: var(--f-mono); font-size: .74rem;
  letter-spacing: .04em; color: var(--ink-3); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.hbuild__live{
  margin-left: auto; flex: none; padding: 2px 9px; border-radius: 999px;
  background: var(--brand); color: #fff;
  font-size: .58rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
}
.hbuild__view{
  position: relative; overflow: hidden; aspect-ratio: 16 / 10;
  border: 1px solid var(--line); border-radius: 0 0 var(--r-md) var(--r-md);
  background: #1A0E0F;
}
.hbuild__src{
  position: absolute; inset: 0; margin: 0; padding: clamp(14px,2vw,26px);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: clamp(9px, .82vw, 12.5px); line-height: 1.7;
  white-space: pre; color: #9A8C89; overflow: hidden;
}
.hbuild__src .t{ color: #F26D71; } .hbuild__src .a{ color: #E8B3A0; }
.hbuild__src .s{ color: #A8C7A0; } .hbuild__src .x{ color: #FFFFFF; }
.hbuild__shot{
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: top center; display: block;
  animation: hpeel 11s var(--ease-out) infinite;
}
/* inset(top right bottom left): lifting the bottom edge uncovers the
   source sitting behind the screen. */
@keyframes hpeel{
  0%, 40%   { clip-path: inset(0 0 0 0); }
  50%, 72%  { clip-path: inset(0 0 58% 0); }
  82%, 100% { clip-path: inset(0 0 0 0); }
}
.hbuild__cap{
  font-size: .82rem; line-height: 1.55; color: var(--ink-3); margin: 0;
}
.hbuild__cap b{ color: var(--ink-1); }
@media (prefers-reduced-motion: reduce){ .hbuild__shot{ animation: none; } }

/* The switch only exists while a hero parameter is in the URL. */
.heroswap{
  position: fixed; left: 16px; bottom: 16px; z-index: 70;
  display: flex; align-items: center; gap: 6px;
  padding: 6px; border-radius: 999px;
  background: var(--paper); border: 1px solid var(--line);
  box-shadow: 0 18px 40px -24px rgba(20,16,15,.6);
  font-family: var(--f-body); font-size: .72rem; font-weight: 700;
}
.heroswap span{ padding: 0 8px; color: var(--ink-3); letter-spacing: .1em; text-transform: uppercase; font-size: .6rem; }
.heroswap button{
  border: 0; cursor: pointer; padding: 7px 13px; border-radius: 999px;
  background: transparent; color: var(--ink-2); font: inherit;
}
.heroswap button[aria-pressed="true"]{ background: var(--brand); color: #fff; }

/* ═══════════════════════════════════════════════════════════════════
   THE CONSOLE
   Light side: a plain terminal panel, no theatre.
   Dark side: a CRT. Phosphor red rather than the film's green, because
   the brand only owns one colour and this is it.
   ═══════════════════════════════════════════════════════════════════ */
.tgo{
  position: fixed; z-index: 71;
  right: clamp(14px, 4vw, 30px);
  bottom: calc(clamp(14px, 4vw, 30px) + env(safe-area-inset-bottom, 0px));
  display: inline-flex; align-items: center; gap: 9px;
  padding: 12px 17px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--line); background: var(--paper); color: var(--ink-2);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .74rem; letter-spacing: .1em; text-transform: uppercase;
  box-shadow: 0 10px 26px -14px rgba(20,16,15,.55);
  transition: transform .25s var(--ease-snap), border-color .25s var(--ease-out);
}
@media (hover: hover){ .tgo:hover{ transform: translateY(-2px); border-color: var(--brand); } }
.tgo:focus-visible{ outline: 2px solid var(--brand); outline-offset: 3px; }
.tgo__blip{ width: 8px; height: 8px; border-radius: 50%; background: var(--brand); flex: none; }
.tgo__mark{ display: none; font-weight: 700; letter-spacing: 0; }

.tterm{
  position: fixed; z-index: 72;
  right: clamp(14px, 4vw, 30px);
  bottom: calc(clamp(14px, 4vw, 30px) + 68px + env(safe-area-inset-bottom, 0px));
  width: min(430px, calc(100vw - 28px));
  isolation: isolate;
  border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden;
  background: var(--paper);
  box-shadow: 0 30px 70px -30px rgba(20,16,15,.55);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.tterm__bar{
  display: flex; align-items: center; gap: 9px;
  padding: 9px 10px 9px 14px; border-bottom: 1px solid var(--line);
  background: var(--paper-2);
}
.tterm__led{ width: 8px; height: 8px; border-radius: 50%; background: var(--brand); flex: none; }
.tterm__name{ font-size: .7rem; letter-spacing: .07em; color: var(--ink-3); margin-right: auto; }
.tterm__btn{
  width: 26px; height: 26px; display: grid; place-items: center; flex: none;
  border: 0; background: transparent; color: var(--ink-3); cursor: pointer; border-radius: 6px;
}
.tterm__btn svg{ width: 15px; height: 15px; }
.tterm__btn:hover{ color: var(--brand); }
.tterm__btn[aria-pressed="true"] .tterm__wave{ display: none; }
.tterm__glass{ display: contents; }
.tterm__chin{ display: none; }

/* ── The pills, on the console ───────────────────────────────────────
   They came off the masthead because a toy does not belong in the one
   piece of furniture that has to read as serious on every page. This is
   where they do belong: the thing is already a working terminal with a
   power LED and a mute switch, so two pills on its bar are in keeping.

   The buttons keep the navtog__p class so the whole liquid-pill
   treatment, the flow animation, the pressed state and the dark-mode
   glow, applies without being written twice. */
/* The pair sits in a recessed well with a label, because two unlabelled
   lozenges on a bar are not findable. On the CRT this matters most: the
   casing is red, so the red pill was drawing red on red and effectively
   disappeared, while the moulded knobs beside it competed for the eye. */
.tterm__pills{
  display: inline-flex; align-items: center; gap: 7px; flex: none;
  margin-right: 6px; padding: 4px 9px 4px 8px;
  border-radius: 999px;
  background: rgba(20,16,15,.06);
  box-shadow: inset 0 0 0 1px rgba(20,16,15,.1);
}
.tterm__lab{
  font-style: normal; font-family: var(--f-mono);
  font-size: .58rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-3); user-select: none;
}
.tterm__pills .navtog__p{
  width: 38px; height: 20px; padding: 0; flex: none;
  border: 0; background: none; cursor: pointer;
  border-radius: 999px;
}
.tterm__pills .navtog__p{ position: relative; }
/* The pill reads best at 34x18, which is a poor thing to aim at. The hit
   area is extended past it without moving anything: 40px square, which is
   the most the 41px pitch allows before the two overlap each other. */
.tterm__pills .navtog__p::after{
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 40px; height: 40px; transform: translate(-50%,-50%);
}
.tterm__pills .navtog__p:focus-visible{ outline: 2px solid var(--brand); outline-offset: 3px; }

/* On the CRT the well is cut into the casing: a dark socket the two pills
   sit in, which is what separates them from the moulded plastic and stops
   the red one vanishing into it. */
:root[data-pill="red"] .tterm__pills{
  background: rgba(0,0,0,.55);
  box-shadow: inset 0 1px 3px rgba(0,0,0,.8), 0 1px 0 rgba(255,255,255,.14);
}
:root[data-pill="red"] .tterm__lab{ color: rgba(255,255,255,.62); }
:root[data-pill="red"] .tterm__pills .navtog__p[aria-pressed="false"] .lpill{
  box-shadow: 0 0 18px rgba(var(--lp-glow), .75), 0 1px 4px rgba(0,0,0,.6);
}
/* The chosen pill is dimmed by design, so on a dark socket it needs an edge
   or it reads as an empty slot. */
:root[data-pill="red"] .tterm__pills .navtog__p[aria-pressed="true"] .lpill{
  border-color: rgba(255,255,255,.34);
}
.tterm__screen{ padding: 14px 16px 16px; cursor: text; }
.tterm__out{ max-height: 46vh; overflow: auto; scrollbar-width: none; -ms-overflow-style: none; }
.tterm__out::-webkit-scrollbar{ width: 0; height: 0; }
/* ── Console palette ─────────────────────────────────────────────────
   Roles, not one colour reused. Every line used to be either --ink-2 or
   --brand, so a heading, an error and a success were indistinguishable
   and output read as body copy. Declared as tokens on the panel, the way
   the handover declares its transcript palette, so the CRT can restate
   the set rather than override six rules.

   Measured on #FFFFFF: accent 7.16, ok 5.34, meta 5.61, dim 4.63,
   err 6.48, echo 17.4. */
[data-term]{
  --t-accent: #A41E22;
  --t-echo:   #14100F;
  --t-ok:     #1F7A46;
  --t-meta:   #6E6663;
  --t-dim:    #7A7370;
  --t-err:    #B3261E;
}
.tterm__line{ font-size: .8rem; line-height: 1.75; color: var(--t-meta); white-space: pre-wrap; }
.tterm__line.is-echo{ color: var(--t-echo); font-weight: 600; }
.tterm__line.is-head{ color: var(--t-accent); }
.tterm__line.is-meta{ color: var(--t-meta); }
.tterm__line.is-ok{ color: var(--t-ok); }
.tterm__line.is-dim{ color: var(--t-dim); }
.tterm__line.is-err{ color: var(--t-err); }
.tterm__line.is-meta{ font-variant-numeric: tabular-nums; }

/* Two real columns. The command used to be padded out with spaces, which
   aligns only while every line fits: on the CRT the longer descriptions
   wrapped back to column zero and sat under the command instead of under
   the description. A grid keeps the wrap inside its own column. */
.tterm__kv{
  display: grid;
  grid-template-columns: 5.25rem minmax(0, 1fr);
  gap: 0 .7rem;
  padding-left: 1ch;
}
.tterm__kv b{ font-weight: 600; color: var(--t-accent); }
.tterm__kv.is-help b{ color: var(--t-accent); }
.tterm__kv span{ min-width: 0; }

/* The CRT is a narrower screen, so the command column gives ground first. */
:root[data-pill="red"] .tterm__kv{ grid-template-columns: 4.6rem minmax(0, 1fr); gap: 0 .55rem; }
.tterm__row{ display: flex; align-items: baseline; gap: 9px; margin-top: 6px; }
.tterm__ps1{ color: var(--brand); font-size: .8rem; flex: none; }
.tterm__in{
  flex: 1 1 auto; min-width: 0; border: 0; background: transparent; padding: 0;
  font: inherit; font-size: .8rem; color: var(--ink-1); caret-color: var(--brand);
}
.tterm__in:focus{ outline: none; }

/* ── the dark side: an actual CRT ─────────────────────────────────── */
:root[data-pill="red"] .tgo{
  background: #0B0708; border-color: rgba(240,102,106,.4); color: #F0666A;
  box-shadow: 0 0 22px rgba(240,102,106,.22);
}
:root[data-pill="red"] .tgo__blip{ background: #F0666A; box-shadow: 0 0 9px #F0666A; }
/* ── the dark side is an actual monitor ──────────────────────────
   A real CRT, generated through the coreStudio asset stage and cut off
   its white sweep, rather than plastic drawn in CSS. The glass sits at
   a measured percentage of the image, so it stays registered to the
   photograph at every size. Receipt: coreStudio-source/crt/. */
:root[data-pill="red"] .tterm{
  /* The casing adds a lot of bulk around the glass, so the monitor
     needs to be narrower than the plain panel to read as the same
     weight on the page. */
  width: min(440px, calc(100vw - 28px));
  background: url(crt.png) center / 100% 100% no-repeat;
  border: 0; border-radius: 0; padding: 0;
  aspect-ratio: 726 / 609;
  box-shadow: none;
  filter: drop-shadow(0 30px 50px rgba(0,0,0,.75))
          drop-shadow(0 0 40px rgba(240,102,106,.10));
}
:root[data-pill="red"] .tterm__chin,
:root[data-pill="red"] .tterm__name,
:root[data-pill="red"] .tterm__led{ display: none; }

/* the glass, registered to the photograph */
:root[data-pill="red"] .tterm__glass{
  display: block; position: absolute;
  left: 8.3%; top: 10.9%; width: 83.1%; height: 69.6%;
  border-radius: 20px / 26px;      /* follows the tube's curve */
  overflow: hidden;
}
:root[data-pill="red"] .tterm__screen{
  position: absolute; inset: 0; background: #050303;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 14px 18px 16px;
  box-shadow: inset 0 0 40px 10px rgba(0,0,0,.9);
}
:root[data-pill="red"] .tterm__out{ max-height: none; flex: 0 1 auto; }

/* mute and close live on the lower bezel, where the real buttons are */
:root[data-pill="red"] .tterm__bar{
  position: absolute; left: 6%; bottom: 3.2%;
  background: transparent; border: 0; padding: 0; gap: 6px;
  width: auto;
}
:root[data-pill="red"] .tterm__btn{
  width: 22px; height: 22px; border-radius: 5px;
  color: #FFD7D8; background: rgba(0,0,0,.28);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.22);
}
:root[data-pill="red"] .tterm__btn:hover{ color: #fff; background: rgba(0,0,0,.5); }
:root[data-pill="red"] .tterm__btn svg{ width: 12px; height: 12px; }

/* Phosphor. A CRT does not render six inks, it renders one and varies its
   brightness, so the set collapses to steps of the same glow. */
:root[data-pill="red"] [data-term]{
  --t-accent: #FF8A8D;
  --t-echo:   #FFD7D8;
  --t-ok:     #7BE3A4;
  --t-meta:   #E8686C;
  --t-dim:    rgba(232,104,108,.58);
  --t-err:    #FF4E54;
}
:root[data-pill="red"] .tterm__line,
:root[data-pill="red"] .tterm__in{ color: var(--t-meta); text-shadow: 0 0 6px rgba(232,104,108,.55); }
:root[data-pill="red"] .tterm__line.is-echo{ color: var(--t-echo); text-shadow: 0 0 8px rgba(255,215,216,.8); }
:root[data-pill="red"] .tterm__line.is-ok{ color: var(--t-ok); text-shadow: 0 0 6px rgba(123,227,164,.5); }
:root[data-pill="red"] .tterm__line.is-err{ color: var(--t-err); text-shadow: 0 0 7px rgba(255,78,84,.6); }
:root[data-pill="red"] .tterm__line.is-dim{ color: var(--t-dim); }
:root[data-pill="red"] .tterm__ps1{ color: #FFD7D8; }
/* Scanlines and the corner falloff of a curved tube. */
:root[data-pill="red"] .tterm__screen::before{
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 2;
  background: repeating-linear-gradient(180deg,
    rgba(0,0,0,0) 0px, rgba(0,0,0,0) 1px,
    rgba(0,0,0,.34) 2px, rgba(0,0,0,.34) 3px);
  mix-blend-mode: multiply;
}
:root[data-pill="red"] .tterm__screen::after{
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 3;
  background: radial-gradient(120% 130% at 50% 50%, rgba(0,0,0,0) 52%, rgba(0,0,0,.55) 100%);
}
/* Power on: the line snaps across, then the raster opens out. */
:root[data-pill="red"] .tterm.is-on{ animation: crt-on .42s var(--ease-out) both; }
@keyframes crt-on{
  0%   { transform: scaleY(.004) scaleX(.7); filter: brightness(5); opacity: 0; }
  22%  { transform: scaleY(.004) scaleX(1);  filter: brightness(5); opacity: 1; }
  56%  { transform: scaleY(1) scaleX(1);     filter: brightness(1.8); }
  100% { transform: scaleY(1) scaleX(1);     filter: brightness(1); }
}
:root[data-pill="red"] .tterm.is-on .tterm__screen{ animation: crt-flick 5.5s steps(1) infinite; }
@keyframes crt-flick{
  0%,97%  { opacity: 1; }
  98%     { opacity: .93; }
  99%,100%{ opacity: 1; }
}
@media (prefers-reduced-motion: reduce){
  :root[data-pill="red"] .tterm.is-on{ animation: none; }
  :root[data-pill="red"] .tterm.is-on .tterm__screen{ animation: none; }
  .tgo{ transition: none; }
}
@media (max-width: 560px){
  /* A bare status dot reads as decoration, not a control. Swap the word
     for a prompt, which is legible at this size and says what it opens. */
  .tgo__lab{ display: none; }
  .tgo__mark{ display: inline; }
  .tgo{ padding: 12px 15px; }
  .tterm{ left: 14px; right: 14px; width: auto; }
}

/* ═══════════════════════════════════════════════════════════════════
   MODE: BLUE  (default)
   The site straight. No lens, no source, quieter. This is what the
   brief asked for and what every search visitor lands in.
   ═══════════════════════════════════════════════════════════════════ */
:root[data-pill="blue"] .lens,
:root[data-pill="blue"] .lens__ring,
:root[data-pill="blue"] .lens__hint{ display: none !important; }

/* ═══════════════════════════════════════════════════════════════════
   ATMOSPHERE LAYERS  ·  base rules, mode independent
   These are positioning only. Their appearance is set per mode below.
   Keep them OUT of the mode blocks: they were defined inside the red
   block once and a rewrite of that block deleted them, which dropped an
   857px canvas into the document flow and pushed the whole page down.
   ═══════════════════════════════════════════════════════════════════ */
.ambient{
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  opacity: 0; transition: opacity .6s var(--ease-out);
}
:root[data-pill="red"] .ambient{ opacity: 1; }
/* The blue-mode ambient rule that used to sit here was never closed, so
   the browser joined it to the selector below: `[data-pill="blue"] .ambient`
   inherited position:relative and the fixed canvas dropped into the flow,
   pushing the whole page down 536px on the light side. It also scoped this
   rule to blue only. The base .ambient rule already sets opacity 0, so
   there was nothing for a blue override to do. */

body > *:not(.ambient):not(.totop):not(.barc):not(.sheet):not(.heroswap):not(.tgo):not(.tterm):not(.skip){ position: relative; z-index: 1; }


/* ═══════════════════════════════════════════════════════════════════
   MODE: RED  ·  AI enhanced
   A different site, not a louder one. The ground inverts to the
   maroon-black the spec reserves for an inverted moment, the grid
   becomes lit rather than drawn, and every surface turns to dark glass.

   NOTE: the brief says the site carries no dark sections. This is opt
   in, it is never what a search visitor lands in, and blue is untouched.
   ═══════════════════════════════════════════════════════════════════ */
:root[data-pill="red"]{
  --ground:     #110B0C;
  --paper:      #191011;
  --paper-2:    #191011;
  --paper-3:    #241718;
  --ink-1:      #FBF6F5;
  --ink-2:      #CDBFBD;
  --ink-3:      #918280;
  --line:       #342426;
  --line-soft:  #241819;
  /* The mark stays exactly #A41E22. Text and hairlines use the same hue
     lifted, because brand maroon on this ground is unreadable. */
  --brand:      #A41E22;
  /* Was #F0666A, which is the right hue at 67% lightness and read as
     salmon rather than as the brand. #E05055 is the same hue nearer the
     mark and still clears AA for body text on this ground: measured 4.90:1
     against #14100F, where #A41E22 itself is 2.51 and fails even large
     text. Display figures get --brand-lit-lg, which can sit closer to the
     mark because large text only needs 3.0. */
  --brand-lit:    #E05055;
  --brand-lit-lg: #E05055;   /* the whole page is dark here, so one value serves */
  /* Text never uses --brand on this ground: measured at 2.48:1 on the
     sheet headings across 52 pages. --brand-ink is the readable one. */
  --brand-ink:  #E05055;
  --ink-3:      #A99D9B;
  --brand-wash: rgba(224,80,85,.10);
  --brand-hair: rgba(224,80,85,.30);
  --lift:       0 1px 0 rgba(255,255,255,.04) inset, 0 24px 50px -26px rgba(0,0,0,.9);
  --lift-2:     0 1px 0 rgba(255,255,255,.06) inset, 0 44px 90px -34px rgba(0,0,0,1);
  color-scheme: dark;
}

/* Accents that were brand now use the lifted hue so they read. */
:root[data-pill="red"] .label--brand,
:root[data-pill="red"] .shead__n,
:root[data-pill="red"] .card__n,
:root[data-pill="red"] .crumb .here,
:root[data-pill="red"] .brand,
:root[data-pill="red"] .card__go,
:root[data-pill="red"] .live__go,
:root[data-pill="red"] .mega__cat,
:root[data-pill="red"] .mega__all,
:root[data-pill="red"] .cmp td.yes,


:root[data-pill="red"] .lens__hint{ color: var(--brand-lit); }
:root[data-pill="red"] .shead__n::before,
:root[data-pill="red"] .hr-brand,
:root[data-pill="red"] .rule--brand{ background: var(--brand-lit); }
:root[data-pill="red"] .ticks li::before{ background: var(--brand-lit); }

/* Ground: a dot matrix and fine scanlines, not a grid.
   Horizontal and vertical rules at two frequencies is how you draw
   tartan, and that is exactly what it looked like. A dot at each
   intersection reads as graph paper or a board instead, and the
   scanlines carry the terminal association the mode is trading on. */
:root[data-pill="red"] body,
:root[data-pill="red"]{
  background-color: var(--ground);
  background-image:
    radial-gradient(1200px 700px at 78% -8%, rgba(164,30,34,.30), transparent 62%),
    radial-gradient(900px 600px at 8% 108%, rgba(164,30,34,.16), transparent 60%),
    radial-gradient(circle at center, rgba(240,102,106,.20) 0 1.1px, transparent 1.6px),
    radial-gradient(circle at center, rgba(240,102,106,.07) 0 .9px, transparent 1.4px);
  background-size: auto, auto, 64px 64px, 16px 16px;
  background-attachment: fixed;
}
/* Multiply is invisible on a dark ground; the plate has to add light. */
:root[data-pill="red"] 
/* Every surface becomes dark glass. */
:root[data-pill="red"] .card,
:root[data-pill="red"] .feature,
:root[data-pill="red"] .lead-card,
:root[data-pill="red"] .live,
:root[data-pill="red"] .picker__panel,
:root[data-pill="red"] .door,
:root[data-pill="red"] .ledger,
:root[data-pill="red"] .exview,
:root[data-pill="red"] .faq,
:root[data-pill="red"] .steps > div,
:root[data-pill="red"] .cover__row,
:root[data-pill="red"] .ptable__row,
:root[data-pill="red"] .tablewrap,
:root[data-pill="red"] .vs__col{
  background: rgba(255,255,255,.038);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  border-color: var(--line);
}
:root[data-pill="red"] .section--band{
  background: rgba(255,255,255,.028);
  box-shadow: inset 0 1px 0 var(--brand-hair), inset 0 -1px 0 var(--line);
}
:root[data-pill="red"] .steps, :root[data-pill="red"] .cover,
:root[data-pill="red"] .ptable{ background: var(--line); }
:root[data-pill="red"] .vs__col--yes{ background: rgba(240,102,106,.10); }
:root[data-pill="red"] .feature__mark{ background: rgba(255,255,255,.05); border-color: var(--line); }
:root[data-pill="red"] .feature__mark--lg{ background: rgba(240,102,106,.08); }

/* Marks are knocked to white rather than to ink. */
:root[data-pill="red"] .feature__mark img{ filter: grayscale(1) brightness(0) invert(1) opacity(.92); }
:root[data-pill="red"] .foot__mark img{ filter: brightness(0) invert(1) opacity(.9); }

/* Masthead: the capsule turns to smoked glass. */
:root[data-pill="red"] .barc__group{
  background: rgba(255,255,255,.06);
  box-shadow: 0 10px 30px -18px rgba(0,0,0,.9), inset 0 0 0 1px rgba(255,255,255,.10);
}
:root[data-pill="red"].is-scrolled .barc__group{ background: rgba(30,20,21,.72); }
:root[data-pill="red"] .lnk{ color: #E7DEDC; }
:root[data-pill="red"] .barc__tel{ color: #E7DEDC; }
:root[data-pill="red"] .barc__tel:hover{ color: var(--brand-lit); background: rgba(255,255,255,.07); }
:root[data-pill="red"] .lnk:hover,
:root[data-pill="red"] .has-drop:hover > .lnk{ color: var(--brand-lit); background: rgba(255,255,255,.07); }

:root[data-pill="red"] .mega{ background: #1A1112; border-color: var(--line); box-shadow: 0 34px 70px -30px rgba(0,0,0,1); }
:root[data-pill="red"] .mega__col a:hover{ background: rgba(255,255,255,.06); }
:root[data-pill="red"] .prodrow{ border-color: var(--line); }
:root[data-pill="red"] .navtog{ background: rgba(255,255,255,.08); }
:root[data-pill="red"] .burger{ background: var(--brand); }
/* Outranks html.is-scrolled in core.css (0,2,0 vs 0,1,1), which left the
   burger brand-on-brand and invisible against the scrolled band. */
:root[data-pill="red"].is-scrolled .burger{ background: #fff; }
:root[data-pill="red"].is-scrolled .burger span{ background: var(--brand); }
/* The sheet carries its own dark ground in both modes now. */

/* Inputs and the mode bar. */
:root[data-pill="red"] .capture input{ background: rgba(255,255,255,.06); color: var(--ink-1); }
:root[data-pill="red"] .capture input::placeholder{ color: var(--ink-3); }
:root[data-pill="red"] .btn--ghost{ color: var(--ink-1); border-color: var(--line); }
:root[data-pill="red"] .btn--ghost:hover{ color: var(--brand-lit); border-color: var(--brand-lit); }
:root[data-pill="red"] .chip{ background: rgba(255,255,255,.05); border-color: var(--line); color: var(--ink-2); }
:root[data-pill="red"] .foot{ background: rgba(255,255,255,.022); border-top-color: var(--line); }
:root[data-pill="red"] .ledger__head{ background: #000; }
:root[data-pill="red"] .cmp thead th{ background: #000; }

/* Type turns up, and the lens is the point of this mode. */
:root[data-pill="red"] h1{ font-size: clamp(3.5rem, 8.2vw, 7.5rem); letter-spacing: -.05em; }
/* Only a touch over blue. The contrast in this mode comes from the
   ground, not from setting every heading larger, and the extra 12%%
   was wrapping the byCORE headline to seven lines. */
/* The dark mode amplifies display headings. It targets bare h2, which is
   (0,2,1) and therefore beats `.foot h2` and `.sheet h2` at (0,1,1) no
   matter what order they appear in. Those are navigation labels, not
   display type; they were h4 until the heading outline was fixed, which
   is when this rule started catching them and blowing the three footer
   labels up to 66px, where they collided with each other. */
:root[data-pill="red"] h2{ font-size: clamp(2.3rem, 4.6vw, 4.35rem); letter-spacing: -.035em; }
:root[data-pill="red"] .foot h2{ font-size: .8rem; letter-spacing: .085em; }
:root[data-pill="red"] .sheet h2{ font-size: .7rem; letter-spacing: .18em; }
:root[data-pill="red"] .flow h2{ font-size: clamp(1.5rem, 2.1vw, 1.95rem); letter-spacing: -.02em; }
/* The hero headline matches blue exactly. It carried the same 11% bump
   the h2 above was given and then had taken back for the same reason:
   it wraps. At mid widths the extra size pushed this to five lines
   against blue's three, so the two modes no longer read as one page.
   Cannot simply be deleted: `:root[data-pill="red"] h1` above has equal
   specificity and comes later, so removing this would hand the hero the
   7.5rem display size instead. */
:root[data-pill="red"] .phero .hero-grid h1{ font-size: clamp(2rem, 1.3rem + 1.9vw, 2.9rem); }
:root[data-pill="red"] .lead{ font-size: clamp(1.22rem, 1.45vw, 1.55rem); }
:root[data-pill="red"] .shead__n::before{ width: 64px; height: 4px; }
:root[data-pill="red"] .lens{ box-shadow: 0 0 90px rgba(240,102,106,.20) inset; }
:root[data-pill="red"] .lens__ring{ border-color: var(--brand-lit); box-shadow: 0 0 40px rgba(240,102,106,.45), 0 0 0 1px rgba(255,255,255,.2) inset; }

/* Registration marks on every card. */
:root[data-pill="red"] .card{ position: relative; }
:root[data-pill="red"] .card::before,
:root[data-pill="red"] .card::after{
  content: ""; position: absolute; width: 11px; height: 11px;
  border-color: var(--brand-lit); border-style: solid; opacity: .55;
}
:root[data-pill="red"] .card::before{ top: -1px; left: -1px; border-width: 2px 0 0 2px; }
:root[data-pill="red"] .card::after{ bottom: -1px; right: -1px; border-width: 0 2px 2px 0; }

/* Reveals wipe instead of fading. */
:root[data-pill="red"].js [data-reveal],
:root[data-pill="red"].js [data-reveal-group] > *{
  clip-path: inset(0 100% 0 0); transform: none; opacity: 1;
  transition: clip-path .8s var(--ease-out);
}
:root[data-pill="red"].js [data-reveal].in,
:root[data-pill="red"].js [data-reveal-group].in > *{ clip-path: inset(0 0 0 0); }
@media (prefers-reduced-motion: reduce){
  :root[data-pill="red"].js [data-reveal],
  :root[data-pill="red"].js [data-reveal-group] > *{ clip-path: none !important; }
}
:root[data-pill="red"] .flagfill{ animation: flagpulse 2.4s var(--ease-out) 1; }
@keyframes flagpulse{
  0%{ filter: brightness(1); } 18%{ filter: brightness(1.5) saturate(1.3); } 100%{ filter: brightness(1); }
}

/* Photography gains contrast against the dark ground. */
@media (hover: hover) and (pointer: fine){
  :root[data-pill="red"] .lead-card__face img{ filter: grayscale(1) contrast(1.16) brightness(.92); }
}
:root[data-pill="red"] .lead-card__face img{ filter: contrast(1.08); }
:root[data-pill="red"] .strip__cap{ background: rgba(25,16,17,.92); color: var(--ink-2); }
:root[data-pill="red"] .live__chrome{ background: rgba(255,255,255,.05); border-bottom-color: var(--line); }
:root[data-pill="red"] .exview__chrome{ background: rgba(255,255,255,.05); border-bottom-color: var(--line); }
:root[data-pill="red"] .exview__tag{ background: rgba(25,16,17,.9); border-color: var(--line); color: var(--ink-2); }

/* ── The switch, in the masthead ─────────────────────────────────────
   Both capsules stay visible. The one you are in is lit and ringed; the
   other is dimmed, and that dim one is the invitation. A single pill
   removed the choice from view and left it to the label to explain. */
.navtog{
  display: inline-flex; align-items: center; gap: 8px; flex: none;
  padding: 4px 12px 4px 4px; border-radius: var(--r-pill);
  background: rgba(20,16,15,.06);
}
:root[data-pill="red"] .navtog{ background: rgba(255,255,255,.08); }

.navtog__p{
  position: relative; display: block; flex: none; padding: 0; border: 0;
  background: none; cursor: pointer; line-height: 0;
  width: 64px; height: 30px;
  -webkit-tap-highlight-color: transparent;
  transition: transform .3s var(--ease-snap);
}
/* Base first, modifier second: written the other way round these have equal
   specificity and the base silently repainted the red capsule teal. */
.navtog__p{      --lp-line: #1C7C8C; --liq-a: #0C5A6B; --liq-b: #38E0E8; --lp-glow: 56,224,232; }
.navtog__p--red{ --lp-line: #A41E22; --liq-a: #6E0F13; --liq-b: #F0666A; --lp-glow: 240,102,106; }

/* The capsule IS the control: an outlined oval, nothing behind it. */
.lpill{
  position: relative; display: block; width: 100%; height: 100%;
  border-radius: 999px; overflow: hidden;
  border: 1.5px solid var(--lp-line);
  background: transparent;
  transition: border-color .35s var(--ease-snap), box-shadow .35s var(--ease-snap);
}
/* The seam where the two halves meet, slightly off centre like a real one. */
/* No seam. These are gel capsules, one continuous body of liquid, not
   two hard halves pressed together: any line across the middle, however
   soft, reads as a moulded joint. */
/* The liquid. Empty until this mode is the one you are in. */
.lpill__liq{
  position: absolute; inset: 0; border-radius: 999px;
  /* The tile has to start and end on the same colour or the loop snaps.
     It used to run a to b to a to b, so every wrap jumped from the light
     end straight back to the dark one, once per cycle. */
  background-image: linear-gradient(100deg,
    var(--liq-a) 0%, var(--liq-b) 25%, var(--liq-a) 50%,
    var(--liq-b) 75%, var(--liq-a) 100%);
  background-size: 200% 100%; background-repeat: repeat;
  background-position: 0% 50%;
  opacity: 0; transform: scaleX(.16); transform-origin: left center;
  transition: opacity .4s var(--ease-snap), transform .55s var(--ease-out);
}
/* Bubbles, so the fill reads as liquid rather than paint. */
.lpill__liq::after{
  content: ""; position: absolute; inset: -20% -50%;
  animation: lpillbub 17s linear infinite;
  background:
    radial-gradient(circle at 22% 70%, rgba(255,255,255,.55) 0 1.4px, transparent 2px),
    radial-gradient(circle at 61% 40%, rgba(255,255,255,.40) 0 1.1px, transparent 1.7px),
    radial-gradient(circle at 84% 66%, rgba(255,255,255,.30) 0 .9px, transparent 1.5px);
}
/* Specular streak along the top, which is what sells the glass. */
.lpill__gloss{
  position: absolute; left: 7%; right: 7%; top: 11%; height: 30%;
  border-radius: 999px; pointer-events: none;
  background: linear-gradient(180deg, rgba(255,255,255,.9), rgba(255,255,255,0));
  opacity: .22; transition: opacity .35s var(--ease-snap);
}

/* WHICH CAPSULE IS FULL: the one you are NOT in.
   The filled, glowing capsule is the offer, matching the label beside it
   ("AI enhanced / Take the red one"). The mode you are currently in is the
   quiet outlined one. This is deliberately the inverse of the usual
   selected-is-highlighted convention, so the label carries the state and
   the fill carries the invitation. */
.navtog__p[aria-pressed="true"]{ cursor: default; }
.navtog__p[aria-pressed="true"] .lpill{
  border-color: color-mix(in srgb, var(--lp-line) 58%, transparent);
  box-shadow: none;
}
/* A trace of liquid, so the current mode reads as present rather than off. */
.navtog__p[aria-pressed="true"] .lpill__liq{ opacity: .12; transform: scaleX(1); animation: none; }
.navtog__p[aria-pressed="true"] .lpill__gloss{ opacity: .18; }

/* The other mode: full, lit, and the only thing here asking to be pressed. */
.navtog__p[aria-pressed="false"] .lpill{
  border-color: var(--lp-line);
  box-shadow: 0 0 14px rgba(var(--lp-glow), .45), 0 1px 3px rgba(20,16,15,.28);
}
.navtog__p[aria-pressed="false"] .lpill__liq{
  opacity: 1; transform: scaleX(1);
  animation: lpillflow 11s linear infinite;
}
.navtog__p[aria-pressed="false"] .lpill__gloss{ opacity: .6; }
@media (hover: hover){
  .navtog__p[aria-pressed="false"]:hover{ transform: translateY(-2px); }
  .navtog__p[aria-pressed="false"]:hover .lpill{
    box-shadow: 0 0 20px rgba(var(--lp-glow), .62), 0 2px 6px rgba(20,16,15,.3);
  }
}
.navtog__p:focus-visible{ outline: 2px solid var(--lp-line); outline-offset: 4px; }
@keyframes lpillbub{ from{ transform: translate3d(0,0,0); }
                      to{ transform: translate3d(33%,0,0); } }
@keyframes lpillflow{ from{ background-position: 0% 50%; }
                       to{ background-position: 200% 50%; } }
@media (prefers-reduced-motion: reduce){
  .navtog__p[aria-pressed="false"] .lpill__liq{ animation: none; }
}
@media (prefers-reduced-motion: reduce){
  .navtog__p[aria-pressed="true"] .lpill__liq{ animation: none; }
}

/* Reserve the width of the longest phrase. "See how deep the stack goes"
   and "Back to the surface" are different lengths, so the nav group
   changed width on toggle, placeFlag recomputed from it, and the
   pennant and logo jumped sideways. Ashley spotted the cause. */
.navtog__say{ display: grid; line-height: 1.15; text-align: left;
              min-width: 13.75rem; }
.navtog__say b{ font-family: var(--f-body); font-weight: 700; font-size: .8rem; color: var(--ink-1); white-space: nowrap; }
.navtog__say i{ font-style: normal; font-size: .68rem; color: var(--ink-3); white-space: nowrap; }
:root[data-pill="red"] .navtog__say i{ color: var(--brand-lit); }
@media (max-width: 1559px){ .navtog__say{ display: none; } }

/* Two unlabelled pills say nothing about what they do, and the one line
   that explained them only appeared above 1559px, so on a laptop, or at
   120% zoom, nobody ever saw it. Each pill now names its own destination
   on hover, at any width. Pointer devices only: there is no hover on a
   touch screen, and the mobile sheet already spells both out in full. */
@media (hover: hover) and (pointer: fine){
  .navtog__p[data-tip]{ position: relative; }
  .navtog__p[data-tip]::after{
    content: attr(data-tip);
    position: absolute; top: calc(100% + 12px); right: 0;
    padding: 7px 12px; border-radius: 9px;
    font-family: var(--f-body); font-size: .72rem; font-weight: 600;
    letter-spacing: .01em; white-space: nowrap;
    background: var(--ink-1); color: var(--paper);
    box-shadow: 0 14px 30px -18px rgba(20,16,15,.6);
    opacity: 0; transform: translateY(-5px); pointer-events: none;
    transition: opacity .18s var(--ease-out), transform .18s var(--ease-out);
    z-index: 70;
  }
  .navtog__p[data-tip]:hover::after,
  .navtog__p[data-tip]:focus-visible::after{ opacity: 1; transform: none; }
  :root[data-pill="red"] .navtog__p[data-tip]::after{
    background: var(--paper-2); color: var(--ink-1);
    box-shadow: 0 14px 30px -18px #000, inset 0 0 0 1px var(--line);
  }
}

/* In the bar itself below the nav breakpoint. The masthead copy of the
   toggle sits inside .barc__group, which is display:none there, so on a
   phone the pills existed only inside the burger sheet: invisible until
   you opened the menu. This instance is always on screen. */
/* Above .flag (z:3): if the width maths is ever wrong the pills should
   be visible on top of the pennant, not silently buried under it. */
.navtog--bar{ display: none; position: relative; z-index: 4;
              background: none; padding: 0; gap: 7px; margin-right: 12px; }
@media (max-width: 1179px){ .navtog--bar{ display: inline-flex; } }
.navtog--bar .navtog__p{ width: 46px; height: 23px; }
@media (max-width: 420px){
  .navtog--bar{ gap: 6px; margin-right: 9px; }
  .navtog--bar .navtog__p{ width: 40px; height: 20px; }
}
:root[data-pill="red"] .navtog--bar{ background: none; }

/* Below the nav breakpoint it lives in the sheet, with words. */
.navtog--sheet{
  display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: 10px;
  background: none; padding: 0; margin-bottom: 10px;
}
.navtog--sheet .navtog__p{
  width: 100%; height: auto; display: grid; gap: 10px; justify-items: start;
  /* The base rule sets line-height:0, which was right when the control was
     just an image. Here it left the label with a zero height line box, so
     the text laid out on top of the capsule instead of under it. */
  line-height: 1.35;
}
.navtog--sheet .lpill{ width: 100%; max-width: 190px; height: 52px; }
.navtog--sheet .navtog__p span{ font-family: var(--f-body); font-weight: 700; font-size: .9rem; color: var(--ink-3); }
.navtog--sheet .navtog__p[aria-pressed="true"] span{ color: var(--lp-line); }




/* ── Back to top ─────────────────────────────────────────────────────
   The pages are long and the masthead menu is the only way back up, so
   below the fold there was no route home without a full manual scroll. */
.totop{
  position: fixed; z-index: 70;
  right: clamp(14px, 4vw, 30px);
  /* Stacked above the console launcher, which owns the corner. */
  bottom: calc(clamp(14px, 4vw, 30px) + 62px + env(safe-area-inset-bottom, 0px));
  width: 48px; height: 48px; border: 0; border-radius: 999px;
  display: grid; place-items: center; cursor: pointer;
  background: var(--brand); color: #fff;
  box-shadow: 0 6px 20px -8px rgba(20,16,15,.6);
  opacity: 0; transform: translateY(10px) scale(.9); pointer-events: none;
  transition: opacity .3s var(--ease-out), transform .3s var(--ease-snap);
}
.totop svg{ width: 21px; height: 21px; }
html.is-deep .totop{ opacity: 1; transform: none; pointer-events: auto; }

/* ── The corner gets out of the way ──────────────────────────────────
   Both fixed controls sit bottom-right. On a phone there is no gutter,
   so they sit on the copy. site.js sets .is-away while the reader is
   moving forward and clears it the moment they scroll up or stop, so
   the corner is empty while reading and populated when reached for.

   Coarse pointers only: on a desktop there is room beside the measure
   and the controls moving would be motion for nothing. */
@media (pointer: coarse){
  .totop, .tgo{
    transition: opacity .26s var(--ease-out), transform .26s var(--ease-snap);
  }
  html.is-away .totop,
  html.is-away .tgo{
    opacity: 0; pointer-events: none;
    transform: translateY(14px) scale(.94);
  }
  /* Back-to-top is only wanted by someone already heading back, so on a
     touch screen it appears on the upward scroll and not before. That
     keeps the corner empty for the whole of a forward read, which is
     when it was landing on the copy. The console launcher stays, so at
     rest there is one small control in the corner rather than two. */
  /* Matching html.is-deep .totop above, which is (0,1,1); a bare .totop
     is (0,1,0) and loses to it, so the hide has to be written at the
     same weight or higher. */
  html.is-deep .totop{ opacity: 0; pointer-events: none; transform: translateY(10px) scale(.9); }
  html.is-deep.is-up .totop{ opacity: 1; pointer-events: auto; transform: none; }
  html.is-away.is-deep .totop{ opacity: 0; pointer-events: none; }
  /* The console panel is a deliberate mobile treatment, full width at
     560px. If it is open the launcher must not slide out from under it. */
  html.is-away .tgo[aria-expanded="true"]{
    opacity: 1; pointer-events: auto; transform: none;
  }
}

@media (prefers-reduced-motion: reduce){
  html.is-away .totop, html.is-away .tgo{ transition: none; }
}

/* ── Night hero owns its own type size in both modes ──────────────────
   :root[data-pill="red"] .phero h1 is (0,3,1) and out-ranks
   .phero--night h1.is-long at (0,3,0), so in red mode the service heroes
   ignored their own sizing and the long-title step stopped working:
   measured 35.2px against the 31.98px the blue mode gives. The band is
   dark in both modes, so the size should not change with the mode. */
/* Red mode runs the matrix on the page ground. The night hero paints its own
   opaque gradient plus a red radial, which cut a rectangle out of it at the
   top of every service page. Both come off so the hero sits on the matrix.
   Contrast re-measured against the red-mode ground #110B0C:
     h1        #fff              18.4:1
     lead      white 74%         10.7:1
     crumb     white 52%          5.69:1
     eyebrow   --brand-lit        5.06:1  (better than the 4.73:1 on the panel) */
:root[data-pill="red"] .phero--night{ background: none; }
:root[data-pill="red"] .phero--night::after{ display: none; }

:root[data-pill="red"] .phero--night h1{
  font-size: clamp(2.6rem, 5.6vw, 4.9rem); line-height: .93; letter-spacing: -.028em;
}
:root[data-pill="red"] .phero--night h1.is-long{
  font-size: clamp(2.3rem, 3.9vw, 3.4rem); line-height: .98;
}
@media (max-width: 720px){
  :root[data-pill="red"] .phero--night h1{ font-size: clamp(2.3rem, 10vw, 3.2rem); }
  :root[data-pill="red"] .phero--night h1.is-long{
    font-size: clamp(1.9rem, 8.2vw, 2.6rem); line-height: 1.02;
  }
}
@media (hover: hover){ .totop:hover{ transform: translateY(-2px); } }
.totop:focus-visible{ outline: 2px solid var(--brand); outline-offset: 3px; }
:root[data-pill="red"] .totop{
  background: var(--brand); color: #fff;
  box-shadow: 0 0 18px rgba(240,102,106,.45), 0 6px 20px -8px rgba(0,0,0,.7);
}
@media (prefers-reduced-motion: reduce){ .totop{ transition: none; } }


/* ── The proof shelf ─────────────────────────────────────────────────
   Client marks on one moving rule. Replaces a static grid that read as
   grey wallpaper: inconsistent optical sizes, an orphan on the last row,
   and TIC Gums clipped by its cell. */
/* The shelf runs on white rather than on the page ground.

   Every mark was composited over seven candidate grounds and looked at.
   White came out best of the light ones: it is the only one on which
   marygrove's wordmark survives, and it costs nothing anywhere else. The
   two DRE marks stay on their -light cut throughout, below.

   White also matches the About Us section it sits in, so there it reads as
   the section continuing rather than as a panel, and on the homepage's
   cream trustbar it reads as a shelf. Both are correct. */
.marq{
  position: relative; overflow: hidden;
  padding: clamp(18px,2.6vw,30px) 0;
  /* --paper, not a literal, so the shelf follows the mode. Light mode gives
     #FFFFFF, which is the ground the marks were measured on; red mode gives
     #191011, and a hardcoded white slab in the dark mode was the bug this
     replaces. The end fades read the same variable. */
  --shelf: var(--paper);
  background: var(--shelf);
  /* No radius. The shelf is full bleed on the homepage, where it sits
     straight in the section, and contained on the other five, where it sits
     inside .wrap. A corner radius is clipped off the edge in the first case
     and invisible against the white section in the second, so it only ever
     showed up as a half-corner at the viewport edge. */
}
/* Marks enter and leave rather than pop. A mask did this before, which is
   wrong once the shelf has a ground of its own: a mask fades the element's
   background along with everything else, so the panel's edges dissolve and
   the rounded corners go with them. Two gradients in the panel's own colour
   fade the marks and leave the panel crisp. */
.marq::before,
.marq::after{
  content: ""; position: absolute; top: 0; bottom: 0; z-index: 2;
  width: clamp(44px, 9%, 130px); pointer-events: none;
}
.marq::before{ left: 0;  background: linear-gradient(90deg,  var(--shelf), color-mix(in srgb, var(--shelf), transparent)); }
.marq::after{  right: 0; background: linear-gradient(270deg, var(--shelf), color-mix(in srgb, var(--shelf), transparent)); }

/* The shelf is the last thing in its section on all six pages that carry
   it, so the section's own bottom padding left ~90px of empty ground under
   a panel that now has a visible edge. It read as a gap rather than as
   breathing room. */
/* Where the shelf ends its section, the section's own bottom padding left a
   band of empty ground under a panel that now has a visible edge. Zero
   rather than a small value: any remainder shows as a thin strip of the
   section's ground trapped between the white shelf and the section edge.

   Scoped to the shelf actually being last, not merely present. The first
   version matched `.section:has(.marq)`, which was true on the four service
   pages too, where the shelf sits mid-section and three client cards close
   it out. Those cards lost their bottom padding and ended flush against the
   section edge. Two selectors because the structures differ: the homepage
   puts the shelf straight in the section, the rest wrap it. */
.section:has(> :last-child > .marq),
.section:has(> .wrap > :last-child > .marq){ padding-bottom: 0; }
/* One duration for every width meant one speed only at one width: the
   track is 3078px at 1400 but 2063px at 390, so a fixed 46s ran at 67px/s
   on a desktop and 45px/s on a phone, where it read as barely moving.
   These steps hold one speed everywhere. Measured, not guessed.

   Slowed from ~75px/s to ~50px/s: every duration multiplied by 1.5, so the
   steps still cancel the width difference and only the pace changes. A mark
   now takes about 4 seconds to cross its own width rather than 2.7. */
.marq__track{ display: flex; width: max-content; animation: marq 42s linear infinite; }
@media (min-width: 821px){  .marq__track{ animation-duration: 47s; } }
@media (min-width: 1100px){ .marq__track{ animation-duration: 54s; } }
@media (min-width: 1400px){ .marq__track{ animation-duration: 63s; } }
.marq__set{
  display: flex; align-items: center; gap: clamp(38px,5.4vw,84px);
  margin: 0; padding: 0 clamp(19px,2.7vw,42px); list-style: none;
}
.marq__i{ flex: none; display: grid; place-items: center; }
.marq__i img{
  display: block; width: auto; object-fit: contain;
  height: clamp(38px, 4.6vw, 62px); max-width: 210px;
  filter: grayscale(1) brightness(0) opacity(.46);
  transition: filter .3s var(--ease-out), transform .3s var(--ease-snap);
}
/* Optical sizing: a wordmark and a round seal are not the same height. */
.marq__i img.marq--marygrove{ height: clamp(50px, 6vw, 82px); }
.marq__i img.marq--who{ height: clamp(44px, 5.4vw, 74px); }
.marq__i img.marq--ticgums{ max-width: 240px; }
/* Ganim publishes exactly one logo file, 321px wide, and it carries gold
   gradients so it cannot honestly be traced to vector. At the shelf's
   default 210px cap it rendered at 196 CSS px, which is only 1.6x and
   visibly soft on any retina screen. Capped so the pixels it does have
   are a true 2x. It is the one mark on the shelf that cannot go bigger. */
.marq__i img.marq--ganim{ max-width: 158px; }

@keyframes marq{ to{ transform: translate3d(-50%, 0, 0); } }

/* A rule draws under the mark you are on, rather than a box appearing
   around it: the same single-rule language the rest of the page uses. */
.marq__i{ position: relative; padding-bottom: 12px; }
.marq__i::after{
  content: ""; position: absolute; left: 50%; right: 50%; bottom: 0; height: 2px;
  background: var(--brand); opacity: 0;
  transition: left .32s var(--ease-out), right .32s var(--ease-out), opacity .2s;
}
@media (hover: hover){
  .marq:hover .marq__track{ animation-play-state: paused; }
  .marq__i img:hover{ filter: none; transform: translateY(-3px) scale(1.04); }
  .marq__i:hover::after{ left: 8%; right: 8%; opacity: 1; }
}
/* Touch has no hover, so pressing a mark does the same thing. */
@media (hover: none){
  .marq__i img{ filter: grayscale(1) brightness(0) opacity(.62); }
  :root[data-pill="red"] .marq__i img{ filter: grayscale(1) brightness(0) invert(1) opacity(.78); }
}
.marq__i img:active{ filter: none; transform: translateY(-3px) scale(1.04); }
.marq__i:active::after{ left: 8%; right: 8%; opacity: 1; }
:root[data-pill="red"] .marq__i::after{ background: var(--brand-lit); }
:root[data-pill="red"] .marq{ border-top-color: var(--line); }
:root[data-pill="red"] .marq__i img{ filter: grayscale(1) brightness(0) invert(1) opacity(.62); }
@media (hover: hover){ :root[data-pill="red"] .marq__i img:hover{ filter: none; } }

/* Reduced motion gets the same marks, standing still and wrapped. */
@media (prefers-reduced-motion: reduce){
  .marq::before, .marq::after{ display: none; }
  .marq__track{ animation: none; width: 100%; }
  .marq__set{ flex-wrap: wrap; justify-content: center; row-gap: clamp(22px,3vw,40px); }
  .marq__set + .marq__set{ display: none; }
}


/* iOS Safari floats its toolbar over the bottom of the page, so a button
   pinned to the bottom edge sits behind it and looks absent. Lift it clear
   wherever there is no hover, which is the same set of devices. */
@media (hover: none), (pointer: coarse){
  .totop{ bottom: calc(84px + 62px + env(safe-area-inset-bottom, 0px)); }
}

/* Headshots: colour is the reward for hovering, but a phone cannot hover,
   so touch devices simply get the photographs in colour. */


/* ── The real product, inside the handover stage ─────────────────────
   "Then it is a real thing" used to land on a dense particle state that
   read as noise, which is the worst possible moment for the page to look
   unfinished. A real client site resolves in instead, and the repo tree
   then assembles over it: the thing you can see becomes the thing you own. */


/* Constellation palette lives here, not in the script, so each mode can
   set it. The nodes were a fixed near-white and the pings a fixed maroon:
   correct on paper, inverted on the dark ground, where the nodes read as
   loud speckle and the pings disappeared into the background. */
.constel{ --cnode: #E4E1DF; --cping: #A41E22; --cping-a: .6; }
:root[data-pill="red"] .constel{
  --cnode: rgba(240,102,106,.26);
  --cping: #F0666A;
  --cping-a: .85;
}


/* ── Glitch: the code showing through, red mode only ──────────────────
   Every few seconds a portrait tears and a line of the thing underneath
   shows through it. Steps timing, so it snaps rather than eases: a glitch
   that fades is just a fade. Staggered per card so they never fire in
   unison, which would read as a page fault rather than a signal. */
:root[data-pill="red"] .lead-card__face{ isolation: isolate; }
:root[data-pill="red"] .lead-card__face img{
}
:root[data-pill="red"] .lead-card__face::before{
  content: "if (contract.ends) { site.keeps_running = true; }";
  position: absolute; left: 0; right: 0; top: 41%; z-index: 3;
  font-family: var(--f-mono); font-size: 11px; font-weight: 600;
  letter-spacing: .01em; color: #F0666A; background: rgba(9,5,6,.9);
  padding: 5px 9px; white-space: nowrap; overflow: hidden;
  border-top: 1px solid rgba(240,102,106,.5);
  border-bottom: 1px solid rgba(240,102,106,.5);
  opacity: 0; pointer-events: none;
}

/* Fires once, when the card reaches the viewport. */
:root[data-pill="red"] .lead-card__face.is-glitch img{ animation: glitchimg 1s steps(1, end) 1; }
:root[data-pill="red"] .lead-card__face.is-glitch::before{ animation: glitchcode 1s steps(1, end) 1; }

@keyframes glitchimg{
  0%{   transform: translate3d(-6px,0,0); filter: contrast(1.08) hue-rotate(-32deg) saturate(1.8); }
  20%{  transform: translate3d(7px,0,0);  filter: contrast(1.3) brightness(1.15); }
  40%{  transform: translate3d(-3px,0,0); filter: contrast(1.08) hue-rotate(18deg); }
  60%{  transform: translate3d(4px,0,0);  filter: contrast(1.08) saturate(.2); }
  80%{  transform: translate3d(-2px,0,0); filter: contrast(1.14) hue-rotate(-10deg); }
  100%{ transform: none; filter: contrast(1.08); }
}
@keyframes glitchcode{
  0%{   opacity: .96; transform: translateX(-3%); }
  20%{  opacity: 0; }
  40%{  opacity: .92; transform: translateX(2%); }
  60%{  opacity: 0; }
  80%{  opacity: .82; transform: translateX(-1%); }
  100%{ opacity: 0; transform: translateX(0); }
}
@media (prefers-reduced-motion: reduce){
  :root[data-pill="red"] .lead-card__face img,
  :root[data-pill="red"] .lead-card__face::before{ animation: none; }
}


/* ── Margin leaking between the systems ──────────────────────────────
   Ported from the coreERP diagnostic. Palette lives here so each mode
   sets it and the canvas is not stuck with a light-ground scheme. */
.leak{
  --lk-line: #14100F; --lk-dot: #6A6260; --lk-loss: #A41E22;
  border-top: 1px solid var(--line); padding-top: 18px;
}
:root[data-pill="red"] .leak{
  --lk-line: rgba(255,255,255,.62);
  --lk-dot: rgba(255,255,255,.42);
  --lk-loss: #F0666A;
}
.leak__meter{ text-align: right; margin-left: auto; }
.leak__n{
  font-family: var(--f-display); font-weight: 900;
  font-variation-settings: "wdth" 74, "wght" 900;
  font-variant-numeric: tabular-nums;
  font-size: clamp(1.9rem, 4.6vw, 3.1rem); line-height: 1;
  color: var(--brand); letter-spacing: -.01em;
}
:root[data-pill="red"] .leak__n{ color: var(--brand-lit); }
.leak__l{
  font-family: var(--f-body); font-size: .74rem; color: var(--ink-3);
  margin-top: 4px; letter-spacing: .01em;
}
.leak canvas{
  display: block; width: 100%; height: clamp(190px, 24vw, 300px); margin-top: 6px;
}
.leak__note{
  font-size: .78rem; color: var(--ink-3); max-width: 62ch; margin-top: 2px;
}
@media (max-width: 620px){
    .leak__meter{ text-align: left; margin-left: 0; }
  }



/* ── Case studies: one block, three stories ──────────────────────────
   Replaces a text feature, a logo feature and a photographic slab that
   were three different formats in the same section. */
.cases{ display: grid; gap: clamp(22px, 3vw, 40px); }

/* The seam between Selected Work and Enterprise Platforms was a large blank
   band with nothing marking where one argument ended and the next began. */
#enterprise{ border-top: 1px solid var(--line); }
.case{
  display: grid; gap: clamp(20px, 3vw, 42px);
  padding: clamp(22px, 3vw, 44px);
  border-radius: var(--r-lg); background: var(--paper); box-shadow: var(--lift);
}
@media (min-width: 900px){
  .case{ grid-template-columns: minmax(0,.34fr) minmax(0,1fr); align-items: start; }
}
.case--lead{ padding: clamp(30px, 4vw, 60px); }


.case__media{ display: flex; align-items: center; min-width: 0; }
.case__media img{ width: 100%; max-width: 340px; height: auto; display: block; }
/* A photograph is the story, not a mark beside it: full width, above. */
.case__body{ min-width: 0; }
.case__stats .stat__n{ color: var(--ink-1); }
.case__stats .stat__n:not(:has(.suf)){ font-variation-settings: "wdth" 96, "wght" 800; }
.case__stats .stat__n .suf{ color: var(--ink-3); font-size: .58em; font-weight: 700; margin-left: .12em; }
.case__stats .stat__l{ color: var(--ink-3); }
:root[data-pill="red"] .case{ background: rgba(255,255,255,.04); box-shadow: none; border: 1px solid var(--line); }
/* Client marks on the dark side. Measured on a near-black ground,
   FraudSniffr is 60% near-black pixels and OCLC 55%, so both effectively
   vanish. A filter cannot help: brightness(0) invert(1) would turn OCLC's
   rings and FraudSniffr's dog white along with the type. So each has a
   dark-mode file where only the ink is switched to white and every brand
   colour is left exactly as drawn. Approved by Ashley. The url is
   relative to this stylesheet, so it survives being served off a subpath. */
:root[data-pill="red"] .case__media img[src$="clients/fraudsniffr.png"],
:root[data-pill="red"] .feature__mark img[src$="clients/fraudsniffr.png"]{
  content: url(clients/fraudsniffr-dark.png);
}
:root[data-pill="red"] .case__media img[src$="clients/oclc.png"],
:root[data-pill="red"] .feature__mark img[src$="clients/oclc.png"]{
  content: url(clients/oclc-dark.png);
}


/* White-on-transparent marks need inverting on paper and leaving alone on
   the dark ground. A blanket brightness(0) would flatten colour logos. */


.lens__code .d{ color: #4A2A2C; }   /* dot leaders: a rule, not content */


/* A #FFFFFF card on a #F1EFED ground is 1.15:1: the fill alone cannot
   describe the shape, so every panel needs a drawn edge. Without it the
   sections read as loose text floating on grey. */
.card, .feature, .case, .lead-card, .live, .exview, .picker__panel,
.door, .dna__card, .faq, .ptable, .steps, .cover{
  border: 1px solid var(--line);
}
:root[data-pill="red"] .card, :root[data-pill="red"] .case,
:root[data-pill="red"] .lead-card, :root[data-pill="red"] .faq{
  border-color: var(--line);
}


/* ── The gap: one composed band ──────────────────────────────────────
   Was four stacked rows (heading, a stage list that lined up with
   nothing, a diagram, a number parked in the far corner) with a separate
   card section after it. The number is the diagram's consequence, so it
   sits with it, and the outcome cards close the same band. */
@media (min-width: 860px){
    .leakband__top .leak__meter{ text-align: right; }
}
.leak__n{ font-size: clamp(2.4rem, 6vw, 4.4rem); }
.leak{ border-top: 0; padding-top: 0; }
.leak canvas{ height: clamp(190px, 22vw, 290px); margin-top: clamp(10px, 1.6vw, 22px); }
.leak__note{ margin-top: 8px; }
:root[data-pill="red"] :root[data-pill="red"] .section--well{ background: rgba(255,255,255,.03); }


/* ── The night shift ─────────────────────────────────────────────────
   The one dark band on the light version. The brief said remove every
   dark section; Ashley approved breaking it where the content earns it,
   and this section is literally about the hours when nobody is watching:
   "800 sites. Somebody is awake." It also gives eight light sections
   something to be light against, which no amount of contrast tuning
   inside a single value range can do.

   Scoped as a token flip rather than per-element overrides, so every
   child inverts consistently and nothing has to be restyled twice. */
.section--night{
  background: #14100F;
  --ground:    #14100F;
  --paper:     #1C1817;
  --paper-3:   #241F1E;
  --ink-1:     #F6F3F1;
  --ink-2:     #CFC7C3;
  --ink-3:     #9C938F;
  --line:      #3A3230;
  --line-soft: #2A2422;
  --lift: none;
  color: var(--ink-1);
}
.section--night h2, .section--night h3{ color: var(--ink-1); }
/* Maroon is 1.7:1 on this ground, so text and rules take the lifted hue
   while fills keep the exact brand colour. */
.section--night .shead__n{ color: #F0666A; }
.section--night .shead__n::before{ background: #F0666A; }
.section--night .stat__n{ color: var(--ink-1); }
.section--night .stat__n .suf{ color: var(--brand-lit-lg); }
.section--night .stat__l{ color: var(--ink-3); }
.section--night .night__deck{ color: var(--ink-2); max-width: 52rem; }
.section--night .constel{
  --cnode: rgba(240,102,106,.40);
  --cping: #F0666A;
  --cping-a: .85;
}
/* In red mode the whole page is already dark, so the band would vanish:
   lift it slightly instead of painting it the same colour as its ground. */
:root[data-pill="red"] .section--night{ background: rgba(255,255,255,.035); --ground: transparent; }


/* Every client mark sits in the same left column. The even cards used to
   flip theirs to the right to make the stack zigzag, but a logo wall reads
   as a wall only when the marks line up: alternating them meant no two
   consecutive logos shared an edge to scan down. */


/* The pennant point hangs to --pennant-h, and .phero clears exactly that
   plus a gap, so shortening the point on a phone moves the hero with it.
   This was previously fixed for phones alone by hard-coding both numbers,
   which left every width above 700px still overlapping: the point reached
   130px and the eyebrow started at 124. */
@media (max-width: 700px){ :root{ --pennant-h: 108px; } }
@media (max-width: 420px){ :root{ --pennant-h: 100px; } }


/* The capture field now carries a label, so the row that was the form is
   an inner element and the form itself stacks. */
.capture{ display: block; }
.capture__lab{
  display: block; margin-bottom: 8px;
  font-family: var(--f-body); font-weight: 700; font-size: .74rem;
  letter-spacing: .085em; text-transform: uppercase; color: var(--ink-3);
}
.capture__row{ display: flex; flex-wrap: wrap; gap: 10px; }
.capture__row input{ flex: 1 1 240px; min-width: 0; }
.capture__row .btn{ flex: none; }

.capture--cta{ display: flex; flex-wrap: wrap; gap: 10px; }
/* In a centred section the button has to be centred by the flex box, not
   by text-align, which flex children ignore. It was sitting flush to the
   left edge of its 560px wrapper while the copy above and the phone pill
   below were both centred. Scoped to .center so the hero, where this same
   block is deliberately left-aligned, is unaffected. */
.center .capture--cta{ justify-content: center; }


/* Trust bar: the enterprise names, immediately under the hero. */
.trustbar{ padding-block: clamp(26px, 3.4vw, 48px); }
.trustbar__line{
  font-family: var(--f-body); font-weight: 700; font-size: .78rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
}
.routes{ display: flex; flex-wrap: wrap; gap: 10px; }

/* The strip used to sit directly under the hero, where it needed no room
   above it. It now closes the work section, against a card. */
.strip{ margin-top: clamp(30px, 3.8vw, 60px); }
.strip__head{ margin-bottom: clamp(10px, 1.4vw, 18px); }


/* ── The enterprise band ─────────────────────────────────────────────
   Brand colour at full strength rather than as an accent. Not a dark
   section: this is #A41E22, the same maroon already on every button and
   the masthead flag, so it reads as the brand turned up, not as the
   near-blacks the brief ruled out.

   Enterprise and the gap share it. They are one argument, and running
   them as two grounds put a 6% wash directly against full colour.

   Every alpha here was measured against #A41E22. White at 50%, which the
   study proposed for the lanes, is 2.88:1 and fails the 3:1 minimum for a
   UI line, so lanes sit at 66% (4.03:1) and the quiet label at 62%
   (3.72:1, large text only, which is what it is). */
.band--brand{
  /* Literals, not var(--brand): this same rule redefines --brand to white
     for the type inside, and custom properties resolve at use time, so the
     gradient was reading its own override and painting white on white. */
  background: linear-gradient(168deg, #A41E22 0%, #8A181B 62%, #7A1417 100%);
  --ink-1: #FFFFFF;
  --ink-2: rgba(255,255,255,.82);
  --ink-3: rgba(255,255,255,.66);
  --line:  rgba(255,255,255,.26);
  --line-soft: rgba(255,255,255,.16);
  --brand: #FFFFFF;
  --lift: none;
  color: #FFFFFF;
}
.band--brand + .band--brand{ margin-top: -1px; }   /* one continuous ground */
.band--brand h2, .band--brand h3{ color: #FFFFFF; }
.band--brand .shead__n{ color: rgba(255,255,255,.66); }
.band--brand .shead__n::before{ background: rgba(255,255,255,.5); }
.band--brand .btn--ghost{ color: #FFFFFF; border-color: rgba(255,255,255,.42); }
.band--brand .btn--ghost:hover{ border-color: #FFFFFF; background: rgba(255,255,255,.08); }

/* Canvas palette, read by converge.js and leak.js. */
.band--brand .converge__stage, .band--brand.converge{
  --cv-lane:  rgba(255,255,255,.52);
  --cv-label: #FFFFFF;
  --cv-spine: #FFFFFF;
  --cv-dot:   #FFFFFF;
}
.band--brand .leak{
  --lk-line:  rgba(255,255,255,.66);
  --lk-dot:   rgba(255,255,255,.5);
  --lk-loss:  #FFFFFF;
  --lk-label: rgba(255,255,255,.82);
}
.band--brand .leak__n{ color: #FFFFFF; }
@media (min-width: 760px){ }
.b-tag{
  display: block; margin-bottom: .8rem;
  font-family: var(--f-body); font-weight: 700; font-size: .66rem;
  letter-spacing: .17em; text-transform: uppercase; color: rgba(255,255,255,.62);
}
.b-cap{
  display: block; margin-top: .6rem; max-width: 30ch;
  font-size: .88rem; line-height: 1.45; color: rgba(255,255,255,.76);
}
:root[data-pill="red"] .band--brand{
  background: linear-gradient(168deg, #7E1619 0%, #5E1013 70%, #4A0D0F 100%);
}


/* ── coreAssist plan picker ──────────────────────────────────────────
   Was a raw range input at 30px tall with the browser's own track, which
   on the dark ground rendered as a solid white bar and became the
   loudest object in the section. Rebuilt: a thin rail, a brand fill, and
   the levels as real buttons, because drag-only is the least reliable
   control there is on a touch screen. */
.plan{
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--paper); box-shadow: var(--lift);
  padding: clamp(20px, 3vw, 40px);
}
.plan__top{ display: grid; gap: clamp(20px, 3vw, 44px); align-items: start; }
@media (min-width: 820px){ .plan__top{ grid-template-columns: minmax(0,1fr) minmax(0,1fr); } }
.plan__fig{
  font-family: var(--f-display); font-weight: 900; line-height: .92;
  font-size: clamp(2.8rem, 7vw, 4.6rem); letter-spacing: -.04em; color: var(--ink-1);
  font-variant-numeric: tabular-nums;
}
.plan__fig .per{ font-size: .26em; font-weight: 700; color: var(--ink-3); letter-spacing: 0; margin-left: .15em; }
.plan__hours{
  font-family: var(--f-body); font-weight: 700; font-size: .78rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); margin-top: 10px;
}
/* The right half used to hold one floating line of terms. */
.plan__terms{ display: grid; gap: 12px; margin: 0; align-content: start; }
.plan__terms > div{
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding-bottom: 10px; border-bottom: 1px solid var(--line-soft);
}
.plan__terms dt{
  font-family: var(--f-body); font-weight: 700; font-size: .7rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
}
.plan__terms dd{ margin: 0; font-weight: 600; color: var(--ink-1); font-size: .95rem; text-align: right; }

/* Slider: the input stays for keyboard and drag, but is made invisible
   and laid over the drawn rail. */
.plan__slider{ position: relative; margin-top: clamp(26px, 3.4vw, 44px); padding-top: 6px; }
.plan__slider input[type="range"]{
  position: absolute; left: 0; top: 0; width: 100%; height: 34px; margin: 0;
  opacity: 0; cursor: pointer; z-index: 2;
}
.plan__rail{
  position: relative; height: 6px; border-radius: 999px;
  background: var(--line); overflow: hidden;
}
.plan__fill{
  position: absolute; inset: 0 auto 0 0; width: 0%;
  background: linear-gradient(90deg, var(--brand-deep), var(--brand));
  border-radius: 999px; transition: width .32s var(--ease-snap);
}
.plan__steps{ display: grid; grid-template-columns: repeat(4, 1fr); margin-top: 14px; }
.plan__step{
  display: grid; justify-items: center; gap: 6px; padding: 0 4px;
  background: none; border: 0; cursor: pointer; font: inherit;
}
.plan__dot{
  width: 13px; height: 13px; border-radius: 50%; margin-top: -26px;
  background: var(--paper); border: 2px solid var(--line);
  transition: border-color .25s var(--ease-snap), background .25s var(--ease-snap),
              transform .25s var(--ease-snap), box-shadow .25s var(--ease-snap);
}
.plan__step b{
  font-family: var(--f-body); font-weight: 700; font-size: .78rem;
  letter-spacing: .08em; color: var(--ink-3); transition: color .25s var(--ease-out);
}
.plan__step i{
  font-style: normal; font-family: var(--f-body); font-weight: 600;
  font-size: .8rem; color: var(--ink-3); opacity: .7; font-variant-numeric: tabular-nums;
}
.plan__step.is-on .plan__dot{
  background: var(--brand); border-color: var(--brand);
  transform: scale(1.5); box-shadow: 0 0 0 5px var(--brand-wash);
}
.plan__step.is-on b, .plan__step.is-on i{ color: var(--brand); opacity: 1; }
@media (hover: hover){ .plan__step:hover .plan__dot{ border-color: var(--brand); } }
.plan__slider input:focus-visible + .plan__rail{ outline: 2px solid var(--brand); outline-offset: 4px; }

/* Coverage: included is stated, locked says what unlocks it. Fading the
   text to 34% opacity read as broken rather than as not yet included. */
.cover{
  margin-top: clamp(24px, 3vw, 38px); border: 1px solid var(--line);
  border-radius: var(--r-md); overflow: hidden; background: var(--line-soft);
  display: grid; gap: 1px;
}
@media (min-width: 780px){ .cover{ grid-template-columns: 1fr 1fr; } }
.cover__row{
  display: flex; align-items: center; gap: 12px;
  padding: 14px 18px; background: var(--paper);
  transition: background .3s var(--ease-out), color .3s var(--ease-out);
}
.cover__row::before{
  content: ""; flex: none; width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid var(--line); transition: all .3s var(--ease-snap);
}
.cover__row[data-on="true"]::before{
  border-color: var(--brand); background: var(--brand);
  box-shadow: inset 0 0 0 2px var(--paper);
}
.cover__row b{ font-family: var(--f-body); font-weight: 600; font-size: .95rem; color: var(--ink-1); flex: 1; }
.cover__row[data-on="false"] b{ color: var(--ink-3); }
.cover__tier{
  flex: none; font-family: var(--f-body); font-weight: 700; font-size: .66rem;
  letter-spacing: .09em; padding: 4px 9px; border-radius: 999px;
  border: 1px solid var(--line); color: var(--ink-3);
}
.cover__row[data-on="true"] .cover__tier{ border-color: transparent; color: var(--brand); background: var(--brand-wash); }
:root[data-pill="red"] .plan{ background: rgba(255,255,255,.04); }
:root[data-pill="red"] .cover{ background: var(--line); }
:root[data-pill="red"] .cover__row{ background: #1A1112; }
:root[data-pill="red"] .plan__dot{ background: #1A1112; }


/* Interior page heroes carry two-sentence headlines; the homepage carries
   a five word poster line. They cannot share a size. The base h1 tops out
   at 7rem, and the red mode override pushed it to 7.5rem, so a product
   headline ran six lines and filled the viewport on its own. The homepage
   keeps its own size through the more specific .hero-grid rule. */
.phero h1{ font-size: clamp(2.1rem, 4.4vw, 3.7rem); letter-spacing: -.035em; line-height: 1; }
:root[data-pill="red"] .phero h1{ font-size: clamp(2.2rem, 4.7vw, 4rem); letter-spacing: -.04em; }


/* ── Enterprise section, merged ──────────────────────────────────────
   Head and symptoms share a row so the recognition lands beside the
   claim rather than three paragraphs below it. */
.ent__head{ display: grid; gap: clamp(20px, 3vw, 52px); align-items: start; }
@media (min-width: 900px){ .ent__head{ grid-template-columns: minmax(0,1.1fr) minmax(0,.9fr); } }
.ent__symptoms{ list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; align-content: start; }
@media (min-width: 900px){ .ent__symptoms{ margin-top: 34px; } }
.ent__symptoms{ border-left: 1px solid rgba(255,255,255,.32); padding-left: clamp(16px,1.8vw,26px); }
.ent__symptoms li{
  font-size: clamp(1rem, 1.15vw, 1.12rem); color: rgba(255,255,255,.86);
}
.ent__note{
  margin-top: clamp(14px, 2vw, 22px); max-width: 46rem;
  font-size: clamp(1rem, 1.15vw, 1.12rem); color: rgba(255,255,255,.78);
}
/* The proof band sits directly under the scrub band. Each .band--brand
   paints the full gradient, so two adjacent ones restart it and leave a
   visible step. This one continues from where the other ended. */
.ent__proof{
  padding-top: clamp(28px, 4vw, 56px);
  background: linear-gradient(168deg, #7A1417 0%, #6E1215 100%);
}
:root[data-pill="red"] .ent__proof{ background: linear-gradient(168deg, #4A0D0F 0%, #400B0D 100%); }

.ent__value{
  margin-top: clamp(20px, 2.6vw, 34px); max-width: 52rem;
  font-size: clamp(1.02rem, 1.2vw, 1.18rem); line-height: 1.55;
  color: rgba(255,255,255,.84);
  padding-top: clamp(16px, 2vw, 24px);
}
.ent__value b{ color: #FFFFFF; font-weight: 800; }


/* The sticky stage is exactly 100vh with overflow:hidden and its content
   centred, so anything taller than the viewport is clipped at both ends
   and the eyebrow loses its top half. Measured at 760px tall: 785px of
   content in a 760px box. Everything inside scales down with the
   viewport's height, not just its width. */
@media (max-height: 900px){
  .converge__stage{ max-height: 42vh; }
  .ent__head{ gap: clamp(14px, 2vw, 30px); }
  .ent__head h2{ font-size: clamp(1.7rem, 3vw, 2.7rem); }
  .ent__symptoms{ gap: 7px; }
  .ent__symptoms li{ font-size: 1rem; }
  @media (min-width: 900px){ .ent__symptoms{ margin-top: 22px; } }
  .ent__note{ margin-top: 12px; font-size: 1rem; }
  .converge__stage.mt-8{ margin-top: 22px; }
}
@media (max-height: 760px){
  .converge__stage{ max-height: 36vh; }
  .ent__head h2{ font-size: clamp(1.55rem, 2.7vw, 2.2rem); }
  .ent__symptoms li{ font-size: .95rem; }
  .ent__note{ font-size: .95rem; }
}


/* ── Estimate intake ─────────────────────────────────────────────────
   The page asked for a URL and promised a real number in two days. This
   asks what is actually needed to price the work, and branches, because
   the enterprise and AI buyers often have no site to give. */
.estimate__grid{ grid-template-columns: minmax(0,1.35fr) minmax(0,.65fr); }
/* The form runs to about 1,800px and the contact card is 500px, so by the
   time you reach the submit button the phone number has been off screen
   for a while. The card follows instead.

   A grid item stretches to the row by default, and a stretched item has
   no room left to stick in, so it needs align-self:start before sticky
   does anything. top clears the fixed masthead. */
@media (min-width: 941px){
  .estimate__grid > :last-child{ position: sticky; top: calc(var(--flag-h) + 20px); align-self: start; }
}
@media (max-width: 940px){ .estimate__grid{ grid-template-columns: minmax(0,1fr); } }
/* Nothing to follow on one column: the card simply sits after the form. */
@media (prefers-reduced-motion: reduce){ .estimate__grid > :last-child{ position: static; } }

.intake{ display: grid; gap: clamp(36px, 4.4vw, 58px); }
.fset{ border: 0; margin: 0; padding: 0; display: grid; gap: 24px; }
.fset__l{
  font-family: var(--f-body); font-weight: 700; font-size: .74rem;
  letter-spacing: .12em; text-transform: uppercase; color: var(--brand);
  /* The rule was sitting almost on the label, and the content almost
     on the rule. A step header needs air on both sides of its line. */
  padding: 0 0 18px; border-bottom: 1px solid var(--line); width: 100%;
}
/* .fset is a grid with a 24px gap, but a <legend> inside a <fieldset> is
   laid out by the fieldset itself and never becomes a grid item, so the
   gap never applied to it: measured 0px between the rule and the first
   card on steps 1, 3 and 4, against 14px on step 2 where the label is a
   plain div. The air below the rule has to be its own margin. */
legend.fset__l{ margin-bottom: 24px; }
.needs{ display: grid; gap: 14px; }
@media (min-width: 620px){ .needs{ grid-template-columns: 1fr 1fr; } }
.need input{ position: absolute; opacity: 0; pointer-events: none; }
.need__b{
  display: grid; gap: 3px; padding: 14px 16px; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--paper);
  transition: border-color .2s var(--ease-snap), background .2s var(--ease-snap);
}
.need__b b{ font-family: var(--f-body); font-weight: 700; font-size: 1rem; color: var(--ink-1); }
.need__b i{ font-style: normal; font-size: .88rem; color: var(--ink-3); line-height: 1.4; }
.need input:checked + .need__b{ border-color: var(--brand); background: var(--brand-wash); }
.need input:focus-visible + .need__b{ outline: 2px solid var(--brand); outline-offset: 2px; }

/* gap matches the legend margin above, so step 2's rule sits the same
   distance from its content as steps 1, 3 and 4 do from theirs. */
.fset--branch{ padding: clamp(20px,2.2vw,26px); border: 1px solid var(--line);
               border-radius: var(--r-md); background: var(--brand-wash);
               gap: 24px; }
.fset__hint{ margin: 0; font-size: .93rem; line-height: 1.55; color: var(--ink-3); max-width: 56ch; }
.fq{ display: grid; gap: 13px; }
.fq + .fq{ margin-top: 26px; }
.fq__q{ font-family: var(--f-body); font-weight: 600; font-size: .95rem; color: var(--ink-1); }
.opts{ display: flex; flex-wrap: wrap; gap: 8px; }
.opt input{ position: absolute; opacity: 0; pointer-events: none; }
.opt span{
  display: inline-block; padding: 8px 14px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 999px; background: var(--paper);
  font-size: .9rem; color: var(--ink-2);
  transition: border-color .2s var(--ease-snap), background .2s var(--ease-snap), color .2s;
}
.opt input:checked + span{ border-color: var(--brand); background: var(--brand); color: #fff; }
.opt input:focus-visible + span{ outline: 2px solid var(--brand); outline-offset: 2px; }

.grid2{ display: grid; gap: 20px; }
@media (min-width: 620px){ .grid2{ grid-template-columns: 1fr 1fr; } .fld--wide{ grid-column: 1 / -1; } }
.fld{ display: grid; gap: 6px; }
.fld > span{
  font-family: var(--f-body); font-weight: 600; font-size: .82rem; color: var(--ink-2);
}
.fld em{ font-style: normal; color: var(--brand); margin-left: 2px; }
.fld input, .fld textarea{
  width: 100%; padding: 12px 14px; font: inherit; font-size: .96rem;
  color: var(--ink-1); background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--r-md);
}
.fld textarea{ resize: vertical; }
.fld input:focus, .fld textarea:focus{ outline: 2px solid var(--brand); outline-offset: 1px; border-color: var(--brand); }
.fld input[aria-invalid="true"]{ border-color: var(--brand); background: var(--brand-wash); }

.intake__foot{ display: flex; flex-wrap: wrap; align-items: center; gap: 14px 20px; }
.intake__note{ font-size: .86rem; color: var(--ink-3); max-width: 34rem; margin: 0; }
.intake__note[data-state="error"]{ color: var(--brand); font-weight: 600; }

:root[data-pill="red"] .need__b,
:root[data-pill="red"] .opt span,
:root[data-pill="red"] .fld input,
:root[data-pill="red"] .fld textarea{ background: rgba(255,255,255,.05); }


/* Tighten the nav between the breakpoint and 1560 so the brand keeps its
   room. Measured at 1400: the group started at x59 with the pennant
   running 58 to 258, so the wordmark was completely covered. */
@media (max-width: 1559px){
  .lnk{ padding: 10px 11px; font-size: 14.5px; }
  .barc__group{ padding-right: 6px; }
}



/* The maroon is a panel now, not a wall. Full bleed it ran 1185px of red
   through the middle of the scroll to make one point; as a contained
   object it is about a third of that, and the headline and the result sit
   on the page's own ground where they read as part of the page. */
.entpanel{
  border-radius: var(--r-lg);
  padding: clamp(22px, 2.6vw, 40px) clamp(20px, 2.4vw, 36px) clamp(18px, 2vw, 28px);
}
.entpanel .converge__stage{ max-height: 460px; }
/* Five labelled lanes need vertical room. At 16/7 a 310px phone stage is
   only 136px tall, which stacks the lanes 25px apart with 11px labels. */
@media (max-width: 760px){
  .entpanel .converge__stage, .converge__stage{ aspect-ratio: 5 / 4; max-height: none; }
}
.entpanel .ent__note{
  margin-top: clamp(12px, 1.6vw, 20px); color: rgba(255,255,255,.82);
  border-top: 1px solid rgba(255,255,255,.24); padding-top: clamp(12px,1.6vw,18px);
}
/* Back on the light ground, these take the page's own ink again. */
.converge .ent__symptoms{ border-left-color: var(--line); }
.converge .ent__symptoms li{ color: var(--ink-2); }
.converge .b-tag{ color: var(--ink-3); }
.converge .b-cap{ color: var(--ink-3); }
.converge .ent__value{ color: var(--ink-2); }
.converge .ent__value b{ color: var(--brand); }

/* Long-form policy pages: the section headings are h2 because that is
   what they are in the document, but they are body-scale headings, not
   the display h2 used to open a section of the marketing site. */
.flow h2{
  font-weight: 700; font-size: clamp(1.5rem, 2.1vw, 1.95rem);
  line-height: 1.16; letter-spacing: -.02em; font-variation-settings: normal;
}


/* ── Enterprise proofs, one rank ──────────────────────────────────
   Four clients at equal, compact weight. The previous treatment gave
   three of them full-width blocks running 558, 394 and 623px, which
   was a third of the page before the reader reached the live work, so
   the examples read as an afterthought to the credentials. Same four
   claims, a quarter of the height, and the room goes to the sites you
   can actually click into. */
.proof{
  display: grid; align-content: start; gap: 10px;
  padding: clamp(20px, 2.2vw, 30px);
  background: var(--paper); border-radius: var(--r-lg); box-shadow: var(--lift);
}
/* ── Client marks, matched by optical area ───────────────────────────
   Capping every logo at one max-height and one max-width matches them
   numerically and not visually. A wide wordmark hits the width cap and
   renders short; a square mark hits the height cap and renders small.
   Measured on the portfolio cards before this: KFC rendered 52x52 for
   2,704px of optical area against 5,135 to 5,756 for the wordmarks
   beside it, so it read at half their weight even with the hand-tuned
   exception it already had. That turned out to be a bad source file
   rather than a bad rule: kfc.svg declared a square 24x24 viewBox
   around a glyph only 7.54 tall, so 68% of what every height cap
   measured was empty. The viewBox is now trimmed to the glyph and KFC
   is an ordinary ratio-3.18 wordmark, sized by the formula below with
   no exception at all.

   Heights below are generated, not eyeballed: for each logo's real
   aspect ratio r, height = BASE * (1/r)^0.4, with BASE set so a ratio-3
   wordmark lands on 54px. The 0.4 exponent rather than a true 0.5 area
   match is deliberate, because a square mark reads heavier than a
   wordmark of identical area. That lands every mark between 4,225 and
   6,233px of area instead of 2,704 to 5,756.

   Regenerate if a logo is added or replaced: the ratios come from the
   files themselves, PNG headers and SVG viewBoxes. ─────────────────── */
.proof__mark{ display: flex; align-items: center; height: 96px; margin-bottom: 4px; }
.proof__mark img{
  max-height: 54px; max-width: 240px; width: auto; height: auto;
  object-fit: contain; object-position: left center;
}
  .proof__mark img[src$="drevet-light.png"]{ max-height: 60px; }
  .proof__mark img[src$="drevet-mono.png"]{ max-height: 60px; }
  .proof__mark img[src$="drevet.png"]{ max-height: 60px; }
  .proof__mark img[src$="ticgums.png"]{ max-height: 57px; }
  .proof__mark img[src$="oclc-dark.png"]{ max-height: 54px; }
  .proof__mark img[src$="oclc.png"]{ max-height: 54px; }
  .proof__mark img[src$="who.svg"]{ max-height: 53px; }
  .proof__mark img[src$="ganim.png"]{ max-height: 53px; }
  .proof__mark img[src$="thieme.png"]{ max-height: 50px; }
  .proof__mark img[src$="didage.png"]{ max-height: 50px; }
  .proof__mark img[src$="lantech.png"]{ max-height: 48px; }
    .proof__mark img[src$="fraudsniffr-dark.png"]{ max-height: 45px; }
  .proof__mark img[src$="fraudsniffr.png"]{ max-height: 45px; }
  .proof__mark img[src$="dremed-light.png"]{ max-height: 44px; }
  .proof__mark img[src$="dremed-mono.png"]{ max-height: 44px; }
  .proof__mark img[src$="dremed.png"]{ max-height: 44px; }
  .proof__mark img[src$="marygrove.svg"]{ max-height: 40px; }
.proof__n{
  font-family: var(--f-body); font-size: .74rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--brand);
}
.proof h3{ font-size: clamp(1.15rem, 1.55vw, 1.42rem); line-height: 1.18; }
.proof p{ font-size: .93rem; line-height: 1.55; color: var(--ink-3); margin: 0; }
.proof__stats{ display: flex; flex-wrap: wrap; gap: 10px 30px; margin-top: 6px; }
.proof__stats .stat__n{
  font-family: var(--f-display); font-weight: 800;
  font-size: clamp(1.5rem, 2vw, 1.85rem);
  color: var(--ink-1); line-height: 1.1;
}
/* The suffix carries the unit, so it is the half you have to be able to
   read: "years", "-figure". At .55em of an 18.9px number it was 10.4px. */
.proof__stats .stat__n .suf{ color: var(--ink-3); font-size: .6em; margin-left: .1em; }
.proof__stats .stat__l{ font-size: .84rem; color: var(--ink-3); margin-top: 4px; }
/* The arrow is sized by a rule scoped to .card, so outside one it fell
   back to the SVG default of 300x150 and rendered 407px tall, which
   dragged its whole grid row to 708px. */
.proof .card__go{ margin-top: 4px; align-items: center; }
.proof .card__go svg{ width: 17px; height: 17px; flex: none; }

/* One rank means one height: the row is equalised so a client with a
   stat line and a client without still read as the same kind of thing. */
.proofs{ grid-auto-rows: 1fr; }
@media (max-width: 720px){
  /* Scaled from the desktop box rather than re-tuned, so the optical
     match above survives the breakpoint. */
  .proof__mark{ height: 52px; }
  .proof__mark img{ max-height: 32px; }
}

/* The marks that are dark ink need the same white treatment here that
   they already get in the feature and case blocks. */
:root[data-pill="red"] .proof__mark img{ filter: grayscale(1) brightness(0) invert(1) opacity(.92); }
:root[data-pill="red"] .proof__mark img[src$="clients/fraudsniffr.png"]{
  content: url(clients/fraudsniffr-dark.png); filter: none;
}
:root[data-pill="red"] .proof__mark img[src$="clients/oclc.png"]{
  content: url(clients/oclc-dark.png); filter: none;
}
:root[data-pill="red"] .proof{ background: rgba(255,255,255,.04); box-shadow: none; border: 1px solid var(--line); }

/* The live examples are what the page is for, so they get the width.
   Four across put every site in a 280px card; two across roughly
   doubles them and puts them on a par with the proofs beside them. */
@media (max-width: 900px){ .grid.g-2{ grid-template-columns: minmax(0,1fr); } }


/* ── Homepage work blocks, one height ─────────────────────────────
   The four ran 502, 384, 523 and 623px, so a row that is meant to read
   as four peers read as four different components. FraudSniffr's block
   is the target. Two things drove the spread: three or four stats
   wrapping onto a second row (+111px on two of them) and a square
   client mark forcing a 261px media column. Both are held here rather
   than by cutting the claims. */
/* With the two height drivers held, the four land within 96px of each
   other; this closes the last of it so they are literally one height. */
/* Desktop only: stacked on a phone, equal rows would pad every block
   out to the tallest one's content and leave three dead screens. */
/* grid-auto-rows: 1fr used to sit here, making all four cards as tall as the
   tallest. .cases is a single column, so equal heights bought nothing and cost
   the shorter cards their padding: with align-items:start the whole surplus
   fell below the content. The WHO card read 43px above and 88px below. Each
   card sizes to its own content now. */
.cases .case{ padding: clamp(26px, 3vw, 42px); }
.cases .case--lead{ padding: clamp(26px, 3vw, 42px); }
.cases .slab__stats{
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  gap: 20px; align-items: start;
}
.cases .slab__stats .stat__n{ font-size: clamp(1.55rem, 2.3vw, 2.05rem); }
.cases .slab__stats .stat__l{ font-size: .86rem; }
.cases .case__body h3{ font-size: clamp(1.45rem, 2.1vw, 1.9rem); }
.cases .case__body .lead{ font-size: 1rem; line-height: 1.5; }
.cases .case__media{ max-height: 104px; align-items: flex-start; }
.cases .case__media img{
  max-height: 104px; max-width: 230px; width: auto; height: auto;
  object-fit: contain; object-position: left center;
}
.cases .case__body .mt-4{ margin-top: 10px; }
.cases .case__body .mt-6{ margin-top: 14px; }
.cases .case__body .mt-8{ margin-top: 18px; }
.cases .case__body .mt-10{ margin-top: 20px; }


/* The fun-sites plates run the real site over their own screenshot. */
.strip__plate iframe{
  position: absolute; top: 0; left: 0; border: 0; transform-origin: 0 0;
  opacity: 0; transition: opacity .55s var(--ease-out); pointer-events: none;
}
.strip__plate iframe.is-in{ opacity: 1; }
/* The caption has to stay legible once a whole site is running behind it. */
.strip__plate .strip__cap{ z-index: 2; }


/* DRE Medical and DRE Veterinary are full-colour lockups drawn for a dark
   ground. Two treatments both failed them: the shelf's dark filter is
   grayscale then brightness(0) then invert(1), which collapses every
   opaque pixel to one white and turned the globe into a plain disc; and
   showing them as drawn left two blue marks in a row of light-grey ones.

   These are single-tone renders instead. Luminance is mapped onto a light
   grey band (112 to 255, nineteen steps), so the globe keeps its
   structure while the mark still reads as one colour alongside its
   neighbours. Hover still reveals the real artwork, as it does for every
   other mark on the shelf. */
/* Light page, same problem mirrored. brightness(0) paints the whole mark
   one flat black, so the globe was a plain disc there too. These marks are
   drawn for a dark ground, which means their BRIGHT parts are the ink, so
   the light-page render inverts the ramp: bright source becomes dark ink.
   Banded 100 to 170 so the average lands on the neighbours' 130.1 with 70
   levels left for the sphere. Hover still gives them the dark ground they
   were drawn for, with the real artwork on it. */
:root[data-pill="blue"] .marq__i img.marq--dremed{
  content: url(clients/dremed-light.png); filter: none; opacity: 1;
}
:root[data-pill="blue"] .marq__i img.marq--drevet{
  content: url(clients/drevet-light.png); filter: none; opacity: 1;
}
/* On hover dremed shows -positive: the globe exactly as DRE publishes it,
   with the wordmark taken from white to #003C7B. That navy is not invented,
   it is the most common dark value inside DRE's own globe (98% of its dark
   blue pixels) and reads 10.87:1 on white. The globe is protected by its own
   dilated shape, because it carries near-white highlight dots that are part
   of the artwork; a straight near-white rewrite flattened them.

   drevet does not get the same treatment. Its wordmark is white with a thin
   dark outline, so recolouring the fill leaves hollow letters, and its globe
   is light enough that protecting it costs the effect. It keeps the light
   cut, which is clean and legible, and takes the lift and the rule like
   every other mark.

   Both are derivatives. DRE publishes only reverse artwork, so if they ever
   issue a positive cut it should replace this. */
@media (hover: hover){
  :root[data-pill="blue"] .marq__i img.marq--dremed:hover{
    content: url(clients/dremed-positive.png);
  }
}
@media (hover: none){
  :root[data-pill="blue"] .marq__i img.marq--dremed{
    content: url(clients/dremed-light.png); filter: none; opacity: 1;
  }
  :root[data-pill="blue"] .marq__i img.marq--drevet{
    content: url(clients/drevet-light.png); filter: none; opacity: 1;
  }
}

:root[data-pill="red"] .marq__i img.marq--dremed{
  content: url(clients/dremed-mono.png); filter: none; opacity: .62;
}
:root[data-pill="red"] .marq__i img.marq--drevet{
  content: url(clients/drevet-mono.png); filter: none; opacity: .62;
}
@media (hover: hover){
  :root[data-pill="red"] .marq__i img.marq--dremed:hover{
    content: url(clients/dremed.png); filter: none; opacity: 1;
  }
  :root[data-pill="red"] .marq__i img.marq--drevet:hover{
    content: url(clients/drevet.png); filter: none; opacity: 1;
  }
}
@media (hover: none){
  :root[data-pill="red"] .marq__i img.marq--dremed{
    content: url(clients/dremed-mono.png); filter: none; opacity: .78;
  }
  :root[data-pill="red"] .marq__i img.marq--drevet{
    content: url(clients/drevet-mono.png); filter: none; opacity: .78;
  }
}


/* ── coreCerebrum · the running board ─────────────────────────────
   Ported from the v2 product site. The page argued that the board is
   the interface and then showed no board; this is the argument made
   visible. Seeded, so it is identical on every load. */
.bframe{
  border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden; background: var(--paper-2); box-shadow: var(--lift);
}
.bframe__bar{
  display: flex; align-items: center; gap: 9px;
  padding: 11px 15px; border-bottom: 1px solid var(--line);
  font-family: var(--f-mono); font-size: .72rem; letter-spacing: .03em; color: var(--ink-3);
}
.bdot{
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--ink-3); display: inline-block;
}
.bdot.is-run{ background: #2E9E5B; }
.bdot.is-rev{ background: #C98A1B; }
.bdot.is-warn{ background: var(--brand); }
.bboard{
  display: grid; grid-template-columns: repeat(4, minmax(0,1fr));
  gap: 1px; background: var(--line); padding: 1px;
}
@media (max-width: 780px){
  .bboard{ grid-template-columns: repeat(2, minmax(0,1fr)); }
}
.bcol{ background: var(--paper); padding: 12px 11px 14px; min-width: 0; }
.bcol__hd{
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-family: var(--f-body); font-size: .72rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
  padding-bottom: 10px; border-bottom: 1px solid var(--line-soft); margin-bottom: 11px;
}
.bcol__ct{ font-variant-numeric: tabular-nums; color: var(--ink-2); }
.bcol__bd{ display: grid; gap: 9px; align-content: start; min-height: 168px; }
.bcard{
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--paper-2); padding: 10px 11px; min-width: 0;
}
.bcard.is-moving{ animation: bslide .42s var(--ease-out) both; }
@keyframes bslide{ from{ opacity: 0; transform: translateY(-8px); } to{ opacity: 1; transform: none; } }
.bcard__repo{
  font-family: var(--f-mono); font-size: .62rem; letter-spacing: .04em;
  color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bcard__t{
  font-family: var(--f-body); font-weight: 700; font-size: .82rem; line-height: 1.25;
  color: var(--ink-1); margin: 5px 0 7px;
}
.bcard__br{
  display: flex; align-items: center; gap: 6px;
  font-family: var(--f-mono); font-size: .62rem; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bcard__df{ display: flex; gap: 9px; margin-top: 7px; font-family: var(--f-mono); font-size: .62rem; }
.bcard__df .a{ color: #2E9E5B; }
.bcard__df .d{ color: var(--brand); }

/* ── the live session log ─────────────────────────────────────────
   "Where the waste goes" was an argument with nothing under it. */
.clog{
  border: 1px solid var(--line); border-radius: var(--r-md);
  overflow: hidden; background: var(--paper-2);
}
.clog__hd{
  display: flex; align-items: center; gap: 9px; padding: 9px 13px;
  border-bottom: 1px solid var(--line);
  font-family: var(--f-mono); font-size: .68rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
}
.clog__bd{
  display: grid; gap: 4px; padding: 11px 13px 13px;
  min-height: 148px; align-content: start;
  font-family: var(--f-mono); font-size: .72rem; line-height: 1.5;
}

/* Paired with the /cost ledger, the log is half its height and leaves a hole in
   the column. Rather than padding it with more invented log lines, let it fill
   the row and anchor its rows to the bottom: new lines push up from the floor
   and the empty space sits above them, which is how a terminal scrollback reads
   anyway. Scoped to .clog-pair so a standalone log is unchanged. */
.clog-pair{ display: flex; flex-direction: column; height: 100%; }
.clog-pair > .clog{ flex: 1; display: flex; flex-direction: column; }
.clog-pair > .clog > .clog__bd{ flex: 1; align-content: end; }
.clog__row{ display: flex; gap: 9px; align-items: baseline; animation: bslide .3s var(--ease-out) both; }
.clog__t{ color: var(--ink-3); font-variant-numeric: tabular-nums; flex: none; }
.clog__i{ flex: none; width: 1ch; text-align: center; }
.clog__i.is-ok{ color: #2E9E5B; }
.clog__i.is-go{ color: var(--ink-2); }
.clog__i.is-mem{ color: #7A5CC4; }
.clog__i.is-warn{ color: var(--brand); }
.clog__m{ color: var(--ink-2); min-width: 0; }

:root[data-pill="red"] .bframe,
:root[data-pill="red"] .clog{ background: rgba(255,255,255,.04); box-shadow: none; }
:root[data-pill="red"] .bcol{ background: rgba(255,255,255,.02); }
:root[data-pill="red"] .bcard{ background: rgba(255,255,255,.05); }
:root[data-pill="red"] .clog__i.is-mem{ color: #B79BF0; }
@media (prefers-reduced-motion: reduce){
  .bcard.is-moving, .clog__row{ animation: none; }
}


/* ── coreCerebrum product rail ────────────────────────────────────
   Six child pages hang off the product page, so a reader who lands on
   Compare from search can find the rest of it. Scrolls rather than
   wraps on a phone: seven items will not fit and a wrapped rail reads
   as a list rather than a rail. */
.subnav{
  display: flex; gap: 6px; overflow-x: auto; padding-bottom: 4px;
  -webkit-overflow-scrolling: touch; scrollbar-width: none;
  /* A scroll container can only scroll if its own width is constrained.
     As a grid/flex child it sizes to its content by default, so the rail
     grew to 728px and took the page with it instead of clipping. */
  min-width: 0; max-width: 100%;
}
.subnav::-webkit-scrollbar{ display: none; }
.subnav__i{
  flex: none; padding: 9px 15px; border-radius: var(--r-pill);
  border: 1px solid var(--line); background: var(--paper);
  font-family: var(--f-body); font-size: .82rem; font-weight: 600;
  color: var(--ink-2); white-space: nowrap;
  transition: border-color .2s var(--ease-snap), color .2s, background .2s;
}
.subnav__i:hover{ border-color: var(--brand-hair); color: var(--brand); }
.subnav__i.is-on{ background: var(--brand); border-color: var(--brand); color: #fff; }
:root[data-pill="red"] .subnav__i{ background: rgba(255,255,255,.05); }
:root[data-pill="red"] .subnav__i.is-on{ background: var(--brand); }

/* A comparison with five product columns cannot shrink to a phone, so
   it scrolls inside its own box rather than squeezing the page. */
.tblwrap{ overflow-x: auto; -webkit-overflow-scrolling: touch; min-width: 0; max-width: 100%; }
.tblwrap .cmp{ min-width: 0; }
.cmp--wide{ min-width: 760px; }

/* Terminal-style transcript blocks on the product children. */
.ledger__b{
  padding: 9px 20px; border-bottom: 1px solid var(--line-soft);
  font-family: var(--f-mono); font-size: .78rem; line-height: 1.45; color: var(--ink-2);
}
.ledger__b code{ font: inherit; color: inherit; background: none; padding: 0; }
.ledger__b:last-child{ border-bottom: 0; }
.ledger__b.is-ok code{ color: #2E9E5B; }
.ledger__b.is-no code{ color: var(--brand); }


/* ── Dark mode text contrast ──────────────────────────────────────
   Measured across all 52 pages with proper alpha compositing: brand
   maroon used as TEXT ran 1.59 to 2.59 against its own ground, and the
   sheet and footer group headings were the worst of it because they
   appear on every page. --brand is still the fill (white on it passes);
   these are the places it was being used as ink. */
:root[data-pill="red"] .sheet h2,
:root[data-pill="red"] .foot h2,
:root[data-pill="red"] .label--brand,
:root[data-pill="red"] .node__i,
:root[data-pill="red"] .cover__tier,
:root[data-pill="red"] .fset__l,
:root[data-pill="red"] .hcap__n,
:root[data-pill="red"] .proof__n,
:root[data-pill="red"] .shead__n,
:root[data-pill="red"] .card__n,
:root[data-pill="red"] .bcard__df .d,
:root[data-pill="red"] .ledger__b.is-no code,
:root[data-pill="red"] .prodrow b em,
:root[data-pill="red"] .plan__step i,
:root[data-pill="red"] .brand,
:root[data-pill="red"] h2 mark,
:root[data-pill="red"] .headcount mark{ color: var(--brand-ink); }

/* The board stacked three translucent whites, so its 9.92px mono type
   ended up on #423335, the lightest ground on the site. Flattened. */
:root[data-pill="red"] .bframe{ background: rgba(255,255,255,.03); }
:root[data-pill="red"] .bcol{ background: rgba(0,0,0,.18); }
:root[data-pill="red"] .bcard{ background: rgba(255,255,255,.035); }
:root[data-pill="red"] .bcard__df .a{ color: #35B669; }


/* ── Mobile menu, restyled to the reference ───────────────────────
   Top-level items become numbered rows with a hairline under each,
   sub-items become outlined bubbles rather than a plain stacked list,
   and the closing action is a full-width pill with a circular arrow.
   Mobile menu only: the desktop mega menu is untouched. */
.sheet{ counter-reset: sheetnav; }

.sheet a.sheet__top{
  counter-increment: sheetnav;
  display: flex; align-items: baseline; gap: 18px;
  padding: 18px 0; border-bottom: 1px solid var(--line);
}
.sheet a.sheet__top::before{
  content: counter(sheetnav, decimal-leading-zero);
  flex: none; font-family: var(--f-body); font-weight: 600;
  font-size: .82rem; letter-spacing: .12em;
  color: var(--ink-3); font-variant-numeric: tabular-nums;
}

/* Group labels sit above their bubbles, so they need less space below
   than they did above a stacked list. */
.sheet h2{ margin: 30px 0 12px; }

.sheet__subs{ display: flex; flex-wrap: wrap; gap: 9px; }
.sheet a.sheet__sub{
  display: inline-flex; align-items: center;
  padding: 11px 18px; border: 1px solid var(--line);
  border-radius: var(--r-pill); background: transparent;
  font-family: var(--f-body); font-size: .95rem; line-height: 1.2;
  color: var(--ink-1); border-bottom: 1px solid var(--line);
  transition: border-color .2s var(--ease-snap), color .2s, background .2s;
}
.sheet a.sheet__sub:last-child{ border-bottom: 1px solid var(--line); }
.sheet a.sheet__sub:active,
.sheet a.sheet__sub:focus-visible{ border-color: var(--brand-ink); color: var(--brand-ink); }

/* The closing action, as a full-width pill with the arrow in a disc. */
.sheet__go{
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  width: 100%; margin-top: 26px; padding: 18px 18px 18px 26px;
  border-radius: var(--r-pill); background: var(--brand); color: #fff;
  font-family: var(--f-display); font-weight: 800; font-size: .95rem;
  letter-spacing: .07em; text-transform: uppercase;
}
.sheet__go i{
  flex: none; display: grid; place-items: center;
  width: 46px; height: 46px; border-radius: 50%; background: #fff; color: var(--brand);
}
.sheet__go svg{ width: 20px; height: 20px; }
.sheet__tag{
  margin-top: 16px; font-family: var(--f-body); font-size: .9rem; color: var(--ink-3);
}


/* Genuinely dark in both modes, so a [data-pill] rule never reaches them and
   the mark at 2.51:1 is unreadable on them. */
.case--night .label,
.section--night .label{ color: var(--brand-lit); }

/* The mega menu panel, the product rows and the enterprise outcome block are
   NOT dark in both modes. They were in the list above, which meant the lifted
   red was being painted on a #fff panel: #E05055 on white measures 3.85 and
   fails body text, where the mark itself is 7.16. It is also simply the wrong
   red, which is what the Products dropdown was showing. They take the mark on
   the light ground and the lifted red only when the page is dark. */
.mega .node__i,
.mega .label,
.mega .card__n,
.mega .prodrow b em,
.prodrow b em{ color: var(--brand); }

:root[data-pill="red"] .mega .node__i,
:root[data-pill="red"] .mega .label,
:root[data-pill="red"] .mega .card__n,
:root[data-pill="red"] .mega .prodrow b em,
:root[data-pill="red"] .prodrow b em{ color: var(--brand-lit); }



/* Sub-items belong to the row above them, so the group is indented to
   sit under its parent rather than floating between two headings. */
.sheet__group{
  padding: 4px 0 10px 34px; border-bottom: 1px solid var(--line);
}
.sheet__group h2{ margin: 18px 0 11px; }
.sheet__group h2:first-child{ margin-top: 14px; }
@media (max-width: 400px){ .sheet__group{ padding-left: 22px; } }


/* ── Brand ink on a brand-wash panel ──────────────────────────────
   The last cluster of contrast failures all shared one shape: brand
   text sitting on a --brand-wash tint, inside a band that is dark in
   BOTH modes. So a [data-pill] scoped fix never reached them, and the
   maroon measured 1.70 to 2.40 against its own panel.

   #F17377 is the same hue lifted until it clears 4.5:1 on the darkest
   of those grounds (#472B2D, measured 4.52) and comfortably higher on
   the rest, so one value covers every case rather than seven. */
:root{ --brand-on-wash: #F17377; }

/* CORRECTION (client review): the note above assumed these sit on a dark
   wash in BOTH modes, so the rule was left unscoped. Sampling the actual
   painted pixels says otherwise: in light mode the grounds are #FFFFFF,
   #EBE9E7, the brand wash and #C0B1AC, and #F17377 measured 1.36 to 2.82 on
   them (the wash was #FAF2F2 when sampled, it is #F2F1F1 now),
   including the "Ask for access" CTA. The lift belongs to dark mode only. */
:root[data-pill="red"] .steps b,
:root[data-pill="red"] .vs__col--yes .label,
:root[data-pill="red"] .ledger__row.is-total b,
:root[data-pill="red"] .plan__step.is-on b,
:root[data-pill="red"] .plan__step.is-on i,
:root[data-pill="red"] .lead-card .initials,
:root[data-pill="red"] .ptable__name em,
:root[data-pill="red"] .ptable__terms a,
:root[data-pill="red"] .ptable__row .ptable__name em{ color: var(--brand-on-wash); }

/* The console easter egg's comment line, measured 4.20 on its own ground. */
.lens__egg c,
.lens .c{ color: #837572; }


/* ── Handover transcript palette ──────────────────────────────────
   The canvas reads these rather than carrying colours of its own, so
   each mode sets its own set. The handover sits on white in light mode
   and on near-black in dark, so one palette cannot serve both: every
   value below is measured at 4.5:1 or better against its own ground.
   command 7.53 / success 5.34 / progress 5.61 / payoff 18.91 on white;
   6.93 / 9.96 / 7.41 / 18.20 on the dark ground. */
[data-handover]{
  --tc-cmd:  #A41E22;
  --tc-ok:   #1F7A46;
  --tc-dim:  #6E6663;
  --tc-done: #14100F;
  /* The ground the transcript is set on. Without it the type was drawn
     straight onto the screenshot and the two read as one smudged image. */
  --tc-plate:      rgba(255,255,255,.94);
  --tc-plate-edge: rgba(20,16,15,.12);
}
:root[data-pill="red"] [data-handover]{
  --tc-cmd:  #F17377;
  --tc-ok:   #4FD08A;
  --tc-dim:  #A99D9B;
  --tc-done: #FBF6F5;
  --tc-plate:      rgba(18,12,13,.92);
  --tc-plate-edge: rgba(255,255,255,.14);
}

/* ── Client review, round 1 ──────────────────────────────────────────
   #31  A word suffix is not a symbol. "3" + "years" at the same display
   size read as one word, "3years". Word suffixes drop out of the display
   register entirely and sit next to the numeral instead of hugging it.
   Symbol suffixes (+, %, ×) are untouched: they are meant to hug. */
.stat__n .suf--w{
  font-family: var(--f-body); font-size: .3em; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase;
  margin-left: .3em; vertical-align: .32em;
}
.feature__stats .stat__n .suf--w{ font-size: .34em; margin-left: .28em; }
.slab__stats   .stat__n .suf--w{ opacity: .72; }

/* #12  "AI" is two letters in a 0.7rem tracked mono heading, so it read as
   a stray mark rather than a section. Every sheet group heading comes up
   with it, otherwise AI alone would look like a different kind of thing. */
.sheet h2,
:root[data-pill="red"] .sheet h2{ font-size: .84rem; letter-spacing: .13em; }

/* #15  The coreCerebrum access CTA carries more weight than a page's other
   buttons, because it is the only one that leaves for the product itself. */
.btn--loud{ font-weight: 900; font-size: .875rem; padding: 17px 34px; letter-spacing: .085em; }

/* #9  In dark mode the blue pill sits on the red pennant, and .lpill has a
   transparent body with a #1C7C8C outline. Measured 2.19:1 against the
   pennant at the top of the page against 8.4:1 once the near-black band
   slides under it, which is why it only looked broken before you scrolled.
   The body gets its own dark ground so it never sits directly on the red,
   and the outline goes to the lit teal it already carries as --liq-b. */
:root[data-pill="red"] .navtog__p:not(.navtog__p--red){ --lp-line: #5FD9E4; }
:root[data-pill="red"] .navtog__p:not(.navtog__p--red) .lpill{
  background: rgba(6,18,22,.78);
}
:root[data-pill="red"] .navtog__p:not(.navtog__p--red)[aria-pressed="false"] .lpill{
  box-shadow: 0 0 17px rgba(var(--lp-glow), .6), 0 1px 4px rgba(0,0,0,.55);
}

/* #18 / #28  The case stat row is `grid-auto-flow: column`, so three tiles
   stay on one line at every width. On a 390px screen that is 85px per tile
   holding words that need up to 157px ("Multilingual", "Event management"),
   which is where the cramped breaks came from. Below 700px they wrap and
   the numeral drops to a size the words actually fit. */
@media (max-width: 700px){
  .cases .slab__stats{
    grid-auto-flow: row;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px 16px;
  }
  .cases .slab__stats .stat__n{ font-size: 1.25rem; }
  .cases .slab__stats .stat__l{ font-size: .8rem; line-height: 1.35; }
}

/* The one light-mode ground the plain brand still cannot carry: this label
   sits on #C0B1AC, where #A41E22 measures 3.63 against a 4.5 requirement.
   Same hue, taken down rather than a new colour introduced. */
:root:not([data-pill="red"]) .vs__col--yes .label{ color: var(--brand-deep); }


/* ── Large display accents on a dark ground ──────────────────────────
   The suffixes on the night statistics are 3rem type, so AA asks 3.0 not
   4.5 and they can sit closer to the mark than running text can. These
   were the salmon the review picked out. */
.section--night .stat__n .suf,
.case--night .stat__n .suf{ color: var(--brand-lit-lg); }


/* ── Section split ───────────────────────────────────────────────────
   A hairline carrying the masthead's pennant, so the seam between Who we
   are and byCORE is a deliberate mark rather than the sections simply
   running out of padding into each other. */
.splitmark{
  position: relative; height: 0;
  border-top: 1px solid var(--line);
  margin-block: clamp(48px, 7vh, 96px) 0;
}
.splitmark span{
  position: absolute; left: 50%; top: -1px;
  width: 84px; height: 30px;
  transform: translateX(-50%);
  background: var(--brand);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
}


/* ── Brand as ink on the night sections ──────────────────────────────
   These sections are near-black in both modes, so a [data-pill] scoped
   rule never reaches them. Every one of these was rendering #A41E22 on
   #14100F, which measures 2.51:1 and fails even the large-text bar. */
.section--night .card__n,
.section--night .label--brand,
.section--night .shead__n,
.section--night .card__go,
.case--night .card__n,
.case--night .label--brand{ color: var(--brand-lit); }
.section--night .card__go:hover{ border-color: var(--brand-lit); background: rgba(224,80,85,.12); }


/* The picker panel is white on the light ground, so it takes the mark, not
   the lifted red. It was in the list of surfaces that are dark in both
   modes, which it is not: #E05055 on #FFFFFF measures 3.85 and fails body
   text, where the mark itself is 7.16. */
.picker__panel .label{ color: var(--brand); }
:root[data-pill="red"] .picker__panel .label{ color: var(--brand-lit); }


/* ── Mobile sheet on the v6 ground ───────────────────────────────────
   Everything inside was drawn for a white page. On the maroon it all has
   to invert, and these run last so they win on order where specificity
   ties with the light-ground rules above. */
.sheet__close{
  color: #fff;
  border: 1px solid rgba(255,255,255,.3); border-radius: var(--r-pill);
  padding: 10px 18px; background: rgba(0,0,0,.18);
}
.sheet__close:hover{ background: rgba(0,0,0,.32); border-color: rgba(255,255,255,.5); }

.sheet h2,
:root[data-pill="red"] .sheet h2{ color: rgba(255,255,255,.62); }

.sheet a.sheet__top{ color: #fff; border-bottom-color: rgba(255,255,255,.16); }
.sheet a.sheet__top::before{ color: rgba(255,255,255,.45); }
.sheet a.sheet__top:hover{ color: #fff; }

.sheet__group{ border-bottom-color: rgba(255,255,255,.16); }

.sheet a.sheet__sub{
  color: rgba(255,255,255,.88);
  border: 1px solid rgba(255,255,255,.26);
  background: rgba(255,255,255,.04);
}
.sheet a.sheet__sub:last-child{ border: 1px solid rgba(255,255,255,.26); }
.sheet a.sheet__sub:hover,
.sheet a.sheet__sub:active,
.sheet a.sheet__sub:focus-visible{
  color: #fff; border-color: #fff; background: rgba(255,255,255,.12);
}

/* The closing action was brand maroon, which is invisible on a maroon
   ground. Inverted: white pill, brand text, and the arrow disc takes the
   brand fill it used to sit on. */
.sheet__go{ background: #fff; color: var(--brand); }
.sheet__go i{ background: var(--brand); color: #fff; }

.sheet__tag{ color: rgba(255,255,255,.62); }


/* ── Enterprise proof, rebuilt ────────────────────────────────────────
   Was a flat slab: a tracked grey lead-in, a hairline, four figures at the
   same size, a hairline, a paragraph, a button. The single most persuasive
   sentence on the page was set at 0.74rem uppercase, the money read no
   louder than "Six months", and the right half of the block was empty.

   It is a lifted surface now, with one hero figure and three supporting
   facts beside it. The copy is unchanged. */
.proof2{
  margin-top: clamp(1.75rem, 3.5vw, 2.75rem);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--lift);
  overflow: hidden;
}
.proof2__head{ padding: clamp(22px,2.6vw,32px) clamp(22px,3vw,40px); }
.proof2__claim{
  margin: 0; max-width: 30ch;
  font-family: var(--f-display); font-weight: 800;
  font-size: clamp(1.25rem, 2.1vw, 1.75rem);
  line-height: 1.18; letter-spacing: -.02em; color: var(--ink-1);
}

.proof2__body{
  display: grid; gap: clamp(24px,3vw,40px);
  padding: 0 clamp(22px,3vw,40px) clamp(24px,3vw,34px);
  border-top: 1px solid var(--line);
  padding-top: clamp(24px,3vw,34px);
}
@media (min-width: 900px){
  .proof2__body{ grid-template-columns: minmax(0,1.05fr) minmax(0,1fr); align-items: start; }
  /* The hero is one figure and a caption against three stacked facts, so it
     ran 225px short and left a hole under the money. Centred against the
     column beside it instead. */
  .proof2__hero{ align-self: center; }
}

/* The hero: the money, as a before and an after rather than one string.
   "$200K to $10K" set as a single figure made the reader parse a sentence
   where the whole point is the size of the gap. */
.swing{ display: flex; align-items: flex-end; gap: clamp(14px,2vw,26px); margin: 14px 0 0; flex-wrap: wrap; }
.swing__side{ display: grid; gap: 4px; }
.swing__side i{
  font-style: normal; font-family: var(--f-body); font-weight: 700;
  font-size: .7rem; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3);
}
.swing__side b{
  font-family: var(--f-display); font-weight: 900;
  font-variation-settings: "wdth" 96, "wght" 900;
  font-size: clamp(2.4rem, 5.4vw, 4rem); line-height: .9;
  letter-spacing: -.04em; color: var(--ink-3);
}
.swing__side b em{ font-style: normal; font-size: .62em; }
.swing__side--to b{ color: var(--brand); }
.swing__arrow{ display: grid; place-items: center; padding-bottom: .5rem; color: var(--brand); }
.swing__arrow svg{ width: clamp(22px,2.6vw,32px); height: clamp(22px,2.6vw,32px); }

.proof2__hero .b-cap{ display: block; margin-top: 16px; max-width: 40ch; }

/* 10.5px and 11.2px are fine beside a 4rem figure on a desktop column and
   too small to read on a phone, where they are the only thing telling you
   what the number is. */
@media (max-width: 700px){
  .proof2 .b-tag{ font-size: .72rem; }
  .swing__side i{ font-size: .74rem; }
}

/* The three supporting facts, subordinate by size and separated by rules
   rather than by whitespace, so they read as a list of evidence. */
.proof2__facts{ list-style: none; margin: 0; padding: 0; display: grid; }
.proof2__facts li{ padding: 16px 0; border-top: 1px solid var(--line-soft); display: grid; gap: 5px; }
.proof2__facts li:first-child{ border-top: 0; padding-top: 0; }
.proof2__facts li:last-child{ padding-bottom: 0; }
.proof2__facts b{
  font-family: var(--f-display); font-weight: 800;
  font-size: clamp(1.15rem, 1.7vw, 1.45rem); line-height: 1.1;
  letter-spacing: -.02em; color: var(--ink-1);
}

.proof2__foot{
  display: grid; gap: 18px; align-items: center;
  padding: clamp(20px,2.4vw,28px) clamp(22px,3vw,40px);
  border-top: 1px solid var(--line);
  background: var(--paper-3);
}
@media (min-width: 900px){
  .proof2__foot{ grid-template-columns: minmax(0,1fr) auto; gap: clamp(24px,3vw,40px); }
}
.proof2__foot .ent__value{ margin: 0; padding: 0; border: 0; max-width: 56ch; }
.proof2__foot .btn{ justify-self: start; }

/* Dark mode: the same glass every other surface takes. */
:root[data-pill="red"] .proof2{ background: rgba(255,255,255,.038); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); border-color: var(--line); }
:root[data-pill="red"] .proof2__foot{ background: rgba(255,255,255,.03); }
:root[data-pill="red"] .swing__side--to b{ color: var(--brand-lit); }
:root[data-pill="red"] .swing__arrow{ color: var(--brand-lit); }


/* ── Team roster ─────────────────────────────────────────────────────
   The old site showed the whole team in four groups. That is what people
   liked about it, so it comes across, but only leadership can take the
   portrait cards: every other headshot exists solely as a 150px Elementor
   thumbnail, and the card face is 275 x 343. Enlarging a 150px file almost
   five times looks broken.

   So the rest of the team gets a compact row instead: a 64px avatar, which
   150px covers cleanly even at 2x, plus name and title. Originals have been
   requested; when they land these rows can become cards. */
.teamgrp{
  display: flex; align-items: center; gap: 14px;
  /* The heading sat flush on its first row: the roster's margin class was
     dropped when the block was generated, so the rule under the label and
     the top of the pills were touching. The gap belongs to the heading. */
  /* The first group sat flush under the section heading, the same zero gap
     the rows had. Every group gets air above it; --next just gets more,
     because it also closes the group before it. */
  margin: clamp(26px, 3vw, 38px) 0 18px;
  font-family: var(--f-body); font-weight: 700;
  font-size: .8125rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-2);
}
.teamgrp::after{
  content: ""; flex: 1 1 auto; height: 1px; background: var(--line);
}
.teamgrp--next{ margin-top: clamp(40px, 5vw, 64px); }

.roster{
  list-style: none; margin: 0; padding: 0;
  display: grid;
  /* Was 10px down and 18px across, so the grid read as columns of pills
     rather than a grid of people. One value both ways. */
  gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
}
.rost{
  display: flex; align-items: center; gap: 13px; min-width: 0;
  padding: 9px 12px 9px 9px;
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--paper);
}
.rost__f{
  flex: none; width: 46px; height: 46px; border-radius: 50%;
  object-fit: cover; background: var(--paper-3);
}
.rost__f--txt{
  display: grid; place-items: center;
  background: var(--brand-wash); color: var(--brand);
  font-family: var(--f-body); font-weight: 700; font-size: .82rem;
  letter-spacing: .04em;
}
.rost__b{ display: grid; min-width: 0; }
.rost__b b{
  font-family: var(--f-body); font-weight: 700; font-size: .92rem;
  color: var(--ink-1); line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rost__b span{
  font-size: .78rem; color: var(--ink-3); line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis;
}
:root[data-pill="red"] .rost{ background: rgba(255,255,255,.038); border-color: var(--line); }

/* ── Service hero, night ────────────────────────────────────────────
   Replaces the stacked H1 / lead / chips / buttons hero on the service
   pages. The chips read as buttons sitting directly above the actual
   buttons, so they are gone: their content is now a labelled metadata
   row under a rule, which cannot be mistaken for something clickable.

   Colour is measured against the band, not assumed. The wash is a
   radial at 28%, which puts the far right of the band at #481618:

     h1        white          14.96:1  on the washed right
     lead      white 74%       8.66:1
     meta key  white 70%       7.91:1
     meta val  white          14.96:1
     link      white 86%      11.29:1
     eyebrow   --brand-lit     4.73:1  on the left, where it sits

   The metadata keys are white rather than red on purpose. The brand
   red lifts to --brand-lit #E05055 for dark grounds, but on the washed
   band that only reaches 4.1:1 at any wash strength we would accept,
   so small red text has to sit on a panel with its own ground. There
   is no panel here, so the red is carried by the eyebrow and the rule.
   Plain --brand on this band measures 2.42:1 and must never be used. */
.phero--night{
  background: linear-gradient(168deg, #181110 0%, #241314 46%, #100909 100%);
  position: relative; overflow: hidden; isolation: isolate;
  padding-top: calc(var(--pennant-h) + clamp(24px, 2.4vh, 38px));
  padding-bottom: clamp(40px, 4.2vh, 62px);
}
.phero--night::after{
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: -1;
  background: radial-gradient(110% 80% at 94% 0%, rgba(164,30,34,.28), transparent 58%);
}
.phero--night .crumb{ color: rgba(255,255,255,.52); }
.phero--night .crumb a{ color: rgba(255,255,255,.52); }
.phero--night .crumb a:hover{ color: #fff; }
.phero--night .crumb .here{ color: var(--brand-lit); }

.phero__eye{
  margin-top: 18px; display: flex; align-items: center; gap: 12px;
  font-family: var(--f-body); font-size: .75rem; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: var(--brand-lit);
}
.phero__eye::before{ content: ""; width: 30px; height: 2px; background: var(--brand-lit); }

.phero--night h1{
  margin: 20px 0 0; color: #fff; max-width: 19ch;
  font-size: clamp(2.6rem, 5.6vw, 4.9rem); line-height: .93; letter-spacing: -.028em;
}
/* A sentence-length H1 at the display size runs four lines and pushes the
   band past the viewport: the services hub measured 985px against a 900px
   window. Titles over ~34 characters step down and widen their measure. */
.phero--night h1.is-long{ font-size: clamp(2.3rem, 3.9vw, 3.4rem); max-width: 26ch; line-height: .98; }

.phero--night .lead{ color: rgba(255,255,255,.74); max-width: 56ch; margin-top: 20px; }
.phero--night .phero__cta{ margin-top: 28px; align-items: center; gap: 26px; }

/* The dark ground needs its own button. .btn--loud is a size modifier
   with no colour of its own, so on this band it rendered invisible. */
.btn--onnight{ background: #fff; color: #14100F;
  box-shadow: 0 3px 0 0 rgba(0,0,0,.42), 0 14px 30px -12px rgba(0,0,0,.6); }
.btn--onnight:hover{ background: var(--ground); transform: translateY(-2px);
  box-shadow: 0 5px 0 0 rgba(0,0,0,.5), 0 20px 40px -14px rgba(0,0,0,.7); }
.btn--onnight:active{ transform: translateY(1px); box-shadow: 0 1px 0 0 rgba(0,0,0,.42); }

.phero__link{
  font-family: var(--f-body); font-size: .95rem; font-weight: 600;
  color: rgba(255,255,255,.86); text-decoration: none;
  border-bottom: 1px solid rgba(255,255,255,.34); padding-bottom: 3px;
}
.phero__link:hover{ color: #fff; border-color: #fff; }

.phero__rule{
  height: 2px; margin-top: clamp(28px, 3.2vh, 42px);
  background: linear-gradient(90deg, var(--brand-lit) 0%, rgba(224,80,85,.28) 34%, rgba(224,80,85,0) 72%);
}
.phero__meta{ display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: 22px 40px; margin-top: 22px; max-width: 1000px;
  /* .phero__in is itself a grid, so this child defaults to min-width:auto
     and resolves to max-content. Without this the row computed 638px inside
     a 500px viewport and the band's overflow:hidden clipped the last cell
     off-screen instead of wrapping it. */
  min-width: 0; }
.phero__meta > *{ min-width: 0; }
.phero__k{
  font-family: var(--f-body); font-size: .68rem; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: rgba(255,255,255,.70);
}
.phero__v{ margin-top: 8px; font-size: .95rem; line-height: 1.4; color: #fff; }

@media (max-width: 720px){
  .phero--night h1{ font-size: clamp(2.3rem, 10vw, 3.2rem); max-width: none; }
  .phero__meta{ grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 20px 26px; }
  .phero--night .phero__cta{ gap: 18px; }

  /* The band ran past the viewport on a phone: 128% on the application
     development hub, 116% on Laravel, so the metadata row sat below the
     fold on the one screen that is meant to introduce the page.

     Measured, 268px of a 978px band was gap. .phero__in is a grid with a
     22px gap and every child also carries its own top margin, so each
     seam cost 40 to 50px. Right at desktop width, too generous at 390.
     The seams close here and nothing else changes. */
  .phero--night .phero__in{ gap: 10px; }
  .phero--night .phero__eye{ margin-top: 10px; }
  .phero--night h1{ margin-top: 12px; }
  .phero--night .lead{ margin-top: 12px; }
  .phero--night .phero__cta{ margin-top: 18px; }
  .phero--night .phero__rule{ margin-top: 20px; }
  .phero--night .phero__meta{ margin-top: 14px; }
  .phero--night .crumb{ font-size: .72rem; gap: 6px; line-height: 1.45; }
  /* A long title still ran four lines at 390px and pushed the metadata
     row past the fold. The desktop long-title step is too gentle here. */
  .phero--night h1.is-long{ font-size: clamp(1.9rem, 8.2vw, 2.6rem); line-height: 1.02; }
}

/* ── What we build: show the software ────────────────────────────────
   The section was a six-card text grid sitting directly under another
   six-card text grid, so a service page read as one long run of
   identical boxes. Each card now carries a drawn fragment of the thing
   it actually is: a job table, a portal, a quote line, an API response,
   a billing chart, a diff.

   All of it is CSS on the existing tokens. No images, so it adds no
   weight, never looks like stock art, and inverts with red mode on its
   own. The fragments are deliberately abstract: they read as software
   without pretending to be a screenshot of a specific client system. */
.swb{ display: grid; gap: clamp(18px, 2.2vw, 28px); }
@media (min-width: 760px){ .swb{ grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (min-width: 1080px){ .swb{ grid-template-columns: repeat(3, minmax(0,1fr)); } }
.swb__i{
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-md); box-shadow: var(--lift);
  transition: box-shadow .3s var(--ease-out), transform .3s var(--ease-snap);
}
@media (hover: hover){ .swb__i:hover{ box-shadow: var(--lift-2); transform: translateY(-3px); } }
.swb__ui{
  height: 132px; flex: none; padding: 13px; overflow: hidden;
  background: var(--paper-3); border-bottom: 1px solid var(--line-soft);
}
.swb__b{ padding: 16px 18px 20px; }
.swb__t{ font-family: var(--f-display); font-weight: 800; font-size: 1rem;
  letter-spacing: -.01em; color: var(--ink-1); }
.swb__d{ margin-top: 7px; font-size: .9rem; line-height: 1.55; color: var(--ink-2); }

/* ── Fragment primitives ─────────────────────────────────────────── */
.fr{ height: 100%; padding: 9px; background: var(--paper);
  border: 1px solid var(--line-soft); border-radius: 7px; }
.fr__row{ display: flex; align-items: center; gap: 7px;
  padding: 5px 0; border-bottom: 1px solid var(--line-soft); }
.fr__row:last-child{ border-bottom: 0; }
.fr__bar{ height: 6px; border-radius: 3px; background: var(--line-soft); }
.fr__bar--on{ background: var(--brand); opacity: .75; }
.fr__dot{ width: 7px; height: 7px; border-radius: 50%; background: var(--brand); flex: none; }
.fr__dot--off{ background: var(--line); }
.fr__av{ width: 22px; height: 22px; border-radius: 50%; flex: none;
  background: var(--brand-wash); border: 1px solid var(--brand-hair); }
.fr__tag{ margin-left: auto; padding: 3px 6px; border-radius: 4px;
  font: 700 .56rem/1 var(--f-body); letter-spacing: .08em; text-transform: uppercase;
  color: var(--brand); background: var(--brand-wash); border: 1px solid var(--brand-hair); }
.fr__tag--mute{ color: var(--ink-3); background: none; border-color: var(--line-soft); }
.fr__code{ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .6rem; line-height: 1.7; color: var(--ink-3); }
.fr__code b{ color: var(--brand); font-weight: 700; }
.fr__code i{ color: #1F7A46; font-style: normal; }
.fr__code s{ color: #B3261E; text-decoration: none; }
.fr__chart{ display: flex; align-items: flex-end; gap: 5px; height: 52px; }
.fr__chart i{ flex: 1; border-radius: 2px 2px 0 0; background: var(--line-soft); }
.fr__chart i.on{ background: var(--brand); }

/* Red mode: the greens and reds inside a fragment are lit so they hold
   on the dark card ground rather than going muddy. */
:root[data-pill="red"] .fr__code i{ color: #4ADE80; }
:root[data-pill="red"] .fr__code s{ color: #F1707A; }

@media (prefers-reduced-motion: reduce){
  .swb__i{ transition: none; }
  @media (hover: hover){ .swb__i:hover{ transform: none; } }
}

/* ── Proof: the work, not a defence ──────────────────────────────────
   This section used to read "Work you can check" over three sitewide
   numbers, byte-identical on 22 pages. Two problems. It answered an
   accusation nobody had made, which is the same tic as "straight
   answers" and "in plain terms" elsewhere. And 25 pages sharing one
   block of 54 words earns nothing: no page relevance, no entities, no
   internal links.

   It now names the client work that actually belongs to the service,
   links into the project pages, and keeps the numbers as a supporting
   line rather than as the whole argument. */
.pw{ display: grid; gap: clamp(14px, 1.8vw, 20px); }
@media (min-width: 720px){ .pw{ grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (min-width: 1040px){ .pw--3{ grid-template-columns: repeat(3, minmax(0,1fr)); } }
.pw__i{
  display: flex; flex-direction: column; gap: 8px; text-decoration: none;
  padding: clamp(18px,2vw,24px); background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--r-md);
  transition: border-color .25s var(--ease-out), box-shadow .25s var(--ease-out),
              transform .25s var(--ease-snap);
}
@media (hover: hover){
  a.pw__i:hover{ border-color: var(--brand); box-shadow: var(--lift-2); transform: translateY(-2px); }
  a.pw__i:hover .pw__go{ gap: 12px; }
}
.pw__c{ font-family: var(--f-display); font-weight: 800; font-size: 1.12rem;
  letter-spacing: -.02em; color: var(--ink-1); }
.pw__w{ font-size: .92rem; line-height: 1.55; color: var(--ink-2); }
.pw__go{ margin-top: auto; padding-top: 10px; display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--f-body); font-size: .8rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--brand); transition: gap .2s var(--ease-snap); }
.pw__go svg{ width: 14px; height: 14px; }

/* The numbers, demoted to a supporting line under the work */
.pwn{ display: flex; flex-wrap: wrap; gap: 10px 34px; align-items: baseline;
  margin-top: clamp(20px,2.4vw,28px); padding-top: 18px; border-top: 1px solid var(--line-soft); }
.pwn__i{ display: flex; align-items: baseline; gap: 9px; }
.pwn__n{ font-family: var(--f-display); font-weight: 800; font-size: 1.35rem;
  letter-spacing: -.02em; color: var(--ink-1); }
.pwn__n em{ font-style: normal; color: var(--brand); }
.pwn__l{ font-size: .86rem; color: var(--ink-3); }

/* ═══════════════════════════════════════════════════════════════════
   WHAT PEOPLE CALL US ABOUT
   Replaces a section that ran "{Page title}, in plain terms." over three
   floating bullets and a four-step process strip that was byte-identical
   on all 25 service pages. It read as filler and it converted nothing.

   What sits here now is the page's long-tail search intent written as
   prose: the problems people actually type before they find the page.
   Each item leads with a real H3 (these pages had no H3s at all; the
   card grid titles are divs), and the section ends at a call to action
   with a specific offer rather than another generic button.
   ═══════════════════════════════════════════════════════════════════ */
.asks__lede{ margin-top: clamp(16px,1.8vw,22px); max-width: 68ch;
  font-size: clamp(1.02rem, 1.25vw, 1.14rem); line-height: 1.62; color: var(--ink-2); }

.asks{ display: grid; margin-top: clamp(22px,2.6vw,34px); }
@media (min-width: 860px){
  .asks{ grid-template-columns: repeat(2, minmax(0,1fr)); column-gap: clamp(36px,4.4vw,80px); }
}
.asks__i{ padding: clamp(18px,2vw,24px) 0; border-top: 1px solid var(--line-soft); min-width: 0; }
.asks__i h3{ font-family: var(--f-display); font-weight: 800; font-size: 1.06rem;
  letter-spacing: -.015em; line-height: 1.3; color: var(--ink-1); }
.asks__i p{ margin-top: 9px; font-size: .96rem; line-height: 1.6; color: var(--ink-2); max-width: 54ch; }

/* The ask, at the point the reader has just recognised their own problem */
.ctab{ margin-top: clamp(26px,3vw,40px); display: grid; gap: 20px; align-items: center;
  padding: clamp(22px,2.6vw,34px); background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--r-md); box-shadow: var(--lift); }
@media (min-width: 920px){ .ctab{ grid-template-columns: minmax(0,1fr) auto; gap: clamp(28px,3vw,48px); } }
.ctab__t{ font-family: var(--f-display); font-weight: 800;
  font-size: clamp(1.14rem, 1.7vw, 1.42rem); letter-spacing: -.02em; line-height: 1.22; color: var(--ink-1); }
.ctab__s{ margin-top: 9px; font-size: .97rem; line-height: 1.6; color: var(--ink-2); max-width: 60ch; }
.ctab__a{ display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }

/* The longest button label, "Get a support chat assessment", measures 329px
   with .btn's nowrap. Inside .ctab on a 390px screen there are about 306px,
   so below 560px the pair stacks full width and the label is allowed to wrap. */
@media (max-width: 560px){
  .ctab{ padding: 20px 18px; }
  .ctab__a{ flex-direction: column; align-items: stretch; gap: 10px; }
  .ctab__a .btn{ white-space: normal; text-align: center; padding-left: 18px; padding-right: 18px; }
}

/* ═══════════════════════════════════════════════════════════════════
   SERVICE TYPES
   Named services that carry their own search demand, set beside the
   process rather than inside it. Columns divided by a hairline, no
   boxes: the page already runs two boxed grids and a third would read
   as more of the same.
   ═══════════════════════════════════════════════════════════════════ */
.styp{ display: grid; gap: clamp(24px,3vw,40px); margin-top: clamp(24px,3vw,38px); }
@media (min-width: 900px){
  .styp{ grid-template-columns: repeat(3, minmax(0,1fr)); gap: 0; }
  .styp__i + .styp__i{ border-left: 1px solid var(--line-soft); padding-left: clamp(26px,2.8vw,44px); }
  .styp__i{ padding-right: clamp(26px,2.8vw,44px); }
  .styp__i:last-child{ padding-right: 0; }
}
.styp__i{ min-width: 0; }
.styp__n{ font-family: var(--f-body); font-size: .72rem; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: var(--brand); }
.styp__i h3{ margin-top: 10px; font-family: var(--f-display); font-weight: 800;
  font-size: clamp(1.14rem,1.5vw,1.34rem); letter-spacing: -.02em; line-height: 1.18; color: var(--ink-1); }
.styp__i > p{ margin-top: 10px; font-size: .96rem; line-height: 1.6; color: var(--ink-2); }
.styp__l{ margin: 16px 0 0; padding: 0; list-style: none; display: grid; gap: 10px; }
.styp__l li{ position: relative; padding-left: 20px; font-size: .92rem; line-height: 1.55; color: var(--ink-2); }
.styp__l li::before{ content: ""; position: absolute; left: 0; top: .62em;
  width: 10px; height: 1px; background: var(--brand); }

/* ═══════════════════════════════════════════════════════════════════
   PRODUCT HERO
   The service pages get .phero--night, a heavy near-black panel. The
   products are the other half of the company and had no treatment at
   all: the same ground as the body, no seam, no branding, running
   straight into the next section.

   This is deliberately the opposite of the night hero. Light, ruled,
   precise: a drawing surface rather than a stage. Software you can look
   at, next to services you are asked to trust.

   The grid is drawn in CSS rather than shipped as an asset, so it costs
   nothing and recolors with the mode.
   ═══════════════════════════════════════════════════════════════════ */
.phero--product{
  position: relative; overflow: hidden; isolation: isolate;
  background: var(--paper);
  padding-top: calc(var(--pennant-h) + clamp(24px, 2.4vh, 38px));
  padding-bottom: clamp(38px, 4vh, 58px);
  border-bottom: 1px solid var(--line);
}
/* The ruled ground. Two gradients, one grid, fading out before the type
   so it never competes with the H1. */
.phero--product::before{
  content: ""; position: absolute; inset: 0; z-index: -2; pointer-events: none;
  background-image:
    repeating-linear-gradient(to right,  var(--line-soft) 0 1px, transparent 1px 64px),
    repeating-linear-gradient(to bottom, var(--line-soft) 0 1px, transparent 1px 64px);
  opacity: .5;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,.35) 55%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,.35) 55%, transparent 100%);
}
/* A single warm wash off the top right, so the grid does not read as a
   spreadsheet. */
.phero--product::after{
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(120% 85% at 96% -10%, var(--brand-hair), transparent 62%);
}

/* Red mode runs the matrix on the page ground, so the panel and its grid
   come off for the same reason the night hero's did. */
:root[data-pill="red"] .phero--product{ background: none; border-bottom-color: var(--line); }
:root[data-pill="red"] .phero--product::before{ opacity: .22; }

/* ── The byCORE lockup ───────────────────────────────────────────────
   The suite already writes its products as core<em>Suffix</em> with the
   distinctive half in brand red. byCORE follows the same rule: the half
   that is the name carries the color. */
.bcmark{
  display: inline-flex; align-items: baseline; gap: 10px;
  font-family: var(--f-display); font-weight: 800; font-size: .95rem;
  letter-spacing: -.01em; text-decoration: none;
}
.bcmark__w{ color: var(--ink-3); }
.bcmark__w b{ color: var(--brand); font-weight: 800; }
.bcmark__t{
  font-family: var(--f-body); font-size: .72rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
  padding-left: 10px; border-left: 1px solid var(--line);
}
@media (max-width: 560px){ .bcmark{ gap: 8px; } .bcmark__t{ font-size: .66rem; } }

/* The product name, set as a wordmark wherever it is the subject */
.pmark{ font-style: normal; }
.pmark em{ font-style: normal; color: var(--brand); }
:root[data-pill="red"] .pmark em{ color: var(--brand-lit); }

/* .phero__k and .phero__v are #fff, written for the night hero. On the
   product ground that is white on white, so the whole metadata strip was
   invisible. Same failure as .btn--loud on the night hero.
   Measured on #FFFFFF: key --ink-3 5.95:1, value --ink-1 18.9:1.
   .phero__rule uses --brand-lit, which is the red lifted for dark grounds
   and washes out here, so the product rule carries --brand instead. */
.phero--product .phero__k{ color: var(--ink-3); }
.phero--product .phero__v{ color: var(--ink-1); }
.phero--product .phero__rule{
  height: 2px;
  background: linear-gradient(90deg, var(--brand) 0%, rgba(164,30,34,.26) 34%, rgba(164,30,34,0) 72%);
}
.phero--product .phero__link{ color: var(--ink-2); border-bottom-color: var(--line); }
.phero--product .phero__link:hover{ color: var(--brand); border-color: var(--brand); }

/* --brand on the red-mode ground measures 2.59:1, the same failure the
   .section--night block above documents. The lit red is the one that
   works on a dark ground: 5.06:1. */
:root[data-pill="red"] .bcmark__w b{ color: var(--brand-lit); }
:root[data-pill="red"] .bcmark__t{ border-left-color: var(--line); }

/* .btn is nowrap, so "See the actual application" measured 494px and
   pushed a 375px page to 514px wide. Letting the label wrap below 560px
   is enough; flex-wrap already handles the rest. */
@media (max-width: 560px){
  /* Every .btn, not only the hero pair: the class is white-space:nowrap,
     so any long label overflows a 375px screen wherever it sits. A mid
     page ghost button reading "Named comparison, including where they
     beat us" measured 494px and took the page to 514px wide.
     white-space alone is not enough, because a flex item keeps
     min-width:auto and holds its max-content width regardless. */
  .btn{ white-space: normal; text-align: center;
    max-width: 100%; min-width: 0;
    padding-left: 20px; padding-right: 20px; }

  /* .shead is a grid, so its children default to min-width:auto and can
     resolve wider than the track. Measured 386px inside a 335px head on
     the compare page, taking the document to 406px. */
  .shead > *{ min-width: 0; }

  /* The display headings are set large enough that a single long word
     paints past its own box without the box ever measuring wide. On the
     harness page "configuration." in a 335px H2 took the document to
     399px, and nothing in the layout looked wrong when measured, because
     the overflow was ink rather than boxes. */
  h1, h2, h3, .t-upper{ overflow-wrap: break-word; }
}

.phero--product h1{ margin: 18px 0 0; }
.phero--product .lead{ max-width: 58ch; }

/* ═══════════════════════════════════════════════════════════════════
   STICKY PRODUCT SUBNAV
   The coreCerebrum set is seven pages and the rail between them lived
   inside the hero, so moving from Compare to Pricing meant scrolling
   back to the top first.

   It could not stick from where it was: .phero--product sets
   overflow:hidden to clip its ruled ground, and a sticky child cannot
   escape a clipping ancestor. So the rail moved out of the hero into
   its own bar directly beneath it.

   top is --flag-h because the masthead is fixed at that height, and
   z-index sits under the masthead's 60 so the two never fight.
   ═══════════════════════════════════════════════════════════════════ */
.subnav-bar{
  position: sticky; top: var(--flag-h); z-index: 50;
  padding: 11px 0;
  /* Solid, not frosted. At 88% the display headings read straight through
     it as they scrolled past, and nothing else on this site is glass: the
     masthead is a solid pill. */
  background: var(--paper);
  border-bottom: 1px solid var(--line-soft);
  box-shadow: 0 1px 0 0 rgba(20,16,15,.04), 0 8px 20px -18px rgba(20,16,15,.5);
}
.subnav-bar .subnav{ padding-bottom: 0; }

/* Anchors below the bar have to clear the masthead and the bar, not just
   the masthead. Scoped by sibling so only pages carrying a bar shift. */
.subnav-bar ~ * [id],
.subnav-bar ~ [id]{ scroll-margin-top: calc(var(--flag-h) + 84px); }

/* ═══════════════════════════════════════════════════════════════════
   CASE STUDY
   Every project carries its own --cs-accent, taken from the client's own
   identity, and one of four layout variants. The accent is used for the
   eyebrow, the rule, the stat figures and the screenshot frame, so two
   case studies never read as the same page with the words swapped, which
   is what a templated portfolio always looks like.

   The accent is never used for body copy. Client colours are chosen for
   their brand and not for contrast on our ground, so it is confined to
   large type and to furniture, where a 3:1 bar applies.
   ═══════════════════════════════════════════════════════════════════ */
.cs{ --cs-ink: var(--ink-1); }
/* .phero__link is white for the night hero, so it was invisible on the
   case study's light ground. Third time this class of bug has appeared:
   a component styled for the dark hero reused on a light one. */
.cs .phero__link{ color: var(--ink-2); border-bottom-color: var(--line); }
.cs .phero__link:hover{ color: var(--cs-accent, var(--brand)); border-color: currentColor; }
.cs__eye{ font-family: var(--f-body); font-size: .75rem; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: var(--cs-accent, var(--brand));
  display: flex; align-items: center; gap: 12px; }
.cs__eye::before{ content: ""; width: 30px; height: 2px; background: currentColor; }

.cs__shot{ margin-top: clamp(26px,3vw,44px); border-radius: var(--r-lg); overflow: hidden;
  border: 1px solid var(--line); background: var(--paper-3);
  box-shadow: 0 30px 60px -40px rgba(20,16,15,.55); }
.cs__shot img{ display: block; width: 100%; height: auto; }
/* A 6px bar of the client's colour along the top of the shot, which is
   the cheapest way to make 29 pages feel like 29 pages. */
.cs__shot{ border-top: 6px solid var(--cs-accent, var(--brand)); }

/* The spec plate. Four label/value pairs floating in open space read as an
   afterthought, so they are contained, divided, and topped with the case
   study's own accent. The columns are declared rather than auto-fit because
   the cell dividers have to know which cell starts a row. */
.cs__facts{
  display: grid; gap: 0; margin-top: clamp(26px,3vw,38px);
  grid-template-columns: 1fr; min-width: 0;
  border: 1px solid var(--line);
  border-top: 3px solid var(--cs-accent, var(--brand));
  border-radius: var(--r-md);
  background: var(--paper-2);
  overflow: hidden;
}
.cs__facts > *{ min-width: 0; padding: 16px 20px; border-top: 1px solid var(--line); }
.cs__facts > *:first-child{ border-top: 0; }

@media (min-width: 560px){
  .cs__facts{ grid-template-columns: 1fr 1fr; }
  .cs__facts > *{ border-top: 1px solid var(--line); border-left: 1px solid var(--line); }
  .cs__facts > *:nth-child(2n+1){ border-left: 0; }
  .cs__facts > *:nth-child(-n+2){ border-top: 0; }
}
@media (min-width: 940px){
  .cs__facts{ grid-template-columns: repeat(4, 1fr); }
  .cs__facts > *{ border-top: 0; }
  .cs__facts > *:nth-child(n){ border-left: 1px solid var(--line); }
  .cs__facts > *:first-child{ border-left: 0; }
}

.cs__k{ font-family: var(--f-mono); font-size: .64rem; font-weight: 600; letter-spacing: .13em;
  text-transform: uppercase; color: var(--ink-3); }
.cs__v{ margin-top: 8px; font-size: 1.02rem; line-height: 1.4; color: var(--ink-1);
  font-weight: 600; }

/* The stack, as chips. A comma-separated string reads as prose and hides the
   thing people scan a case study for: which platform this was built on. */
.cs__chips{ display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.cs__chip{
  font-family: var(--f-body); font-size: .78rem; font-weight: 600; line-height: 1;
  padding: 5px 10px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--paper); color: var(--ink-1);
}
.cs__v .phero__link{ color: var(--cs-accent, var(--brand)); }

.cs__body{ display: grid; gap: clamp(30px,3.6vw,52px); }
@media (min-width: 900px){ .cs--wide .cs__body{ grid-template-columns: repeat(3, minmax(0,1fr)); } }
.cs__block h2{ font-size: clamp(1.2rem,1.7vw,1.5rem); letter-spacing: -.02em; line-height: 1.18; }
.cs__block h2::after{ content: ""; display: block; width: 34px; height: 2px;
  background: var(--cs-accent, var(--brand)); margin-top: 12px; }
.cs__block p{ margin-top: 14px; font-size: 1rem; line-height: 1.62; color: var(--ink-2); }

.csn{ display: grid; gap: 18px 40px; grid-template-columns: repeat(auto-fit,minmax(180px,1fr));
  margin-top: clamp(26px,3vw,40px); padding-top: 22px; border-top: 1px solid var(--line-soft); }
.csn__n{ font-family: var(--f-display); font-weight: 800; font-size: clamp(1.6rem,2.6vw,2.3rem);
  letter-spacing: -.03em; line-height: 1; color: var(--cs-accent, var(--brand)); }
.csn__l{ margin-top: 9px; font-size: .9rem; line-height: 1.45; color: var(--ink-2); }

/* The variants. Same components, different rhythm, so the set does not
   read as one template run 29 times. */
.cs--v2 .cs__shot{ border-radius: 0; border-left: 0; border-right: 0; }
.cs--v3 .cs__shot{ border-top-width: 0; border-left: 6px solid var(--cs-accent, var(--brand)); }
.cs--v4 .cs__eye::before{ width: 0; }
.cs--v4 .cs__block h2::after{ margin-left: 0; width: 60px; }

/* ═══════════════════════════════════════════════════════════════════
   PORTFOLIO HERO
   The old opening was a headline and two lines of lead on empty ground,
   which is the wrong first screen for a portfolio: it describes the work
   instead of showing it. Now that the 27 client screenshots are in the
   build, the hero shows them.

   Three columns of real project screenshots drift at different speeds
   and in alternating directions, masked to nothing at both ends so the
   loop has no visible seam. It sits beside the copy rather than behind
   it, because type over moving images is unreadable and the point here
   is to invite, not to decorate.
   ═══════════════════════════════════════════════════════════════════ */
.pfhero{ position: relative; overflow: hidden; isolation: isolate;
  padding-top: calc(var(--pennant-h) + clamp(20px,2vh,32px));
  padding-bottom: clamp(34px,4vh,56px); border-bottom: 1px solid var(--line); }
.pfhero__in{ display: grid; gap: clamp(28px,3.4vw,56px); align-items: center; }
@media (min-width: 1000px){ .pfhero__in{ grid-template-columns: minmax(0,1fr) minmax(0,.92fr); } }
.pfhero__copy{ min-width: 0; }

.pfwall{ display: grid; grid-template-columns: repeat(3,1fr); gap: 14px;
  height: clamp(340px, 46vw, 560px); overflow: hidden; min-width: 0;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 14%, #000 86%, transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 14%, #000 86%, transparent); }
.pfwall__col{ display: grid; gap: 14px; align-content: start;
  animation: pfdrift var(--pf-dur, 64s) linear infinite; will-change: transform; }
.pfwall__col--b{ animation-direction: reverse; --pf-dur: 82s; }
.pfwall__col--c{ --pf-dur: 72s; }
.pfwall img{ display: block; width: 100%; height: auto; border-radius: var(--r-sm);
  border: 1px solid var(--line); background: var(--paper);
  box-shadow: 0 14px 30px -22px rgba(20,16,15,.6); }
/* The column holds the set twice, so translating by exactly half its own
   height returns it to the start with nothing to see. */
@keyframes pfdrift{ from{ transform: translateY(0); } to{ transform: translateY(-50%); } }
@media (prefers-reduced-motion: reduce){ .pfwall__col{ animation: none; } }
@media (max-width: 999px){ .pfwall{ height: 300px; } }

/* A grid rather than a flex line, so the figures stay even instead of
   wrapping 3 + 1. Three of them now: the count of case studies came out
   because a number that says how many pages we have written dates the
   page and invites the reader to judge the size of the list. */
.pfstats{ display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 18px 30px;
  margin-top: clamp(22px,2.6vw,30px); padding-top: 20px; border-top: 1px solid var(--line-soft); }
@media (min-width: 560px){ .pfstats{ grid-template-columns: repeat(3, minmax(0,1fr)); } }
.pfstats__n{ font-family: var(--f-display); font-weight: 800; font-size: clamp(1.5rem,2.3vw,2rem);
  letter-spacing: -.03em; line-height: 1; color: var(--ink-1); }
.pfstats__n em{ font-style: normal; color: var(--brand); }
.pfstats__l{ margin-top: 6px; font-size: .86rem; color: var(--ink-3); }

/* ── The full index ──────────────────────────────────────────────── */
.pfgrid{ display: grid; gap: clamp(16px,2vw,24px); margin-top: clamp(24px,3vw,38px); }
@media (min-width: 640px){ .pfgrid{ grid-template-columns: repeat(2,minmax(0,1fr)); } }
@media (min-width: 1040px){ .pfgrid{ grid-template-columns: repeat(3,minmax(0,1fr)); } }
.pfc{ display: flex; flex-direction: column; text-decoration: none; min-width: 0;
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-md);
  overflow: hidden; transition: border-color .25s var(--ease-out), box-shadow .25s var(--ease-out),
  transform .25s var(--ease-snap); }
@media (hover: hover){
  a.pfc:hover{ border-color: var(--pf-accent, var(--brand)); box-shadow: var(--lift-2); transform: translateY(-3px); }
  a.pfc:hover .pfc__go{ gap: 11px; }
}
.pfc__shot{ position: relative; aspect-ratio: 16/10; overflow: hidden; background: var(--paper-3);
  border-bottom: 3px solid var(--pf-accent, var(--brand)); }
.pfc__shot img{ width: 100%; height: 100%; object-fit: cover; object-position: top center; display: block; }
.pfc__b{ padding: clamp(15px,1.7vw,20px); display: flex; flex-direction: column; gap: 7px; flex: 1; }
.pfc__n{ font-family: var(--f-body); font-size: .68rem; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-3); }
.pfc__t{ font-family: var(--f-display); font-weight: 800; font-size: 1.02rem; line-height: 1.24;
  letter-spacing: -.015em; color: var(--ink-1); }
.pfc__s{ font-size: .86rem; line-height: 1.5; color: var(--ink-2); }
.pfc__go{ margin-top: auto; padding-top: 8px; display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--f-body); font-size: .74rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--pf-accent, var(--brand)); transition: gap .2s var(--ease-snap); }
:root[data-pill="red"] .pfc__t{ color: var(--ink-1); }

/* ═══════════════════════════════════════════════════════════════════
   FEATURED CLIENTS
   Was four cards in a 2x2 grid. Grid cells take the height of the
   tallest one, so the three with less to say carried 200px of empty
   white underneath them, and the whole band read as unfinished. It also
   sat above a grid of 29 cards saying much the same thing.

   These are rows now. A row is as tall as its content, so nothing is
   padded out to match a neighbour, and a row can carry a logo at proper
   size next to a claim and its numbers without competing with the index
   below. The client's own colour runs down the left edge.
   ═══════════════════════════════════════════════════════════════════ */
/* ── Selected work ───────────────────────────────────────────────────
   Four rows, one per client. The previous treatment spent a 190-240px
   column on a logo and then repeated the client's name in a label beneath
   it, so a third of the width carried one piece of information. The link
   floated to the far right of the stat row, which put it nearer the next
   client than its own. Rows ran about 340px each.

   Here the headline leads, because that is the line a reader scans. The
   logo moves to the right of it as an identifier, the label carries the
   sector instead of the name again, and the facts and the link sit
   together at the end of the row they belong to. The whole row is the
   link, so the target is the row rather than a 90px phrase.

   Same vocabulary as the homepage focus cards (sector, headline, two
   facts, one action) at a denser setting, so the two read as one family. */

/* ── Client accents on the red-mode ground ───────────────────────────
   Measured across the 29 project accents against #110B0C: 17 of them
   miss the 3:1 large-text bar and The Spread's navy reaches only
   1.58:1. That is not a bad palette, it is the wrong question: a client
   picks a colour to work in their market, not on our background.

   So in red mode the accent is confined to furniture, where no contrast
   rule applies: the rule beside a featured row, the bar on a screenshot,
   the underline beneath a heading. Everything that is read as text takes
   the mode's own ink instead. The light mode keeps the accent on the
   type, where every one of them was measured and passes. */
:root[data-pill="red"] .csn__n{ color: var(--ink-1); }
:root[data-pill="red"] .cs__eye{ color: var(--brand-lit); }
:root[data-pill="red"] .pfc__go{ color: var(--brand-lit); }

/* ── Address ─────────────────────────────────────────────────────────
   The element was not used anywhere: 79 visible addresses, 76 of them a
   plain <span> in the footer and three a <p>. <address> is the right
   element for the contact details of the page's owner, and it also gives
   the microformat parsers something to hold onto next to the JSON-LD.

   Browsers italicise it by default, which is not what any of these want. */
address{ font-style: normal; }
/* Outside the footer the address sets on two lines, because "245 West
   Michigan Ave, Battle Creek," wrapping before "MI 49017" splits the city
   from its state. The footer keeps one line: it sits in a row of
   dot-separated items where a break would read as a new item. */
.addr{ line-height: 1.5; }
.foot__addr{ display: inline; }

/* A field a person never sees and a bot fills in. Off screen rather than
   display:none, because some bots skip anything that is not rendered. */
.intake__hp{ position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
/* The note after a successful send reads as confirmation, not as an error */
.intake__note[data-state="sent"]{ color: var(--ink-1); font-weight: 600; }

/* ═══════════════════════════════════════════════════════════════════
   THE WORK WALL
   Section 02 of the homepage was four stacked cards showing the same
   four client logos that already appear on the portfolio featured rows,
   in the portfolio index and on the service pages. Four repetitions of
   a logo is not evidence, and meanwhile 27 real client screenshots were
   sitting in the build unused on this page.

   So the section shows the work: two rows of live client sites moving
   in opposite directions on a dark band, every tile a link into its
   case study, with three real outcomes named underneath. It is the one
   place on the homepage that is unarguable, so it is the one place that
   should be loud.
   ═══════════════════════════════════════════════════════════════════ */
.wallx{ position: relative; overflow: hidden; }
/* Full bleed out of .wrap: the wall is the point, and a 1240px column
   makes it look like a widget. */
.wallx__rails{ margin-inline: calc(50% - 50vw); width: 100vw;
  display: grid; gap: clamp(12px,1.4vw,20px);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); }
.wallx__rail{ display: flex; gap: clamp(12px,1.4vw,20px); width: max-content;
  animation: wallxroll var(--wx-dur, 90s) linear infinite; will-change: transform; }
.wallx__rail--b{ animation-direction: reverse; --wx-dur: 112s; }
/* Each rail holds its set twice, so translating by half its own width
   returns it to the start with no seam. */
@keyframes wallxroll{ from{ transform: translateX(0); } to{ transform: translateX(-50%); } }
.wallx:hover .wallx__rail{ animation-play-state: paused; }
@media (prefers-reduced-motion: reduce){
  .wallx__rail{ animation: none; }
  .wallx__rails{ mask-image: none; -webkit-mask-image: none; }
}

.wxt{ position: relative; flex: none; width: clamp(230px, 24vw, 340px);
  border-radius: var(--r-md); overflow: hidden; text-decoration: none;
  background: var(--paper-3); border: 1px solid var(--line);
  transition: transform .3s var(--ease-snap), border-color .3s var(--ease-out); }
.wxt img{ display: block; width: 100%; aspect-ratio: 16/10; object-fit: cover;
  object-position: top center; }
/* The caption sits over the shot rather than under it, so a rail of
   tiles reads as one band of work and not as a row of cards. */
.wxt__c{ position: absolute; inset: auto 0 0 0; padding: 26px 14px 12px;
  background: linear-gradient(to top, rgba(10,7,7,.92) 40%, transparent);
  color: #fff; transform: translateY(101%); transition: transform .3s var(--ease-out); }
.wxt__n{ font-family: var(--f-display); font-weight: 800; font-size: .96rem; letter-spacing: -.015em; }
.wxt__s{ margin-top: 3px; font-size: .8rem; color: rgba(255,255,255,.76); line-height: 1.4; }
@media (hover: hover){
  a.wxt:hover{ transform: translateY(-4px); border-color: var(--wx-accent, var(--brand-lit)); }
  a.wxt:hover .wxt__c{ transform: none; }
}
/* Touch has no hover, so the caption is simply always there. */
@media (hover: none){ .wxt__c{ transform: none; } }
a.wxt:focus-visible{ outline: 2px solid var(--brand-lit); outline-offset: 3px; }
a.wxt:focus-visible .wxt__c{ transform: none; }

/* The outcomes. Real numbers from real case studies, each naming the
   client, because a number with nobody attached to it is a claim. */
/* Three named clients, leading the wall. Replaces three bare stat figures that
   sat below it: a number with a caption asks the reader to take the work on
   faith, and a screenshot alone asks them to take the client on faith. These
   carry the recognisable name first, the site behind it, and two facts from the
   case study, so each card answers who, what and how without being opened.
   Each takes its project's own accent, the same one its case study uses. */
.wxf{
  display: grid; gap: clamp(18px,2vw,26px);
  grid-template-columns: 1fr;
  margin-top: clamp(26px,3vw,40px);
}
@media (min-width: 760px){ .wxf{ grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 760px){ .wxf--4{ grid-template-columns: repeat(2, 1fr); } }

.wxf__i{
  display: flex; flex-direction: column; min-width: 0; position: relative;
  border: 1px solid var(--line); border-radius: var(--r-md);
  overflow: hidden; background: var(--paper);
  text-decoration: none; color: inherit; isolation: isolate;
  transition: transform .3s var(--ease-out), border-color .3s var(--ease-out);
}
/* The accent as a top edge that fills on hover, so the colour is a property of
   the project rather than decoration applied to a card. */
.wxf__i::before{
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px; z-index: 2;
  background: var(--wx-accent, var(--brand));
  transform: scaleX(.24); transform-origin: left;
  transition: transform .4s var(--ease-out);
}
.wxf__i:hover{ transform: translateY(-4px); border-color: color-mix(in srgb, var(--wx-accent, var(--brand)) 55%, transparent); }
.wxf__i:hover::before{ transform: scaleX(1); }
.wxf__i:focus-visible{ outline: 2px solid var(--wx-accent, var(--brand)); outline-offset: 3px; }

.wxf__shot{ display: block; overflow: hidden; border-bottom: 1px solid var(--line); }
.wxf__shot img{
  /* 1.9, because the sources are 1.91 to 1.98 wide and object-fit: cover crops
     the sides. At 16/10 that cut 19% of the width off, which a photographic
     screenshot survives and a typographic card does not: the OCLC card lost its
     first letter and its logo. Matching the frame to the sources costs 4%. */
  display: block; width: 100%; height: auto; aspect-ratio: 1.9;
  object-fit: cover; object-position: top center;
  transition: transform .5s var(--ease-out);
}
.wxf__i:hover .wxf__shot img{ transform: scale(1.03); }

/* A flex column so the button can sit on the floor of every card regardless of
   how much copy is above it. Three cards with different length titles used to
   put three buttons at three different heights. */
.wxf__b{ display: flex; flex-direction: column; flex: 1; padding: 24px 24px 22px; }

/* The brand, not our typesetting of it. A logo is what people recognise, and
   these three are recognised. The name stays in the img alt, so the text is
   still there for search and for a screen reader. Sized by height so three
   different aspect ratios sit on one baseline. */
/* Sized by height so three different aspect ratios sit on one baseline, and
   capped by width so the widest wordmark cannot crowd the card. */
.wxf__logo{ display: flex; align-items: center; height: clamp(48px, 4.4vw, 62px); }
.wxf__logo img{
  display: block; width: auto; height: 100%; max-width: 250px;
  object-fit: contain; object-position: left center;
}
.wxf__s{
  display: block; margin-top: 14px; font-family: var(--f-body); font-size: .66rem;
  font-weight: 700; letter-spacing: .13em; text-transform: uppercase;
  color: var(--wx-accent, var(--brand));
}
.wxf__t{ display: block; margin-top: 12px; font-size: .95rem; line-height: 1.5; color: var(--ink-2); }

.wxf__facts{
  display: flex; gap: 26px; margin-top: 18px; padding-top: 15px;
  border-top: 1px solid var(--line);
}
.wxf__f{ display: block; min-width: 0; }
.wxf__f b{
  display: block; font-family: var(--f-display); font-weight: 800;
  font-size: 1.02rem; letter-spacing: -.01em; font-style: normal;
}
.wxf__f i{
  display: block; margin-top: 3px; font-style: normal;
  font-size: .76rem; line-height: 1.35; color: var(--ink-3);
}

/* margin-top:auto pins it to the floor of the card, so three cards with three
   different title lengths still line their buttons up.
   Filled rather than outlined: as accent-coloured text on the #191919 card the
   three read 2.99, 3.61 and 2.69 against WCAG's 4.5. White on the same accents
   measures 5.88, 4.87 and 6.55, so the fill is what makes them legible as well
   as louder. */
.wxf__go{
  margin-top: auto; align-self: flex-start;
  display: inline-flex; align-items: center; gap: 10px;
  padding: 13px 22px; border-radius: 999px;
  border: 1px solid transparent;
  background: var(--wx-accent, var(--brand)); color: #fff;
  font-family: var(--f-body); font-size: .78rem; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase; white-space: nowrap;
  transition: filter .25s var(--ease-out), transform .25s var(--ease-out);
}
.wxf__go svg{ width: 16px; height: 16px; flex: none; }
.wxf__i:hover .wxf__go{ filter: brightness(1.18); }
.wxf__i:active .wxf__go{ transform: translateY(1px); }
.wxf__facts{ margin-bottom: 22px; }

@media (prefers-reduced-motion: reduce){
  .wxf__i, .wxf__i::before, .wxf__shot img{ transition: none; }
  .wxf__i:hover{ transform: none; }
  .wxf__i:hover .wxf__shot img{ transform: none; }
}

