/* ══════════════════════════════════════════════════════════════════════════
   /tech · D.02 — WEBSITES AND DESIGN.  T-1180, 2026-08-14.

   WHY THIS SECTION EXISTS
   -----------------------
   Ethan, verbatim: "tech services page doesnt mention consumer website and
   create design" / "MISSING MASSIVE DETAILS". He is right. /tech sold
   row-level security, Stripe state machines, migrations and release
   process — all true, all senior-engineer language — and never once said
   the firm designs and builds ORDINARY WEBSITES for normal businesses,
   which is what most people arriving on this page are actually shopping
   for. /pricing has priced that work per page and per integration the
   whole time and this page never mentioned it.

   THE ANIMATED MOMENT, AND WHY IT IS THIS ONE
   -------------------------------------------
   Ethan again: "look at the animations we have for the current ones, can't
   just add text, need to add super high quality animations."

   So the section does not describe design, it RUNS it. One drawn browser
   window goes SKETCH -> DESIGN -> LIVE without ever changing object:

     SKETCH  eleven blocks draw themselves in, dashed and unfilled, over a
             red baseline grid. This is the layout being decided.
     DESIGN  the same eleven blocks take on fill, colour, weight and
             radius, washing left to right across the layout. NOTHING
             MOVES — that is the point. The structure was already right;
             what arrives is the design.
     LIVE    a REAL client capture cross-fades onto the same rectangle and
             the address bar resolves to that client's real domain.

   The wireframe geometry is not invented. Every block is positioned in
   percentages traced off the actual captures it dissolves into: the five
   sites share one skeleton — wordmark left, links centre, CTA right, then
   a left type column (eyebrow, two headline lines, rule, lede, two
   buttons) against a right image panel. Compare sluekie/site-home.jpg and
   sam-the-man/site-home.jpg and it is the same page twice. So the
   wireframe is a true reduction of the work, and it resolves into its own
   source rather than into an unrelated screenshot.

   THE SEQUENCE IS 100% CSS. One class, `.is-on`, is added once by an
   IntersectionObserver and never removed; every phase, stagger and
   cross-fade after that is animation-delay. Nothing is on a timer and
   nothing is on the main thread, so the run cannot drop frames while the
   rest of the page is still loading — which matters, because this section
   sits below five demo panels and a video hero.

   Curve is cubic-bezier(.23,1,.32,1) throughout (--wbd-e). No CSS default
   easing anywhere, no ease-in on anything, nothing scales from 0.

   ══ THE FINISHED STATE IS THE DEFAULT. READ THIS BEFORE EDITING. ══
   Every element here is authored in its FINAL appearance and the
   animations run backwards out of a `from` keyframe under `.is-on`, held
   by `animation-fill-mode: both` through the delay. It is deliberately not
   the other way round.

   The obvious build — author the start state, animate to the end — has a
   failure mode this section cannot afford: if the script 404s, is blocked,
   or throws before it reaches the observer, `.is-on` never lands and the
   reader gets an empty white rectangle where the client work should be.
   Authored this way, a script that never runs costs the animation and
   nothing else. That is also why there is no separate no-JS block and why
   `prefers-reduced-motion` is a two-line rule instead of a second
   stylesheet: switching the animations off lands on the finished state by
   construction rather than by a parallel set of declarations that has to
   be kept in sync.

   THE SPECIFICITY TRAPS ON THIS ESTATE — ALL FOUR ARE AVOIDED BY DESIGN,
   NOT BY FIGHTING THEM
   ---------------------------------------------------------------------
   1. `--ink` is INVERTED to bone inside light scopes. Nothing in this file
      reads --ink. Every colour here is a LITERAL HEX, which is also what
      the newest files on this site do deliberately.
   2. site.css's white-ground rule is
      `main > section:not()x7 :where(h1,h2,h3,h4,p,li,dt,dd,figcaption,
      blockquote,span:not([class*="num"]))` — no single class beats it. So
      this section does not try: it WANTS ink type on bone, and it lets
      that rule supply it. Every element that needs a NON-ink colour is a
      `<b>` or an `<em>`, neither of which is in that list, so the red
      figures win with an ordinary class and no !important anywhere in
      this file.
   3. `:where()` contributes zero specificity — so it is never used here
      to carry a value that has to win.
   4. site.css caps `img[src*="/gallery/systems/"]` and
      `img[src*="/apps/screens/"]` at 440px with object-fit: cover. The
      captures here are served from Supabase storage under
      /media/portfolio/<slug>/, which matches neither attribute selector.
      The frame is sized by its own aspect-ratio box instead, so there is
      no cap to restate.

   THE DARK SLAB uses `.t-dark`, which site.css already teaches to restore
   --on-black on itself AND on its descendants with !important. That is why
   the $3,000 total is bone-on-ink for free rather than by a fight. Note
   that <b> and <em> are NOT in that descendant list either, which is how
   an accent inside the slab stays an accent.

   COLOUR, MEASURED
   ----------------
   Ground is --bone #faf8f3. Ink #0a0a0a on it is 18.6:1. The red used for
   small type on this light ground is #a4132c (6.6:1) — NEVER --red-text
   #ef5c6e, which is calibrated for ink grounds and fails badly on bone.
   Large red display figures use #c8102e (5.5:1 on bone).

   IMAGE EVIDENCE — sourced 2026-08-14 from
     portfolio_items WHERE practice = 'technology'
   on Supabase jlnvklonulnlwpcezybj, columns short_description, tech_stack,
   website_url, thumbnail_image. Five rows are consumer/business websites
   rather than infrastructure, and those five are the tabs. Captures are
   the rows' own thumbnail_image values, all 1600x1000, which is why the
   frame is aspect-ratio 8/5 and nothing is cropped.
   ══════════════════════════════════════════════════════════════════════════ */

.wbd {
  /* One curve for the whole section. */
  --wbd-e: cubic-bezier(.23, 1, .32, 1);
  --wbd-ink: #0a0a0a;
  --wbd-red: #c8102e;
  --wbd-red-sm: #a4132c;          /* 6.6:1 on bone — the small-type red   */
  --wbd-rule: rgba(10, 10, 10, .16);
  --wbd-rule-soft: rgba(10, 10, 10, .09);
  --wbd-mute: rgba(10, 10, 10, .62);
  --wbd-body: rgba(10, 10, 10, .76);
  --wbd-ivory: #ece5d7;
  position: relative;
  overflow: hidden;
}

.wbd__inner {
  max-width: 1180px;
  margin-inline: auto;
  padding-inline: clamp(1.15rem, 5vw, 3rem);
}

/* ── HEAD ─────────────────────────────────────────────────────────────── */

.wbd__eyebrow {
  display: block;
  font-family: var(--font-mono);
  font-size: clamp(.69rem, 1.1vw, .7rem);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--wbd-red-sm);
  margin: 0 0 .9rem;
}

.wbd__h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.72rem, 4vw, 2.75rem);
  line-height: 1.08;
  letter-spacing: -.01em;
  margin: 0 0 1rem;
  max-width: 20ch;
}
.wbd__h2 em { font-style: italic; color: var(--wbd-red); }

.wbd__lede {
  font-family: var(--font-body);
  font-size: clamp(.95rem, 1.5vw, 1.06rem);
  line-height: 1.62;
  color: var(--wbd-body);
  max-width: 64ch;
  margin: 0 0 clamp(1.8rem, 3.4vw, 2.8rem);
}
/* <b> is NOT in site.css's white-ground :where() list, so an ordinary class
   colours it. See trap 2 in the header. */
.wbd__lede b { font-weight: 500; color: var(--wbd-ink); }

/* ── THE TWO-COLUMN BODY ──────────────────────────────────────────────── */

.wbd__grid {
  display: grid;
  gap: clamp(1.7rem, 3.6vw, 2.9rem);
  align-items: start;
}
@media (min-width: 940px) {
  .wbd__grid { grid-template-columns: minmax(0, 1.32fr) minmax(0, .68fr); }
}

/* ══ THE BROWSER ═══════════════════════════════════════════════════════
   Drawn, not photographed. A photograph of a screen would be a fourth
   laptop picture on a page Ethan has already stripped three off, and a
   drawn frame is correct at every width instead of only above 1180px.  */

.wbd__browser {
  border: 1px solid var(--wbd-rule);
  background: #fff;
  box-shadow: 0 18px 40px -26px rgba(10, 10, 10, .40),
              0 3px 10px -6px rgba(10, 10, 10, .16);
}

.wbd__chrome {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .5rem .7rem;
  background: var(--wbd-ivory);
  border-bottom: 1px solid var(--wbd-rule-soft);
}
.wbd__dots { display: flex; gap: .3rem; flex: 0 0 auto; }
.wbd__dots i {
  width: 8px; height: 8px; border-radius: 50%;
  background: rgba(10, 10, 10, .18);
}
.wbd__url {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: clamp(.69rem, 1.1vw, .68rem);
  letter-spacing: .02em;
  color: var(--wbd-mute);
  background: #fff;
  border: 1px solid var(--wbd-rule-soft);
  border-radius: 999px;
  padding: .22rem .62rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The rectangle everything happens on. 8/5 is the captures' own aspect
   (1600x1000), so the real screenshot lands with nothing cropped off it. */
.wbd__view {
  position: relative;
  aspect-ratio: 8 / 5;
  overflow: hidden;
  background: #fff;
}

/* ── the baseline grid the layout is decided on ──────────────────────── */
/* Finished state: gone. It only exists during the sketch phase. */
.wbd__field {
  position: absolute;
  inset: 0;
  opacity: 0;
  background:
    repeating-linear-gradient(to right,
      rgba(200, 16, 46, .11) 0 1px, transparent 1px 8.3333%),
    repeating-linear-gradient(to bottom,
      rgba(10, 10, 10, .05) 0 1px, transparent 1px 12.5%);
}

/* ── the eleven blocks ───────────────────────────────────────────────── */
/* Finished state: gone, because the real capture has replaced it. */
.wbd__wire { position: absolute; inset: 0; opacity: 0; }

/* Authored PAINTED — the design phase's destination. wbdPaint runs
   backwards out of the dashed sketch state. */
.wbd__b {
  position: absolute;
  box-sizing: border-box;
  background-color: var(--fill, transparent);
  border: 1px solid var(--stroke, transparent);
  border-radius: var(--r, 0);
}

/* Percentages traced off the captures. left/top/width/height, in order:
   wordmark, nav links, nav CTA, eyebrow, headline A, headline B, red rule,
   lede, primary button, secondary button, image panel. */
.wbd__b--mark   { left: 5.5%;  top: 2.6%;  width: 10.5%; height: 4.2%; }
.wbd__b--nav    { left: 37%;   top: 4.0%;  width: 21%;   height: 1.6%; }
.wbd__b--navcta { left: 84%;   top: 2.2%;  width: 10.5%; height: 5.0%; }
.wbd__b--brow   { left: 5.5%;  top: 20.5%; width: 11%;   height: 1.9%; }
.wbd__b--ha     { left: 5.5%;  top: 26.5%; width: 34%;   height: 9.2%; }
.wbd__b--hb     { left: 5.5%;  top: 38.5%; width: 24%;   height: 9.2%; }
.wbd__b--hr   { left: 5.5%;  top: 53.0%; width: 4%;    height: .8%;  }
.wbd__b--lede   { left: 5.5%;  top: 58.0%; width: 27%;   height: 2.0%; }
.wbd__b--btn1   { left: 5.5%;  top: 67.0%; width: 12.5%; height: 5.6%; }
.wbd__b--btn2   { left: 19.5%; top: 67.0%; width: 12.0%; height: 5.6%; }
.wbd__b--panel  { left: 60%;   top: 12.0%; width: 35%;   height: 76%;  }

/* --fill / --stroke / --r are what each block IS once designed. One shared
   keyframe reads them, so the paint pass is eleven declarations rather
   than eleven keyframe blocks. */
.wbd__b--mark   { --fill: #0a0a0a; }
.wbd__b--navcta { --fill: #c8102e; --r: 2px; }
.wbd__b--brow   { --fill: #a4132c; }
.wbd__b--ha,
.wbd__b--hb     { --fill: #0a0a0a; }
.wbd__b--hr   { --fill: #c8102e; }
.wbd__b--lede   { --fill: rgba(10, 10, 10, .34); }
.wbd__b--btn1   { --fill: #c8102e; --r: 2px; }
.wbd__b--btn2   { --stroke: rgba(10, 10, 10, .78); --r: 2px; }
.wbd__b--panel  { --fill: var(--wbd-ivory); --stroke: rgba(10, 10, 10, .12); --r: 10px; }

/* The nav links are four tick marks inside one block, so the whole nav
   enters and paints as a single object rather than four. */
.wbd__b--nav { display: flex; gap: 8%; align-items: center; border: 0; padding: 0; }
.wbd__b--nav i { flex: 1 1 auto; height: 100%; background: rgba(10, 10, 10, .55); }

/* ── the real captures ───────────────────────────────────────────────── */
.wbd__shot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  opacity: 0;
  visibility: hidden;
  transform: scale(1.03);
  transition: opacity 420ms var(--wbd-e), transform 620ms var(--wbd-e);
}
/* The first capture carries is-on in the MARKUP, so the finished state is
   what renders with no script at all. */
.wbd__shot.is-on { opacity: 1; visibility: visible; transform: none; }

/* ══ THE RUN ═══════════════════════════════════════════════════════════
   Everything below fires off ONE class. Timeline, in ms from .is-on:

     0 -  760   sketch   blocks draw in, 70ms apart, over the red grid
   1150 - 1990  design   the same blocks paint, 28ms apart, left to right
   2250 - 3010  live     the capture resolves, the wire and grid retire

   Held on `both` so an element whose delay has not elapsed sits at its
   from-state and cannot flash its finished appearance first.          */

@keyframes wbdDraw {
  from { opacity: 0; transform: translateY(9px) scale(.965); }
  to   { opacity: 1; transform: none; }
}
@keyframes wbdPaint {
  from {
    background-color: transparent;
    border-color: rgba(10, 10, 10, .30);
    border-style: dashed;
    border-radius: 0;
  }
  to {
    background-color: var(--fill, transparent);
    border-color: var(--stroke, transparent);
    border-style: solid;
    border-radius: var(--r, 0);
  }
}
@keyframes wbdTick    { from { background-color: rgba(10, 10, 10, .24); }
                        to   { background-color: rgba(10, 10, 10, .55); } }
@keyframes wbdField   { from { opacity: 0; } 22% { opacity: 1; } 62% { opacity: 1; } to { opacity: 0; } }
@keyframes wbdWire    { from { opacity: 1; } 68% { opacity: 1; } to { opacity: 0; } }
@keyframes wbdReveal  { from { opacity: 0; visibility: visible; transform: scale(1.035); }
                        to   { opacity: 1; visibility: visible; transform: none; } }
@keyframes wbdSlideIn { from { opacity: 0; transform: translateX(-8px); }
                        to   { opacity: 1; transform: none; } }
@keyframes wbdRise    { from { opacity: 0; transform: translateY(10px); }
                        to   { opacity: 1; transform: none; } }
@keyframes wbdSweep   { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes wbdLight   { from { color: rgba(10, 10, 10, .34); border-bottom-color: transparent; }
                        to   { color: #0a0a0a; border-bottom-color: #c8102e; } }

.wbd.is-on .wbd__b {
  animation:
    wbdDraw  520ms var(--wbd-e) calc(var(--i) * 70ms) both,
    wbdPaint 700ms var(--wbd-e) calc(1150ms + var(--i) * 28ms) both;
}
.wbd.is-on .wbd__b--nav i { animation: wbdTick 700ms var(--wbd-e) 1178ms both; }

.wbd.is-on .wbd__field { animation: wbdField 3000ms var(--wbd-e) 60ms both; }
.wbd.is-on .wbd__wire  { animation: wbdWire 3020ms linear 0ms both; }
.wbd.is-on .wbd__shot--first { animation: wbdReveal 760ms var(--wbd-e) 2250ms both; }
.wbd.is-on .wbd__url span { animation: wbdSlideIn 480ms var(--wbd-e) 2340ms both; }

/* A tab click ends the intro. The animations are dropped rather than
   reversed, which lands on the authored finished state instantly. */
.wbd.is-done .wbd__wire,
.wbd.is-done .wbd__field,
.wbd.is-done .wbd__b,
.wbd.is-done .wbd__b--nav i,
.wbd.is-done .wbd__shot--first,
.wbd.is-done .wbd__url span,
.wbd.is-done .wbd__phase { animation: none; }

/* ── the phase rail ──────────────────────────────────────────────────── */
.wbd__rail {
  display: flex;
  align-items: center;
  gap: clamp(.5rem, 1.4vw, .9rem);
  margin-top: .85rem;
  flex-wrap: wrap;
}
.wbd__phase {
  display: inline-flex;
  align-items: baseline;
  gap: .4rem;
  font-family: var(--font-mono);
  font-size: clamp(.69rem, 1.1vw, .68rem);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #0a0a0a;
  border-bottom: 1px solid #c8102e;
  padding-bottom: 2px;
}
.wbd.is-on .wbd__phase--1 { animation: wbdLight 420ms var(--wbd-e) 120ms both; }
.wbd.is-on .wbd__phase--2 { animation: wbdLight 420ms var(--wbd-e) 1150ms both; }
.wbd.is-on .wbd__phase--3 { animation: wbdLight 420ms var(--wbd-e) 2250ms both; }

.wbd__phase-note {
  font-family: var(--font-mono);
  font-size: clamp(.69rem, 1vw, .66rem);
  color: rgba(10, 10, 10, .5);
  margin: 0;
  flex: 1 1 auto;
  text-align: right;
  min-width: 12ch;
}

/* ── the client tabs ─────────────────────────────────────────────────── */
.wbd__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  margin-top: 1rem;
}
.wbd__tab {
  font-family: var(--font-mono);
  font-size: clamp(.69rem, 1.1vw, .68rem);
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: .44rem .72rem;
  background: transparent;
  color: rgba(10, 10, 10, .64);
  border: 1px solid var(--wbd-rule);
  transition: background-color 180ms var(--wbd-e),
              color 180ms var(--wbd-e),
              border-color 180ms var(--wbd-e),
              transform 180ms var(--wbd-e);
}
.wbd__tab:hover, .wbd__tab:focus-visible { border-color: rgba(10, 10, 10, .44); color: #0a0a0a; }
.wbd__tab[aria-selected="true"] { background: var(--wbd-red); border-color: var(--wbd-red); color: #fff; }
.wbd__tab:active { transform: scale(.975); }

/* Only the selected client's line is in flow, so the block never sizes to
   the longest of the five. */
.wbd__meta { display: none; margin-top: .95rem; }
.wbd__meta.is-on { display: block; }
.wbd__meta-kind {
  display: block;
  font-family: var(--font-mono);
  font-size: clamp(.69rem, 1vw, .66rem);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--wbd-red-sm);
  margin: 0 0 .3rem;
}
.wbd__meta-desc {
  font-family: var(--font-body);
  font-size: clamp(.86rem, 1.3vw, .93rem);
  line-height: 1.6;
  color: var(--wbd-body);
  margin: 0;
  max-width: 58ch;
}
.wbd__meta-stack {
  font-family: var(--font-mono);
  font-size: clamp(.69rem, 1vw, .66rem);
  color: rgba(10, 10, 10, .5);
  margin: .35rem 0 0;
}

/* ══ THE QUOTE ═════════════════════════════════════════════════════════
   The arithmetic is /pricing's own, unrounded and unchanged:
     6 pages x $325 = $1,950 ; 2 integrations x $525 = $1,050 ; = $3,000.
   That is the exact decomposition pricing.html publishes for a custom
   Shopify build, so the two pages cannot drift without one of them
   visibly failing to add up.                                          */

.wbd__quote {
  border: 1px solid var(--wbd-rule);
  background: #fff;
  padding: clamp(1.1rem, 2.4vw, 1.5rem);
  /* Sharp against the browser's square corners — the alternation the
     system asks for, at component scale rather than section scale. */
  clip-path: polygon(4% 0, 100% 0, 100% 96%, 96% 100%, 0 100%, 0 4%);
}
.wbd__quote-k {
  display: block;
  font-family: var(--font-mono);
  font-size: clamp(.69rem, 1.1vw, .68rem);
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--wbd-red-sm);
  margin: 0 0 .2rem;
}
.wbd__quote-h {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.12rem, 2vw, 1.3rem);
  line-height: 1.2;
  margin: 0 0 1rem;
}

.wbd__lines { list-style: none; margin: 0; padding: 0; }
.wbd__line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .8rem;
  padding: .5rem 0;
  border-bottom: 1px solid var(--wbd-rule-soft);
  font-family: var(--font-mono);
  font-size: clamp(.72rem, 1.2vw, .78rem);
  color: var(--wbd-body);
}
.wbd__line b { color: var(--wbd-red-sm); font-weight: 500; }
.wbd__line em { font-style: normal; color: var(--wbd-ink); white-space: nowrap; }

.wbd.is-on .wbd__line { animation: wbdRise 460ms var(--wbd-e) calc(320ms + var(--i) * 130ms) both; }

/* The rule that closes the sum before the total lands. */
.wbd__sweep {
  height: 2px;
  background: var(--wbd-red);
  transform-origin: 0 50%;
  margin: .1rem 0 0;
}
.wbd.is-on .wbd__sweep { animation: wbdSweep 560ms var(--wbd-e) 720ms both; }

/* .t-dark is site.css's own dark-panel-inside-a-light-band class: it
   restores --on-black on itself AND on its descendants with !important, so
   this slab is bone-on-ink without a specificity fight. */
.wbd__total {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .8rem;
  flex-wrap: wrap;
  padding: .85rem 1rem;
  background: #0a0a0a;
}
.wbd.is-on .wbd__total { animation: wbdRise 520ms var(--wbd-e) 1000ms both; }
.wbd__total-k {
  font-family: var(--font-mono);
  font-size: clamp(.69rem, 1.1vw, .69rem);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: rgba(245, 241, 232, .74);
  max-width: 22ch;
  line-height: 1.45;
}
.wbd__total-v {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.5rem, 3vw, 2rem);
  line-height: 1;
  letter-spacing: -.01em;
}

.wbd__quote-note {
  font-family: var(--font-body);
  font-size: clamp(.8rem, 1.25vw, .87rem);
  line-height: 1.62;
  color: var(--wbd-mute);
  margin: .95rem 0 0;
}
.wbd__quote-note b { color: var(--wbd-ink); font-weight: 500; }

.wbd__go {
  display: inline-block;
  margin-top: .95rem;
  font-family: var(--font-mono);
  font-size: clamp(.69rem, 1.1vw, .68rem);
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--wbd-red-sm);
  text-decoration: none;
  border-bottom: 1px solid rgba(164, 19, 44, .38);
  padding-bottom: 2px;
  transition: border-color 180ms var(--wbd-e);
}
.wbd__go:hover, .wbd__go:focus-visible { border-bottom-color: var(--wbd-red-sm); }

/* ══ THE THREE PHASES, WRITTEN OUT ═════════════════════════════════════
   Same three words as the rail under the browser, on purpose: the reader
   watches sketch -> design -> live happen, then reads what each one is.
   This is the part that answers Ethan's actual complaint, because
   "software engineering" reads as "we take your Figma", and that is not
   what happens here.                                                   */

.wbd__phases {
  display: grid;
  gap: clamp(1.1rem, 2.4vw, 1.9rem);
  margin-top: clamp(2rem, 4vw, 3.2rem);
  padding-top: clamp(1.6rem, 3vw, 2.2rem);
  border-top: 1px solid var(--wbd-rule);
}
@media (min-width: 780px) { .wbd__phases { grid-template-columns: repeat(3, 1fr); } }

.wbd.is-on .wbd__col { animation: wbdRise 560ms var(--wbd-e) calc(120ms + var(--i) * 90ms) both; }

.wbd__col-k {
  display: block;
  font-family: var(--font-mono);
  font-size: clamp(.69rem, 1.1vw, .68rem);
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--wbd-red-sm);
  margin: 0 0 .45rem;
}
.wbd__col h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.05rem, 1.9vw, 1.25rem);
  line-height: 1.2;
  margin: 0 0 .5rem;
}
.wbd__col p {
  font-family: var(--font-body);
  font-size: clamp(.88rem, 1.35vw, .95rem);
  line-height: 1.62;
  color: var(--wbd-body);
  margin: 0;
}
.wbd__col p + p { margin-top: .55rem; }
.wbd__col p b { color: var(--wbd-ink); font-weight: 500; }

/* ══ MOBILE ════════════════════════════════════════════════════════════
   The estate was brought to zero horizontal scroll and zero sub-11px body
   text at 390 tonight and this section must not undo either. Every size
   above is a clamp; this block lifts the mono micro-labels clear of 11px
   on phones, where they are read at arm's length rather than on a desk.

   The wireframe needs no mobile treatment at all: it is percentage-
   positioned inside an aspect-ratio box, so it SCALES rather than
   reflows, and nothing in it can overflow its own rectangle at any
   width. That is the reason it is drawn in percentages instead of rem.  */

@media (max-width: 640px) {
  .wbd__eyebrow,
  .wbd__phase,
  .wbd__tab,
  .wbd__quote-k,
  .wbd__go,
  .wbd__col-k { font-size: .7rem; }
  .wbd__url,
  .wbd__phase-note,
  .wbd__meta-kind,
  .wbd__meta-stack { font-size: .69rem; }
  .wbd__line { font-size: .75rem; }
  /* A mono description plus a right-aligned amount is tight at 390, so the
     amount drops onto its own line rather than wrapping mid-sum. */
  .wbd__line { flex-wrap: wrap; row-gap: .15rem; }
  .wbd__line em { margin-left: auto; }
  .wbd__phase-note { display: none; }
  .wbd__total { padding: .8rem .85rem; }
}

/* ══ REDUCED MOTION ════════════════════════════════════════════════════
   Two lines, because the finished state is the authored state. Dropping
   the animations leaves the real capture on the screen, the sum legible,
   the phase rail lit and the columns present — a complete static reading
   of the section, not a broken one.                                    */

@media (prefers-reduced-motion: reduce) {
  .wbd *, .wbd { animation: none !important; }
  .wbd__shot, .wbd__tab { transition: none !important; }
}
