/* ==========================================================================
   system.css — the design system, applied on top of style / pcb / fx
   --------------------------------------------------------------------------
   Loaded last. Everything that decides how the site looks as a whole lives
   here: the scales (type, spacing, radius), the glass material, buttons,
   labels, and the small interaction details. The files before it describe
   layout and individual components; this one keeps them consistent.

   SCALES
     type     12 · 13 · 15 · 17 · 20 · 28 · 44 · 72 (top steps fluid)
     spacing  8-px rhythm: 8 · 16 · 24 · 32 · 48 · 64 · 96 · 128
     radius   12 small controls · 18 cards · 28 feature panels
     widths   1200 · 1024 · 880 · 620 · 400 (plus the nav's own steps)

   GLASS — used sparingly, where it builds hierarchy (NN/g):
     live blur   nav, hero stats, evidence cards, contact card, key facts,
                 back-to-top and the lightbox
     panel       every other card: the same material without a live blur,
                 which is what kept scrolling heavy
   ========================================================================== */

:root {
  --s1: 8px;  --s2: 16px; --s3: 24px; --s4: 32px;
  --s5: 48px; --s6: 64px; --s7: 96px; --s8: 128px;

  --r-s: 12px; --r-m: 18px; --r-l: 28px;

  /* The type scale. Text: 12, 13.5, 15.5, 18, 21, 26. Display: 34, 44,
     54, 84 (headings and figures). Nothing in between on desktop; display
     sizes scale down fluidly on phones through their clamp() minimums. */
  --t-xs: 12px; --t-s: 13.5px; --t-b: 15.5px; --t-m: 18px; --t-l: 21px;
  --t-xl: clamp(21px, 2vw, 26px);
  --t-2xl: clamp(30px, 3.4vw, 44px);
  --t-3xl: clamp(46px, 6.2vw, 84px);

  --label-track: .14em;

  /* Glass, dark. A directional rim (bright top-left edge, faint bottom-
     right) plus a soft highlight near the top: that is what reads as a
     piece of glass catching light, more than transparency does. */
  --glass-bg:
    linear-gradient(180deg, rgba(255,255,255,.07), rgba(255,255,255,0) 38%),
    linear-gradient(150deg, rgba(255,255,255,.07), rgba(255,255,255,.02) 46%, rgba(255,255,255,.045));
  --glass-edge:  rgba(255,255,255,.08);
  --glass-spec:  inset 1px 1px 0 rgba(255,255,255,.18), inset -1px -1px 0 rgba(255,255,255,.035), inset 0 1px 0 rgba(255,255,255,.12);
  --glass-glow:  0 0 0 transparent;     /* no coloured glow */
  --glass-drop:  0 18px 50px rgba(0,0,0,.42), 0 2px 6px rgba(0,0,0,.24);
  --glass-filter:    blur(22px) saturate(180%);
  --glass-filter-sm: blur(18px) saturate(170%);

  /* Panels: the same look without a live blur, a touch more solid so
     text stays readable over whatever is behind. */
  --panel-bg:
    linear-gradient(180deg, rgba(255,255,255,.055), rgba(255,255,255,0) 40%),
    linear-gradient(150deg, rgba(22,36,58,.72), rgba(9,17,31,.8));

  /* Richer light behind the glass. Glass only looks like glass when there
     is colour behind it to bend; the old backdrop was nearly flat navy. */
  --glow-a: rgba(201,164,92,.13);
  --glow-b: rgba(44,112,196,.26);
  --glow-c: rgba(38,150,165,.17);
  --glow-d: rgba(70,92,210,.18);
}

:root[data-theme="light"] {
  --glass-bg:
    linear-gradient(180deg, rgba(255,255,255,.7), rgba(255,255,255,0) 42%),
    linear-gradient(145deg, rgba(255,255,255,.74), rgba(255,253,248,.44) 45%, rgba(255,253,248,.6));
  --glass-edge:  rgba(255,255,255,.92);
  --glass-spec:  inset 1px 1px 0 rgba(255,255,255,1), inset -1px -1px 0 rgba(131,95,20,.08), 0 0 0 1px rgba(70,50,20,.06);
  --glass-glow:  0 0 0 transparent;
  --glass-drop:  0 18px 40px -16px rgba(70,50,20,.22), 0 1px 3px rgba(70,50,20,.08);
  --glass-filter:    blur(20px) saturate(150%) brightness(1.05);
  --glass-filter-sm: blur(16px) saturate(140%) brightness(1.04);
  --panel-bg:
    linear-gradient(180deg, rgba(255,255,255,.82), rgba(255,255,255,.2) 42%),
    linear-gradient(145deg, rgba(255,255,255,.9), rgba(251,248,242,.8));
  --glow-a: rgba(214,172,88,.30);
  --glow-b: rgba(80,150,160,.16);
  --glow-c: rgba(236,210,150,.28);
  --glow-d: rgba(40,78,130,.07);
}

/* ------------------------------------------------------------ panels ----
   Cards that repeat, or whose area is mostly a photograph, drop the live
   backdrop blur and use the panel material instead. */
.readout.glass, .readout-solid, .moment, .mini, .col,
.band-figure, .portrait {
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
.readout.glass, .moment, .mini, .col, .band-figure, .portrait {
  background: var(--panel-bg);
  border: 1px solid var(--glass-edge);
  box-shadow: var(--glass-spec), var(--shadow-md);
}
.readout-solid { background: var(--glass-edge); }
.rd { background: var(--panel-bg); }

/* The nav carries its own backing for contrast; give it the rim too. */
.nav-inner.glass { border-color: var(--glass-edge); box-shadow: var(--glass-spec), var(--glass-drop); }

/* Visitors who asked their system for less transparency get solid panels. */
@media (prefers-reduced-transparency: reduce) {
  .glass, .nav-inner.glass, .contact > .wrap, .case-facts, .ev, .stat, .fx-top, .fx-toast {
    -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
    background: var(--ink-3) !important;
  }
  .readout.glass, .moment, .mini, .col, .band-figure, .portrait, .rd { background: var(--ink-3); }
}

/* <picture> wrappers (WebP + JPEG fallback) take no part in layout. */
.band-figure picture, .portrait picture { display: contents; }

/* ------------------------------------------------------------ radius ---- */
.stat, .ev, .finding, .case-facts, .mini, .moment, .col, .shot,
.readout, .readout-solid, .case-nav a, .band-figure, .case-hero { border-radius: var(--r-m); }
.btn, .nav-cta, .theme-btn, .lb button, .nav-links { border-radius: var(--r-s); }
.nav-inner { border-radius: var(--r-m); }
.contact > .wrap { border-radius: var(--r-l); }

/* ------------------------------------------------------------- labels ---
   One label style for every small uppercase caption. They were spread over
   eleven sizes between 9.5 and 13px with tracking up to .26em. */
.eyebrow, .rd-k, .stat-k, .ev-label, .proj-domain, .finding-k, .case-grid h2,
.shots-h, .col h3, .sk-g, .case-nav-k, .case-facts h2, .case-facts dt, .mini-kind {
  font-size: 11.5px; letter-spacing: var(--label-track); line-height: 1.4;
}
.eyebrow { font-size: var(--t-xs); font-weight: 500; }
/* Section numbers ("01 SELECTED WORK") removed: only projects are numbered,
   where the number means something. */
.eyebrow[data-n]::before { content: none; }

/* body-copy steps */
.proj-cap, .shot figcaption, .note, .exp-tag, .edu-c, .edu-p-sub, .contact-note,
.mini-detail, .moment figcaption, .footer-in { font-size: var(--t-s); }
.ev-find, .exp-pts li, .event-sum, .case-grid p, .band-sub, .lead li, .sk-i { font-size: var(--t-b); }
.lead li, .sk-i { font-size: 14px; }
.sec-lede, .case-sub { font-size: var(--t-m); }

/* ---------------------------------------------------- solid, not shimmer --
   Gradient-shimmer text reads as template decoration; the numbers and the
   mark are simply gold. */
.stat-v, .nav-mark {
  background: none; -webkit-background-clip: border-box; background-clip: border-box;
  -webkit-text-fill-color: currentColor;
}
.stat-v { color: var(--gold-hi); }
.nav-mark { color: var(--gold); }

/* --------------------------------------------------- tags become text ----
   Rows of pills on every card were the loudest "template" signal. On the
   home page, tags and focus areas are plain text separated by dots; pills
   stay only on case pages where they are a compact reference. */
.row-tags, .lanes { gap: 0; }
.row-tags i, .lanes li {
  border: 0; padding: 0; border-radius: 0; background: none;
  font-size: var(--t-s); letter-spacing: .01em; color: var(--fg-2);
}
.row-tags, .lanes, .hero-glance {
  display: flex; flex-wrap: wrap; margin-left: -20px;
  clip-path: inset(-6px -6px -6px 20px);
}
.row-tags i, .lanes li, .hero-glance span { position: relative; margin-left: 20px; }
.row-tags i, .lanes li { white-space: nowrap; }
.row-tags i::before, .lanes li::before, .hero-glance span::before {
  content: '·'; position: absolute; left: -13px; color: var(--fg-3);
}

/* ------------------------------------------------------------ buttons ---
   Two kinds only, same height, radius and press everywhere. */
.btn {
  min-height: 44px; padding: 0 20px; font-size: 13.5px; font-weight: 500; letter-spacing: .02em;
  justify-content: center;
}
.btn-primary { background: rgba(var(--gold-rgb), .12); border-color: rgba(var(--gold-rgb), .5); }
.btn-primary:hover { background: rgba(var(--gold-rgb), .2); }
.btn:active, .nav-cta:active, .theme-btn:active, .prow:active, .mini-link:active {
  transform: translateY(0) scale(.97); transition-duration: .08s;
}

/* --------------------------------------------------------------- hero ---- */
.hero-hello { line-height: 1.1; }
.hero h1 { margin-top: 6px; }
.hero-tagline {
  border-left: 0; padding-left: 0; margin-top: var(--s3);
  font-size: clamp(17px, 2vw, 21px); color: var(--fg); max-width: 34ch; line-height: 1.5;
}
.hero-role { margin-top: var(--s3); font-size: var(--t-b); color: var(--fg-2); font-weight: 500; }
.lanes { margin-top: 6px; }
.hero-cta { margin-top: var(--s4); }
.hero-glance { margin-top: var(--s2); display: flex; flex-wrap: wrap; font-size: var(--t-s); color: var(--fg-3); }


/* ------------------------------------------------------- Easter egg ------ */
.fx-toast {
  position: fixed; left: 50%; bottom: 28px; z-index: 120;
  transform: translate(-50%, 16px); opacity: 0; pointer-events: none;
  max-width: calc(100% - 32px); padding: 12px 18px; border-radius: var(--r-s);
  font-size: var(--t-s); color: var(--fg);
  background: var(--glass-bg), var(--ink-2);
  -webkit-backdrop-filter: var(--glass-filter-sm); backdrop-filter: var(--glass-filter-sm);
  border: 1px solid rgba(var(--gold-rgb), .4);
  box-shadow: var(--glass-spec), var(--glass-drop);
  transition: opacity .3s var(--ease), transform .3s var(--ease);
}
.fx-toast.show { opacity: 1; transform: translate(-50%, 0); }

/* Toast action buttons (Switch off / Replace fuse) */
.fx-toast { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; pointer-events: none; }
.fx-toast.show { pointer-events: auto; }
.fx-toast-btn {
  font: inherit; font-size: 12.5px; cursor: pointer; color: var(--gold-hi);
  padding: 6px 12px; border-radius: 999px; min-height: 32px;
  background: rgba(var(--gold-rgb), .1); border: 1px solid rgba(var(--gold-rgb), .45);
}
.fx-toast-btn:hover { background: rgba(var(--gold-rgb), .2); }

/* ---------------------------------------------------- board: POWERED ----
   Set by 5 clicks on the SK mark and remembered. Every trace runs gold. */
:root { --live: #F3CF7A; --live-rgb: 243,207,122; }
.powered .hero-circuit .t { stroke: var(--live); stroke-opacity: .85; stroke-width: 1.6; stroke-dashoffset: 0; }
.powered .hero-circuit .pad { stroke: var(--live); }
.powered .conn-line { color: rgba(var(--live-rgb), .75); }
.powered .conn-sym  { color: var(--live); }
.powered .sec-rule .ln { background: linear-gradient(90deg, rgba(var(--live-rgb), .8), rgba(var(--live-rgb), .25) 70%, transparent); }
.powered .via { border-color: rgba(var(--live-rgb), .8); }
.powered .via::after, .powered .cv { background: var(--live); fill: var(--copper); stroke: var(--live); }
.powered .exp-pts li::before, .powered .lead li::before { border-color: rgba(var(--live-rgb), .7); }
.powered .exp-pts li::after, .powered .lead li::after { background: var(--live); }
.powered .bg-mesh { filter: sepia(.9) saturate(2.6) hue-rotate(-12deg) brightness(1.25); opacity: .34; }
:root[data-theme="light"].powered .bg-mesh { filter: invert(1) hue-rotate(180deg) sepia(.9) saturate(2.4) brightness(.9); opacity: .24; }
:root[data-theme="light"] { --live: #B07F18; --live-rgb: 176,127,24; }
.powered .nav-led { background: #5CFF96; box-shadow: 0 0 8px 2px rgba(92,255,150,.6); }
.powered .nav-mark { color: var(--live); text-shadow: 0 0 12px rgba(var(--live-rgb), .6); }

/* ------------------------------------------------ board: OVERVOLTAGE --- */
:root.overvolt { --live: #FFB347; --live-rgb: 255,179,71; }
@keyframes fxFlicker { 0%, 100% { opacity: 1; } 42% { opacity: .55; } 46% { opacity: 1; } 71% { opacity: .7; } }

/* ----------------------------------------------------- board: BROKEN ----
   Fuse blown. Cards are knocked askew with the individual rotate/translate
   properties, so they stack on top of whatever transform a card already
   has (tilt, reveal) instead of fighting it. */
:root.broken { --live: #FF5A4E; --live-rgb: 255,90,78; }
.broken .bg-mesh, :root[data-theme="light"].broken .bg-mesh { filter: sepia(1) saturate(5) hue-rotate(-50deg) brightness(1.1); }
.broken .bg { filter: brightness(.8) saturate(.9); }
.broken .nav-led { background: #FF5A4E; box-shadow: 0 0 8px 2px rgba(255,90,78,.6); }

@media (prefers-reduced-motion: no-preference) {
  .overvolt .hero-circuit, .overvolt .conn-line, .overvolt .sec-rule { animation: fxFlicker .9s steps(1) infinite; }
  .broken .hero-circuit, .broken .conn-line, .broken .sec-rule, .broken .bg-mesh { animation: fxFlicker .35s steps(1) infinite; }
  .broken .nav-led { animation: fxFlicker .25s steps(1) infinite; }
}

/* ------------------------------------------------ the fuse blowing ---- */
/* 1. the surge: a white flash and a jolt, just before the fuse goes */
.surge body::after {
  content: ''; position: fixed; inset: 0; z-index: 140; pointer-events: none;
  background: radial-gradient(circle at 8% 4%, rgba(255,255,255,.9), rgba(255,236,190,.35) 30%, transparent 70%);
  animation: fxFlash .38s ease-out forwards;
}
@keyframes fxFlash { from { opacity: 1; } to { opacity: 0; } }
@media (prefers-reduced-motion: no-preference) {
  .surge main, .surge .nav { animation: fxJolt .38s steps(6) 1; }
}
@keyframes fxJolt {
  0% { translate: 0 0; } 20% { translate: -6px 3px; } 40% { translate: 5px -4px; }
  60% { translate: -4px -2px; } 80% { translate: 3px 3px; } 100% { translate: 0 0; }
}

/* 2. sparks from the SK mark */
.fx-sparks, .fx-smoke { position: fixed; z-index: 135; pointer-events: none; width: 0; height: 0; }
.fx-sparks i {
  position: absolute; left: -2px; top: -2px; width: 4px; height: 4px; border-radius: 50%;
  background: #FFE7A3; box-shadow: 0 0 6px 2px rgba(255,190,80,.9);
  animation: fxSpark .7s cubic-bezier(.2,.7,.4,1) var(--sd, 0s) forwards;
}
@keyframes fxSpark {
  from { transform: translate(0, 0) scale(1.2); opacity: 1; }
  to   { transform: translate(var(--sx), var(--sy)) scale(.2); opacity: 0; }
}

/* 3. magic smoke: several puffs drifting up and spreading */
.fx-smoke i {
  position: absolute; left: -18px; top: -18px; width: 36px; height: 36px; border-radius: 50%;
  background: radial-gradient(circle, rgba(185,185,195,.55), rgba(120,120,130,0) 70%);
  animation: fxSmoke 2.6s ease-out var(--md, 0s) forwards; opacity: 0;
}
@keyframes fxSmoke {
  0%   { opacity: .9; transform: translate(0, 0) scale(.5); }
  100% { opacity: 0;  transform: translate(var(--mx, 10px), -130px) scale(var(--ms, 2.8)); }
}

/* 4. the broken board: headings pick up a colour split that shimmers now
      and then. Colour only (text-shadow), so the text always stays whole
      and readable. */
.broken .hero h1, .broken .sec-head h2, .broken .prow-title {
  text-shadow: -1.5px 0 rgba(255,60,80,.45), 1.5px 0 rgba(60,200,255,.35);
}
@media (prefers-reduced-motion: no-preference) {
  .broken .hero h1, .broken .sec-head h2 { animation: fxGlitch 3.2s steps(1) infinite; }
}
@keyframes fxGlitch {
  0%, 88%, 100% { text-shadow: -1.5px 0 rgba(255,60,80,.45), 1.5px 0 rgba(60,200,255,.35); }
  90% { text-shadow: -4px 0 rgba(255,60,80,.6), 3px 0 rgba(60,200,255,.5); }
  92% { text-shadow: 3px 0 rgba(255,60,80,.55), -3px 0 rgba(60,200,255,.45); }
  94% { text-shadow: -2px 0 rgba(255,60,80,.5), 2px 0 rgba(60,200,255,.4); }
}

/* 4a. a dim red cast at the screen edges while the fuse is open */
.broken body::before {
  content: ''; position: fixed; inset: 0; z-index: 3; pointer-events: none;
  background-image: linear-gradient(180deg, rgba(255,70,60,.16), transparent 20%, transparent 80%, rgba(255,70,60,.16)),
                    linear-gradient(90deg, rgba(255,70,60,.10), transparent 12%, transparent 88%, rgba(255,70,60,.10));
}

/* 4b. a dead control: clicked with no power, it flickers and does nothing.
       Outline only, so nothing moves. */
.fx-dead { outline: 1px dashed rgba(255,90,78,.75); outline-offset: 2px; }
@media (prefers-reduced-motion: no-preference) {
  .fx-dead { animation: fxDead .55s steps(1) 1; }
}
@keyframes fxDead { 0%, 40%, 80% { opacity: .45; } 20%, 60%, 100% { opacity: 1; } }
/* no hover response from a dead board either */
.broken .prow:hover, .broken .rv.in.prow:hover, .broken .btn:hover { transform: none; }

/* 5. replacing the fuse: a power cycle with a boot log */
.fx-reboot {
  position: fixed; inset: 0; z-index: 150; display: grid; place-items: center;
  background: #020408; opacity: 0; transition: opacity .35s ease; pointer-events: none;
}
.fx-reboot.on { opacity: 1; pointer-events: auto; }
.fx-reboot pre {
  font-family: var(--mono); font-size: 13px; line-height: 1.8; color: #9FE3B4;
  min-width: min(360px, 86vw); white-space: pre-wrap;
}

/* ------------------------------------------------------- UART console --- */
.fx-uart {
  position: fixed; left: clamp(12px, 3vw, 28px); bottom: clamp(12px, 3vw, 28px); z-index: 125;
  width: min(430px, calc(100% - 24px)); border-radius: var(--r-m); overflow: hidden;
  background: rgba(3, 7, 12, .92); border: 1px solid rgba(var(--cyan-rgb), .35);
  box-shadow: 0 24px 60px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.08);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  font-family: var(--mono); font-size: 12.5px; color: #CFE9EE;
  opacity: 0; transform: translateY(14px); pointer-events: none;
  transition: opacity .25s var(--ease), transform .25s var(--ease);
}
.fx-uart.show { opacity: 1; transform: none; pointer-events: auto; }
.fx-uart-bar {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px 8px 14px;
  font-size: 11px; letter-spacing: .1em; color: #8FB6BF; border-bottom: 1px solid rgba(255,255,255,.08);
}
.fx-uart-bar .led { width: 6px; height: 6px; border-radius: 50%; background: #5CFF96; box-shadow: 0 0 6px #5CFF96; }
.fx-uart-x { margin-left: auto; width: 32px; height: 32px; border: 0; border-radius: 8px; background: none; color: #8FB6BF; font-size: 20px; cursor: pointer; }
.fx-uart-x:hover { background: rgba(255,255,255,.08); }
.fx-uart-out { height: 190px; overflow-y: auto; padding: 10px 14px; line-height: 1.6; white-space: pre-wrap; scrollbar-width: thin; }
.fx-uart-out .cmd { color: #F3CF7A; }
.fx-uart-in { display: flex; gap: 8px; align-items: center; padding: 8px 14px 12px; border-top: 1px solid rgba(255,255,255,.06); color: #F3CF7A; }
.fx-uart-in input { flex: 1; min-width: 0; background: none; border: 0; outline: none; color: #EAF6F8; font: inherit; caret-color: #5CFF96; }

/* silkscreen designators while the console is open */
.silk [data-ref] { position: relative; }
.silk [data-ref]::after {
  content: attr(data-ref); position: absolute; top: -9px; left: 14px; z-index: 5;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .08em; line-height: 1;
  padding: 3px 6px; border-radius: 4px; pointer-events: none;
  color: var(--ink); background: rgba(var(--gold-rgb), .85);
}

@media (prefers-reduced-motion: reduce) {
  .fx-toast { transition: none; }
}

/* ======================================================== project list ===
   Compact glass rows that alternate sides, joined by short circuit
   connectors. The first four are visible; the rest sit collapsed behind a
   stack of glass slabs until "Show all". A plain click opens a pop-up. */
.plist { position: relative; }
.prow {
  position: relative; z-index: 1; display: grid; align-items: center;
  grid-template-columns: minmax(0, 340px) minmax(0, 1fr); gap: clamp(18px, 3vw, 36px);
  padding: 12px; border-radius: var(--r-m); color: inherit;
  background: var(--panel-bg); border: 1px solid var(--glass-edge);
  box-shadow: var(--glass-spec), var(--shadow-md);
  transition: transform .4s var(--ease-out), border-color .3s var(--ease), box-shadow .4s var(--ease-out), opacity .8s var(--ease-out);
}
.prow.flip { grid-template-columns: minmax(0, 1fr) minmax(0, 340px); }
.prow.flip .prow-media { order: 2; }
.prow-fig { display: block; aspect-ratio: 16 / 10; overflow: hidden; border-radius: var(--r-s); }
.prow-fig picture { display: contents; }
.prow-fig img { width: 100%; height: 100%; object-fit: cover; filter: var(--img-dim); transition: transform 1s var(--ease-out); }
.prow-body { display: flex; flex-direction: column; gap: 8px; padding: 6px clamp(4px, 1.4vw, 16px); min-width: 0; }
.prow-title { font-family: var(--sans); font-size: clamp(24px, 2.8vw, 32px); line-height: 1.1; letter-spacing: -.01em; transition: color .3s var(--ease); }
.prow-sub { font-size: var(--t-b); color: var(--fg-2); max-width: 52ch; }
.prow .row-tags { margin-top: 2px; }
.prow-go { display: inline-flex; align-items: center; gap: 6px; margin-top: 6px; font-size: var(--t-s); color: var(--gold); }
.prow-go svg { width: 13px; height: 13px; transition: transform .3s var(--ease); }
.rv.in.prow:hover, .prow:not(.rv):hover { transform: translateY(-3px); }
.prow:hover { border-color: rgba(var(--gold-rgb), .35); box-shadow: var(--glass-spec), var(--shadow-lg); }
.prow:hover .prow-title { color: var(--gold-hi); }
.prow:hover .prow-fig img { transform: scale(1.035); }
.prow:hover .prow-go svg { transform: translate(2px, -2px); }
.prow .band-top .proj-year { margin-left: auto; }

/* short connectors between rows */
.conn-short { height: clamp(46px, 5.5vw, 70px); margin: 0; }

/* the stack: slabs of glass tucked under the last visible row */
.plist-stack { position: relative; height: 38px; margin-top: -12px; transition: opacity .35s var(--ease), height .45s var(--ease-out); }
.plist-stack .slab {
  position: absolute; height: 26px; border-radius: 0 0 var(--r-m) var(--r-m);
  background: var(--panel-bg); border: 1px solid var(--glass-edge); border-top: 0;
  box-shadow: var(--shadow-md);
}
.plist-stack .s1 { top: 0;  left: 2%; right: 2%; opacity: .85; }
.plist-stack .s2 { top: 10px; left: 4.5%; right: 4.5%; opacity: .6; z-index: -1; }
.plist-stack .s3 { top: 20px; left: 7%; right: 7%; opacity: .38; z-index: -2; }
.plist-stack.gone { opacity: 0; height: 0; pointer-events: none; }

/* the collapsed rows */
.plist-more { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .6s var(--ease-out); }
.plist-more.open { grid-template-rows: 1fr; }
.plist-more-clip { min-height: 0; overflow: clip; overflow-clip-margin: 48px; }
.plist-more:not(.open) .plist-more-clip { visibility: hidden; transition: visibility 0s .6s; }

.plist-toggle { display: flex; justify-content: center; margin-top: var(--s3); }
.plist-toggle .btn svg { transition: transform .35s var(--ease); }
.plist-toggle .btn[aria-expanded="true"] svg { transform: rotate(180deg); }
.plist-toggle .btn:hover svg { transform: none; }
.plist-toggle .btn[aria-expanded="true"]:hover svg { transform: rotate(180deg); }

@media (max-width: 880px) {
  .prow, .prow.flip { grid-template-columns: 1fr; gap: 12px; }
  .prow.flip .prow-media { order: 0; }
  .prow-body { padding: 4px 6px 8px; }
}

/* evidence card → its project */
.ev { display: flex; flex-direction: column; }
.ev-from { display: inline-flex; align-items: center; gap: 6px; margin-top: auto; padding-top: var(--s2); align-self: flex-start; font-size: var(--t-s); color: var(--gold); }
.ev-from svg { width: 12px; height: 12px; }
.ev-from:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ============================================================== pop-up === */
dialog.pop {
  padding: 0; border: 0; background: transparent; color: var(--fg);
  width: min(720px, calc(100% - 32px)); max-width: none; max-height: calc(100dvh - 40px);
  margin: auto; overflow: auto; border-radius: var(--r-l); overscroll-behavior: contain;
  /* no scrollbar: it broke the card's symmetry and the card is sized to fit
     a normal screen anyway; on a very short one it still scrolls by wheel,
     touch or keys */
  scrollbar-width: none;
}
dialog.pop::-webkit-scrollbar { display: none; }
dialog.pop[open] { animation: popIn .28s var(--ease-appear); }
dialog.pop[open]::backdrop { animation: popFade .28s var(--ease-out); }
dialog.pop::backdrop { transition: opacity .18s cubic-bezier(.4, 0, 1, 1); }
dialog.pop.closing::backdrop { opacity: 0; }
dialog.pop::backdrop { background: rgba(4, 8, 15, .62); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
:root[data-theme="light"] dialog.pop::backdrop { background: rgba(40, 36, 28, .28); }
@keyframes popIn { from { opacity: 0; transform: translateY(10px) scale(.985); } to { opacity: 1; transform: none; } }
@keyframes popFade { from { opacity: 0; } }
.pop-in {
  position: relative; overflow: hidden; border-radius: var(--r-l);
  background: var(--glass-bg), var(--ink-2); border: 1px solid var(--glass-edge);
  box-shadow: var(--glass-spec), 0 30px 90px rgba(0, 0, 0, .5);
}
/* the picture sits inset in the card with its own rounded frame (the card
   radius less the inset), so its edges line up with the text */
.pop-fig {
  --pop-in: clamp(10px, 1.6vw, 14px);
  position: relative; aspect-ratio: 16 / 10; overflow: hidden; margin: var(--pop-in);
  border-radius: calc(var(--r-l) - var(--pop-in)); background: var(--ink-3);
  box-shadow: inset 0 0 0 1px var(--hair-2), 0 10px 28px -14px rgba(0, 0, 0, .45);
}
.pop-fig picture { display: contents; }
.pop-fig img { width: 100%; height: 100%; object-fit: cover; display: block; filter: var(--img-dim); }
.pop-title { font-family: var(--sans); font-size: clamp(28px, 4vw, 38px); line-height: 1.08; margin-top: 10px; }
.pop-sub { color: var(--fg-2); font-size: var(--t-m); margin-top: 8px; }
.pop-specs { margin: var(--s3) 0 0; max-width: none; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.pop .tags { margin-top: var(--s2); }
.pop-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: var(--s3); }

/* Phones: one column: the picture, then the overview. */
.pop-in { display: flex; flex-direction: column; }
.pop-main { padding: 6px clamp(18px, 3vw, 26px) clamp(18px, 3vw, 24px); }

/* Wider screens: picture and facts on the left, the story on the right,
   so the whole card fits a laptop screen without scrolling. */
@media (min-width: 900px) {
  dialog.pop { width: min(940px, calc(100% - 48px)); }
  .pop-in { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); align-items: center; }
  .pop-main { padding: 26px 30px 26px 14px; }
  .pop-head { padding-right: 48px; }
}
.pop-x {
  position: absolute; top: 12px; right: 12px; z-index: 2; width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer; color: #F2EFE7;
  background: rgba(4, 8, 15, .55); border: 1px solid rgba(255, 255, 255, .2);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.pop-x svg { width: 18px; height: 18px; }
.pop-x:hover { background: rgba(4, 8, 15, .75); }
@media (max-width: 620px) {
  .pop-actions .btn { flex: 1 1 100%; }
}
@media (max-width: 380px) { .pop-specs { grid-template-columns: 1fr 1fr; } }
@media (prefers-reduced-motion: reduce) {
  dialog.pop[open] { animation: popFade .15s linear; }
  .plist-more { transition: none; }
}

/* ------------------------------------------------------------- hints ----
   Quiet nudges towards the Easter eggs (js/fx.js hints()). */
.nav-status { cursor: pointer; }
.nav-mark { position: relative; }
.nav-mark::after {
  content: ''; position: absolute; inset: 6px -2px; border-radius: 10px; pointer-events: none;
  border: 1px solid rgba(var(--gold-rgb), .0);
}
@media (prefers-reduced-motion: no-preference) {
  /* one soft pulse on the SK mark once the page has appeared (fx.js adds
     .hinted, after the loader if there is one) */
  .nav.hinted .nav-mark::after { animation: fxHint 1.6s var(--ease-out) 1.2s 1; }
}
@keyframes fxHint {
  0% { border-color: rgba(var(--gold-rgb), .7); transform: scale(.9); opacity: 1; }
  100% { border-color: rgba(var(--gold-rgb), 0); transform: scale(1.35); opacity: 0; }
}
.nav-mark:hover { text-shadow: 0 0 10px rgba(var(--gold-rgb), .45); }
.foot-hint { flex-basis: 100%; text-align: center; font-size: 11.5px; color: var(--fg-3); margin-top: 6px; letter-spacing: .02em; }

/* ---------------------------------------------------------- selection ---
   Selected text uses the site's own colours instead of the browser blue:
   gold on navy in the dark theme, navy on ivory in the light one. */
::selection { background: rgba(201, 164, 92, .85); color: #04080F; text-shadow: none; }
::-moz-selection { background: rgba(201, 164, 92, .85); color: #04080F; text-shadow: none; }
:root[data-theme="light"] ::selection { background: rgba(14, 23, 38, .85); color: #F4EFE4; }
:root[data-theme="light"] ::-moz-selection { background: rgba(14, 23, 38, .85); color: #F4EFE4; }
/* images and icons do not take a selection tint */
img::selection, svg::selection { background: transparent; }

/* ---------------------------------------------------------------- logo ---
   The SK monogram (assets/img/logo-sk*, cut out by tools/logo.py). It is
   the power switch for the Easter egg, so its states follow the board. */
.nav-mark { display: inline-flex; align-items: center; min-height: 44px; }
.nav-mark picture { display: contents; }
.nav-logo { height: 34px; width: auto; display: block; transition: filter .35s var(--ease), transform .3s var(--ease); }
.nav-mark:hover .nav-logo { transform: scale(1.04); filter: drop-shadow(0 0 8px rgba(var(--gold-rgb), .35)); }
.powered .nav-logo { filter: drop-shadow(0 0 6px rgba(var(--live-rgb), .75)) drop-shadow(0 0 16px rgba(var(--live-rgb), .35)); }
:root.overvolt .nav-logo { filter: sepia(.4) saturate(1.6) hue-rotate(-12deg) drop-shadow(0 0 8px rgba(255,179,71,.7)); }
:root.broken .nav-logo { filter: sepia(1) saturate(4) hue-rotate(-45deg) brightness(.9) drop-shadow(0 0 8px rgba(255,90,78,.7)); }
@media (prefers-reduced-motion: no-preference) {
  :root.broken .nav-logo { animation: fxFlicker .3s steps(1) infinite; }
}
@media (max-width: 400px) { .nav-logo { height: 28px; } }

/* ------------------------------------------------ refraction surfaces (js/glass.js) ----
   Where the SVG lens filter is active (Chromium), the glass gets a brighter
   specular rim so it reads as a thick piece of glass, not a tinted panel. */
.lg-refract .lg-on {
  background:
    linear-gradient(180deg, rgba(255,255,255,.10), rgba(255,255,255,0) 34%),
    linear-gradient(150deg, rgba(255,255,255,.05), rgba(255,255,255,.01) 50%, rgba(255,255,255,.035)) !important;
  border-color: rgba(255,255,255,.14) !important;
  box-shadow:
    inset 1.5px 1.5px 0 rgba(255,255,255,.32),
    inset -1px -1px 0 rgba(255,255,255,.08),
    inset 0 -18px 30px -24px rgba(255,255,255,.28),
    0 20px 50px rgba(0,0,0,.4) !important;
}
/* The nav keeps a tinted backing under the lens, so its links stay
   readable over whatever passes beneath. */
.lg-refract .nav-inner.lg-on {
  background:
    linear-gradient(180deg, rgba(255,255,255,.08), rgba(255,255,255,0) 40%),
    rgba(8,14,24,.62) !important;
}
:root[data-theme="light"].lg-refract .nav-inner.lg-on {
  background:
    linear-gradient(180deg, rgba(255,255,255,.6), rgba(255,255,255,0) 40%),
    rgba(250,247,240,.72) !important;
}
:root[data-theme="light"].lg-refract .lg-on {
  background:
    linear-gradient(180deg, rgba(255,255,255,.5), rgba(255,255,255,0) 40%),
    linear-gradient(150deg, rgba(255,253,247,.28), rgba(255,253,247,.08) 50%, rgba(255,253,247,.2)) !important;
  border-color: rgba(255,255,255,.75) !important;
  box-shadow:
    inset 1.5px 1.5px 0 rgba(255,255,255,.95),
    inset -1px -1px 0 rgba(131,95,20,.08),
    0 0 0 1px rgba(70,50,20,.05),
    0 14px 30px -16px rgba(70,50,20,.3) !important;
}
.lg-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ------------------------------------------------------------- folds ----
   Detail behind a small toggle (Experience, earlier schooling, the longer
   leadership list). Same grid-rows open/close as "Show all". */
.fold { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .34s var(--ease-out); }
.fold.open { grid-template-rows: 1fr; }
.fold-clip { min-height: 0; overflow: hidden; }
.fold:not(.open) .fold-clip { visibility: hidden; transition: visibility 0s .34s; }
.fold-clip > .exp-pts { margin-top: 11px; }
.fold-btn {
  display: inline-flex; align-items: center; gap: 6px; min-height: 36px; margin-top: 6px; padding: 0 2px;
  font: 500 12px/1 var(--mono); letter-spacing: .06em; text-transform: uppercase; color: var(--gold-hi);
  background: none; border: 0; cursor: pointer;
}
.fold-btn svg { width: 14px; height: 14px; transition: transform .3s var(--ease); }
.fold-btn[aria-expanded="true"] svg { transform: rotate(180deg); }
.fold-btn:hover .t { text-decoration: underline; text-underline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .fold, .fold-btn svg { transition: none; } }

/* --------------------------------------------------------- about tabs ----
   Phones only: one column at a time. Wider screens show all three. */
.about-tabs { display: none; }
@media (max-width: 620px) {
  .about-tabs {
    display: flex; gap: 4px; padding: 4px; margin-bottom: 14px;
    border: 1px solid var(--glass-edge); border-radius: 999px; background: var(--panel-bg);
  }
  .about-tabs [role="tab"] {
    flex: 1; min-height: 40px; border: 0; border-radius: 999px; background: none; cursor: pointer;
    font: 500 12.5px/1 var(--sans); letter-spacing: .02em; color: var(--fg-2);
    transition: background .25s var(--ease), color .25s var(--ease);
  }
  .about-tabs [aria-selected="true"] { background: rgba(var(--gold-rgb), .16); color: var(--gold-hi); box-shadow: inset 0 0 0 1px rgba(var(--gold-rgb), .35); }
  .cols > .col:not(.on) { display: none; }
}


/* ----------------------------------------------------- phone polish ----
   The toast becomes a bottom sheet with its buttons side by side, and the
   back-to-top button keeps clear of the footer line. */
@media (max-width: 560px) {
  .fx-toast {
    left: 12px; right: 12px; bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    max-width: none; transform: translateY(16px); padding: 14px 16px; gap: 10px 8px;
  }
  .fx-toast.show { transform: none; }
  .fx-toast > span { flex: 1 1 100%; }
  .fx-toast-btn { flex: 1 1 0; min-height: 40px; }
  .footer { padding-bottom: 84px; }
}

/* the progress trace under the nav: a little stronger, with a bright head
   like a signal running along it */
.nav-prog { height: 1.5px; opacity: .9; }
.nav-prog::after {
  content: ''; position: absolute; right: -2px; top: 50%; width: 5px; height: 5px; margin-top: -2.5px;
  border-radius: 50%; background: var(--gold-hi); box-shadow: 0 0 8px 2px rgba(var(--gold-rgb), .6);
}

/* the dead board: pictures go dim like an unpowered display, and the
   power browns out now and then (the pieces falling apart are js/fx.js) */
.broken main img { filter: brightness(.72) saturate(.55); transition: filter .6s var(--ease); }
@media (prefers-reduced-motion: no-preference) {
  .broken body::before { animation: fxBrownout 5.2s steps(1) infinite; }
}
@keyframes fxBrownout {
  0%, 90%, 100% { background-color: transparent; }
  91% { background-color: rgba(0,0,0,.42); }
  92% { background-color: transparent; }
  94% { background-color: rgba(0,0,0,.28); }
  95% { background-color: transparent; }
}

/* sparks from the pointer while the board is powered (desktop only) */
.fx-trail { position: fixed; inset: 0; z-index: 72; pointer-events: none; width: 100%; height: 100%; }

/* burn marks on a few of the fallen cards */
.fx-burn {
  position: absolute; inset: 0; z-index: 3; pointer-events: none; border-radius: inherit;
  background:
    radial-gradient(var(--bs) calc(var(--bs) * .7) at var(--bx) var(--by), rgba(6,4,2,.9), rgba(18,11,5,.72) 40%, rgba(40,24,10,.28) 70%, transparent),
    radial-gradient(calc(var(--bs) * .6) calc(var(--bs) * .45) at var(--bx2) 100%, rgba(10,6,3,.8), rgba(40,24,10,.25) 60%, transparent),
    linear-gradient(0deg, rgba(20,10,4,.45), transparent 22%);
  animation: fxBurn .9s ease-out both;
}
@keyframes fxBurn { from { opacity: 0; } to { opacity: 1; } }

/* the lights stutter for a moment before the fuse goes */
@media (prefers-reduced-motion: no-preference) {
  .flicker body::before {
    content: ''; position: fixed; inset: 0; z-index: 140; pointer-events: none;
    animation: fxStutter .9s steps(1) both;
  }
}
@keyframes fxStutter {
  0%, 100% { background: transparent; }
  10% { background: rgba(0,0,0,.55); } 18% { background: transparent; }
  32% { background: rgba(0,0,0,.35); } 38% { background: transparent; }
  55% { background: rgba(0,0,0,.7); }  62% { background: rgba(0,0,0,.2); }
  74% { background: rgba(0,0,0,.6); }  82% { background: transparent; }
}

/* every extra click on a live board shakes the page a little harder */
@media (prefers-reduced-motion: no-preference) {
  .zapped main, .zapped .nav-inner { animation: fxZap .32s steps(5) 1; }
}
@keyframes fxZap {
  0%, 100% { translate: 0 0; }
  20% { translate: calc(var(--zap, 1px) * -1) calc(var(--zap, 1px) * .6); }
  40% { translate: var(--zap, 1px) calc(var(--zap, 1px) * -.8); }
  60% { translate: calc(var(--zap, 1px) * -.6) calc(var(--zap, 1px) * -.4); }
  80% { translate: calc(var(--zap, 1px) * .5) calc(var(--zap, 1px) * .5); }
}

/* ------------------------------------------------- wreckage (wreck.js) ----
   Arcs are drawn on one fixed canvas; cracks are an SVG laid over a card.
   Dead glass: with no power the live blur goes, which also keeps the
   moving pieces cheap to draw. */
.fx-arcs { position: fixed; inset: 0; z-index: 71; pointer-events: none; width: 100%; height: 100%; }
.fx-crack { position: absolute; inset: 0; z-index: 4; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
.fx-crack path { fill: none; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.fx-crack .dk { stroke: rgba(0,0,0,.55); stroke-width: 3; }
.fx-crack .lt { stroke: rgba(255,255,255,.62); stroke-width: 1.1; }
:root[data-theme="light"] .fx-crack .lt { stroke: rgba(255,255,255,.95); }
.broken :is(.glass, .ev, .stat, .col, .moment, .mini, .case-facts, .prow, .shot, .event, .readout, .contact > .wrap) {
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
}
.broken .fx-piece { cursor: grab; user-select: none; -webkit-user-select: none; }
.fx-grabbing, .fx-grabbing * { cursor: grabbing !important; }
.broken .plist-more-clip { overflow: visible; }
@media (hover: none) { .broken .fx-piece { cursor: auto; } }

/* ======================================================== refinement v2 ===
   From the design audit. Everything here overrides earlier rules; delete
   this block (and restore the font link and tokens) to go back.

   Type: one sans (Schibsted Grotesk) with JetBrains Mono for figures,
   weight and tracking instead of size, an eight-step scale.
   Colour: gold means "you can act on this", cyan means "this is a measured
   value", labels are neutral.
   Material: glass only on the nav, the pop-up and the contact card. */

/* ------------------------------------------------------------ headings */
.hero h1 {
  font-family: var(--sans); font-weight: 650; font-variation-settings: normal;
  font-size: var(--t-3xl); letter-spacing: -.04em; line-height: .96;
}
.hero-hello {
  font-family: var(--sans); font-style: normal; font-weight: 450; font-variation-settings: normal;
  font-size: var(--t-l); color: var(--fg-2); letter-spacing: -.01em;
}
.sec-head h2, .case-head h1, .case-miss h1, .contact-h {
  font-family: var(--sans); font-weight: 620; letter-spacing: -.03em; line-height: 1.05;
}
.sec-head h2 { font-size: var(--t-2xl); margin-top: 0; }
.case-head h1 { font-size: clamp(32px, 4.4vw, 54px); }
.contact-h { font-size: clamp(30px, 4vw, 48px); }
.approach .sec-head h2 {
  font-style: normal; font-weight: 560; font-size: clamp(23px, 2.5vw, 31px);
  line-height: 1.25; letter-spacing: -.02em; max-width: 26ch;
}
.prow-title, .pop-title, .event-title, .band-title, .mini-title {
  font-family: var(--sans); font-weight: 600; letter-spacing: -.02em; line-height: 1.15;
}
.prow-title { font-size: var(--t-xl); }
.pop-title { font-size: clamp(24px, 2.6vw, 30px); }
.event-title, .band-title { font-size: var(--t-xl); }
.case-nav-t { font-family: var(--sans); font-weight: 600; font-size: var(--t-m); letter-spacing: -.01em; }
.about-lede {
  font-family: var(--sans); font-weight: 400; font-size: var(--t-l);
  line-height: 1.5; letter-spacing: -.01em; max-width: 52ch;
}

/* --------------------------------------------------------- type scale ----
   The small sizes that had drifted (11.5, 12.5, 13, 13.3, 14, 14.5 …) are
   pulled onto the scale. */
.eyebrow, .rd-k, .stat-k, .ev-label, .proj-domain, .finding-k, .case-grid h2, .shots-h,
.col h3, .sk-g, .case-nav-k, .case-facts h2, .case-facts dt, .mini-kind, .proj-year,
.exp-dates, .tag, .fold-btn, .back, .nav-here { font-size: var(--t-xs); }
.proj-cap, .shot figcaption, .moment figcaption, .note, .exp-tag, .edu-m, .edu-c, .edu-p-top,
.edu-p-sub, .contact-note, .mini-detail, .mini-link, .footer-in, .moments-stats, .hero-glance,
.ev-from, .prow-go, .row-tags i, .lead li, .sk-i, .nav-links a { font-size: var(--t-s); }
.ev-find, .exp-pts li, .event-sum, .case-grid p, .band-sub, .prow-sub, .hero-role, .sec-lede,
.btn, .pop-sub, .finding p, .contact-p, .edu-deg, .exp-org { font-size: var(--t-b); }
.hero-tagline, .case-sub, .exp-role { font-size: var(--t-m); }

/* ---------------------------------------------------------------- hero */
.hero-tagline { font-weight: 450; letter-spacing: -.01em; max-width: 36ch; }
.hero-role { margin-top: var(--s2); color: var(--fg-2); font-weight: 400; max-width: 46ch; line-height: 1.55; }
.hero-cta { margin-top: var(--s4); }
.hero-glance { margin-top: var(--s3); color: var(--fg-3); max-width: none; }
.hero-glance span + span::before { content: none; }

/* stats: a row of figures, not four boxes */
.stats { gap: 0; }
.stat, .hero .stat {
  background: none; border: 0; box-shadow: none; border-radius: 0;
  -webkit-backdrop-filter: none; backdrop-filter: none;
  padding: 4px 0 4px clamp(14px, 2vw, 24px); border-left: 1px solid var(--hair-2);
}
.stat::before, .stat::after { content: none; }
.stat:hover { transform: none; }
.stat-v { color: var(--cyan-hi); font-size: clamp(26px, 3vw, 36px); letter-spacing: -.03em; }
.stat-k { color: var(--fg-3); margin-top: 8px; }
@media (max-width: 620px) {
  .stats { grid-template-columns: 1fr 1fr; gap: var(--s3) 0; }
}

/* ------------------------------------------------------------- colour --
   Gold for actions, cyan for measured values, neutral for labels. */
.proj-domain, .finding-k, .ev-label, .col h3, .case-facts h2, .case-facts dt, .shots-h, .mini-kind,
.section .eyebrow, .case-grid h2 { color: var(--fg-3); }
.exp-dates, .ev-metric, .rd-v, .edu-p-top .mono { color: var(--cyan-hi); }
:root[data-theme="light"] .exp-dates, :root[data-theme="light"] .ev-metric,
:root[data-theme="light"] .stat-v, :root[data-theme="light"] .rd-v { color: var(--cyan); }

/* numbering: project numbers carry no information on the home page */
.nav-links a em, .nav-here em, .prow .proj-num, .pop .proj-num { display: none; }

/* the status light is steady: nothing here is live */
.nav-led { animation: none; }

/* tags read as a list, with commas instead of a dot before each */
.row-tags { margin-left: 0; clip-path: none; gap: 0; }
.row-tags i { margin-left: 0; position: static; }
.row-tags i::before { content: none; }
.row-tags i:not(:last-child)::after { content: ','; margin-right: .35em; }

/* ---------------------------------------------------------- materials --
   Panels are solid with a fine edge. Live glass stays on the nav, the
   project pop-up and the contact card. */
.ev, .col, .moment, .mini, .case-facts, .readout.glass, .shot {
  -webkit-backdrop-filter: none; backdrop-filter: none;
  background: var(--panel-bg);
  border: 1px solid var(--glass-edge);
  box-shadow: var(--glass-spec), var(--shadow-md);
}
.ev::before { content: none; }

/* -------------------------------------------------------------- layout */
/* findings: the first one leads across the full width, figure on the
   left and the explanation beside it; the other two sit underneath */
@media (min-width: 990px) {
  .evidence { grid-template-columns: 1fr 1fr; }
  .evidence > .ev:first-child {
    grid-column: 1 / -1; display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
    grid-template-rows: auto auto 1fr; column-gap: clamp(28px, 4vw, 64px); align-items: start;
    padding: clamp(30px, 3.4vw, 44px);
  }
  .evidence > .ev:first-child .ev-metric { font-size: clamp(48px, 5.6vw, 76px); grid-column: 1; grid-row: 1; }
  .evidence > .ev:first-child .ev-label { grid-column: 1; grid-row: 2; }
  .evidence > .ev:first-child .ev-find { grid-column: 2; grid-row: 1 / span 2; margin: 0; align-self: center; }
  .evidence > .ev:first-child .ev-from { grid-column: 2; grid-row: 3; margin-top: var(--s2); }
  .evidence > .ev:not(:first-child) .ev-metric { font-size: clamp(26px, 2.6vw, 34px); }
}
/* About: the education column is the widest; the three cards share one
   height (the tallest), so the row reads as a set */
@media (min-width: 621px) {
  .cols { grid-template-columns: 1.25fr 1fr 1fr; align-items: stretch; }
}
.col h3 {
  font-family: var(--sans); font-weight: 500; letter-spacing: var(--label-track);
  text-transform: uppercase; margin-bottom: 18px;
}

/* phone About tabs: the buttons inherit the page font */
.about-tabs [role="tab"] { font-family: inherit; font-size: var(--t-s); }


/* --------------------------------------------- fixes from the render pass */
/* the facts line under the stats is plain text now: no dot-clipping strip */
.hero-glance { display: block; margin-left: 0; clip-path: none; }
/* the lead finding centres its content instead of pinning the link low */
/* the feedback summary is a sentence, not a readout */
.moments-stats { font-family: var(--sans); letter-spacing: 0; color: var(--fg-2); }
/* labels are neutral everywhere; gold is kept for things you can act on */
.eyebrow, .section .eyebrow { color: var(--fg-3); }
/* section numbers in the phone nav chip go with the rest of the numbering */
.nav-here b { display: none; }

/* phones: the About intro steps down a size */
@media (max-width: 620px) { .about-lede { font-size: var(--t-m); } }
.nowrap { white-space: nowrap; }


/* -------------------------------------------------- scale and radius ----
   Strays the canon audit (2026-10-03) found, pulled onto the scales. */
.nav-name i, .nav-status .t, .nav-cta, .foot-hint, .event-role, .tag, .case-facts .tag { font-size: var(--t-xs); }
.nav-name i { letter-spacing: .1em; }
.nav-name b, .rd-v { font-size: var(--t-s); }
.mini-title { font-size: var(--t-b); }
.approach .sec-head h2 { font-size: clamp(21px, 2.2vw, 26px); }
.stat-v, .evidence > .ev:not(:first-child) .ev-metric { font-size: clamp(26px, 2.6vw, 34px); }
.contact-h { font-size: var(--t-2xl); }
.case-head h1 { font-size: clamp(32px, 4.4vw, 54px); }
@media (min-width: 990px) { .evidence > .ev:first-child .ev-metric { font-size: var(--t-3xl); } }
/* radius: outer surfaces use the tokens; an image inset in a padded card
   takes the card radius minus its padding (a derived value, not a step) */
.portrait { border-radius: var(--r-m); }

/* ------------------------------------------------- audit fixes (Phase 2) */
/* case-page labels are h2 now (heading order); keep the label look */
.case-grid h2, .case-facts h2, .shots-h { line-height: 1.4; }
/* the logo never squeezes in a crowded phone nav */
.nav-mark { flex: none; }
.nav-logo { flex-shrink: 0; }

/* ------------------------------------------- circuit view toggle (nav) --
   Same look as the theme button beside it; 44px target. The layer itself
   is styled in css/circuit.css, loaded with js/circuit.js on first use. */
.circuit-btn {
  position: relative; display: inline-grid; place-items: center; flex: none;
  width: 32px; height: 32px; border-radius: var(--r-s); cursor: pointer;
  color: var(--fg-2); background: rgba(var(--gold-rgb), .05);
  border: 1px solid var(--hair-2);
  transition: color .3s var(--ease), border-color .3s var(--ease);
}
.circuit-btn::before { content: ''; position: absolute; inset: -6px; }
.circuit-btn:hover, .circuit-btn[aria-pressed="true"] { color: var(--gold-hi); border-color: rgba(var(--gold-rgb), .5); }
.circuit-btn svg { width: 16px; height: 16px; }
.circuit-btn:active { transform: translateY(1px); }
.foot-hint.wdt { color: var(--fg-2); }
/* scope game canvas inside the console (js/console-extra.js) */
.fx-scope { display: block; margin: 8px 0; border: 1px solid var(--hair-2); border-radius: 8px; background: var(--ink); }

/* ============================================================ refinement v3 ===
   Apple-style pass (2026-10-04): a three-tier material, a calmer type
   hierarchy, consistent interaction states. Overrides what comes before;
   delete this block to go back to v2.

   MATERIAL TIERS
     clear    floating controls: nav, back-to-top, toast, "Show all", the
              hero readout. Light tint, small blur, a lit top edge.
     regular  focal surfaces: the project pop-up, the contact card, the
              console. Denser tint, bigger blur, a gradient rim.
     solid    everything that repeats or carries reading (cards, columns):
              the panel, no blur.
   The rim is a 1px gradient drawn in a ::after with a mask, so the edge
   catches light at the top left instead of being one flat line.
   At the lite graphics level there is no live blur except the nav (the
   rules under "graphics: lite" above still apply). */

:root {
  --mat-clear-fill: linear-gradient(180deg, rgba(255,255,255,.085), rgba(255,255,255,.015) 48%, rgba(255,255,255,.03)), rgba(9,17,30,.46);
  --mat-clear-filter: blur(18px) saturate(160%);
  --mat-regular-fill: linear-gradient(180deg, rgba(255,255,255,.08), rgba(255,255,255,0) 42%), rgba(11,20,35,.68);
  --mat-regular-filter: blur(26px) saturate(180%);
  --mat-rim: linear-gradient(160deg, rgba(255,255,255,.34), rgba(255,255,255,.08) 26%, rgba(255,255,255,.025) 60%, rgba(255,255,255,.12));
  --mat-inner: inset 0 1px 0 rgba(255,255,255,.1);
  --mat-shadow-clear: 0 12px 32px -12px rgba(0,0,0,.5), 0 2px 6px rgba(0,0,0,.16);
  --mat-shadow-regular: 0 34px 80px -28px rgba(0,0,0,.62), 0 4px 14px rgba(0,0,0,.2);
  --ease-ui: cubic-bezier(.2, .8, .2, 1);
  --t-b: 16.5px;
  --t-m: 18.5px;
}
:root[data-theme="light"] {
  --mat-clear-fill: linear-gradient(180deg, rgba(255,255,255,.86), rgba(255,255,255,.45) 50%, rgba(255,255,255,.58)), rgba(251,248,242,.6);
  --mat-regular-fill: linear-gradient(180deg, rgba(255,255,255,.9), rgba(255,255,255,.5) 46%), rgba(251,248,242,.84);
  --mat-rim: linear-gradient(160deg, rgba(255,255,255,1), rgba(255,255,255,.7) 28%, rgba(131,95,20,.14) 66%, rgba(255,255,255,.85));
  --mat-inner: inset 0 1px 0 rgba(255,255,255,.95);
  --mat-shadow-clear: 0 14px 30px -14px rgba(70,50,20,.26), 0 1px 3px rgba(70,50,20,.08);
  --mat-shadow-regular: 0 34px 70px -28px rgba(70,50,20,.32), 0 2px 8px rgba(70,50,20,.07);
}
@media (max-width: 620px) { :root { --t-b: 16px; --t-m: 17.5px; } }

/* ---------------------------------------------------------- the tiers */
.fx-top, .fx-toast, .hero .stats, .plist-toggle .btn {
  background: var(--mat-clear-fill);
  -webkit-backdrop-filter: var(--mat-clear-filter); backdrop-filter: var(--mat-clear-filter);
  border-color: transparent;
  box-shadow: var(--mat-inner), var(--mat-shadow-clear);
}
.contact > .wrap, .fx-uart {
  background: var(--mat-regular-fill);
  -webkit-backdrop-filter: var(--mat-regular-filter); backdrop-filter: var(--mat-regular-filter);
  border-color: transparent;
  box-shadow: var(--mat-inner), var(--mat-shadow-regular);
}
dialog.pop {
  box-shadow: inset 1px 1px 0 rgba(255,255,255,.16), inset 0 0 0 1px rgba(255,255,255,.06), var(--mat-shadow-regular);
}
:root[data-theme="light"] dialog.pop { box-shadow: inset 1px 1px 0 rgba(255,255,255,.9), inset 0 0 0 1px rgba(14,23,38,.06), var(--mat-shadow-regular); }
.nav-inner.glass { box-shadow: var(--mat-inner), var(--mat-shadow-clear); }

/* the lit rim */
.nav-inner.glass::after, .contact > .wrap::after, .fx-top::after, .fx-toast::after,
.hero .stats::after, .plist-toggle .btn::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none;
  background: var(--mat-rim);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
}
.nav-inner.glass, .contact > .wrap, .hero .stats, .plist-toggle .btn { position: relative; }
.nav-inner.glass { border-color: transparent; }

@media (prefers-reduced-transparency: reduce) {
  .hero .stats, .plist-toggle .btn, .fx-uart { -webkit-backdrop-filter: none !important; backdrop-filter: none !important; background: var(--ink-3) !important; }
}
@media (prefers-contrast: more) {
  .nav-inner.glass, .contact > .wrap, .hero .stats, .fx-top, .fx-toast, .plist-toggle .btn, dialog.pop {
    -webkit-backdrop-filter: none !important; backdrop-filter: none !important; background: var(--ink-2) !important;
    border: 1px solid var(--fg-2) !important;
  }
}

/* --------------------------------------------------------- typography
   Tracking by size: tighter as it grows, neutral at body size. */
body { font-size: var(--t-b); line-height: 1.6; }
.hero h1 { letter-spacing: -.045em; line-height: .98; }
.sec-head h2, .contact-h, .case-head h1 { letter-spacing: -.03em; line-height: 1.06; }
.prow-title, .pop-title, .exp-role, .event-title, .band-title, .mini-title, .case-nav-t { letter-spacing: -.018em; }
.prow-sub, .ev-find, .exp-pts li, .event-sum, .case-grid p, .sec-lede, .pop-sub, .contact-p, .about-lede { line-height: 1.6; }
.prow-sub, .exp-pts li, .case-grid p, .sec-lede { max-width: 62ch; }
.hero-tagline { font-size: clamp(18.5px, 2vw, 22px); line-height: 1.45; letter-spacing: -.012em; }
.hero-role { font-weight: 400; line-height: 1.6; }

/* Labels: quiet sentence-case sans instead of letter-spaced mono capitals.
   Mono stays for figures, dates and part numbers. */
.proj-domain, .ev-label, .col h3, .sk-g, .case-facts h2, .case-facts dt, .case-grid h2, .shots-h,
.rd-k, .mini-kind, .finding-k, .section .eyebrow, .case-nav-k, .exp-tag {
  font-family: var(--sans); text-transform: none; letter-spacing: 0;
  font-size: var(--t-s); font-weight: 500; line-height: 1.4; color: var(--fg-3);
}
.ev-label::first-letter { text-transform: uppercase; }
.col h3 { font-size: var(--t-m); font-weight: 600; letter-spacing: -.01em; color: var(--fg); margin-bottom: var(--s2); }
.sk-g { color: var(--fg-2); font-weight: 600; }
.stat-k { text-transform: none; letter-spacing: 0; font-family: var(--sans); font-size: var(--t-s); color: var(--fg-3); }
.proj-year, .exp-dates, .mini-year { letter-spacing: .02em; }
.nav-name i { letter-spacing: .06em; }
.fold-btn { letter-spacing: .02em; }

/* -------------------------------------------------------------- hero */
@media (min-width: 881px) {
  .hero-wrap { grid-template-columns: minmax(0, 1.18fr) minmax(0, .82fr); }
}
.hero .portrait { border-radius: var(--r-l); }
.hero-cta { gap: 12px; }
.hero-cta .btn { min-height: 48px; padding: 0 24px; font-size: 15px; }
/* the figures sit in one clear readout under the copy */
.hero .stats {
  margin-top: clamp(28px, 4vw, 48px); padding: clamp(14px, 2vw, 20px) clamp(8px, 1.6vw, 16px);
  border-radius: var(--r-m);
}
.hero .stat { padding-top: 2px; padding-bottom: 2px; }
.hero .stat:first-child { border-left: 0; }
.hero-glance { margin-top: var(--s3); }

/* ----------------------------------------------------------- buttons */
.btn {
  font-size: 15px; letter-spacing: 0; font-weight: 500; border-radius: var(--r-s);
  transition: background .2s var(--ease-ui), border-color .2s var(--ease-ui), transform .2s var(--ease-ui), box-shadow .2s var(--ease-ui);
}
.btn-primary {
  color: var(--ink); background: var(--gold); border-color: var(--gold);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.28), 0 6px 18px -10px rgba(var(--gold-rgb), .7);
}
.btn-primary:hover { background: var(--gold-hi); border-color: var(--gold-hi); }
:root[data-theme="light"] .btn-primary { color: #FFFDF7; }
.btn:not(.btn-primary) { background: rgba(255,255,255,.045); border-color: var(--hair-2); }
.btn:not(.btn-primary):hover { background: rgba(255,255,255,.085); border-color: rgba(var(--gold-rgb), .45); }
:root[data-theme="light"] .btn:not(.btn-primary) { background: rgba(255,255,255,.55); }
@media (hover: hover) and (pointer: fine) { .btn:hover { transform: translateY(-1px); } }
.btn:active, .nav-cta:active, .theme-btn:active, .circuit-btn:active, .prow:active, .fold-btn:active, .fx-top:active {
  transform: scale(.97); transition-duration: .1s;
}
.btn:focus-visible, .prow:focus-visible, .fold-btn:focus-visible { outline: 2px solid var(--gold-hi); outline-offset: 3px; }
/* "Show all" is a glass control, not a gold pill */
.plist-toggle { margin-top: var(--s4); }
.plist-toggle .btn, :root[data-theme] .plist-toggle .btn.btn-primary { min-width: 220px; min-height: 48px; color: var(--fg); }
.plist-toggle .btn:hover, :root[data-theme] .plist-toggle .btn.btn-primary:hover { color: var(--gold-hi); background: var(--mat-clear-fill); border-color: transparent; }

/* ------------------------------------------------------ project rows */
.prow { padding: 14px; gap: clamp(20px, 3.4vw, 44px); transition: transform .25s var(--ease-ui), border-color .25s var(--ease-ui), box-shadow .25s var(--ease-ui), opacity .6s var(--ease-out); }
.prow-body { gap: 10px; }
.prow-title { font-size: clamp(24px, 2.6vw, 30px); font-weight: 620; }
.prow .band-top { display: flex; align-items: baseline; gap: 10px; }
.prow-go {
  align-self: flex-start; min-height: 40px; padding: 0 14px; margin-top: 8px;
  border-radius: 999px; border: 1px solid rgba(var(--gold-rgb), .4); font-weight: 500;
  transition: background .2s var(--ease-ui), border-color .2s var(--ease-ui);
}
.prow:hover .prow-go { background: rgba(var(--gold-rgb), .1); border-color: rgba(var(--gold-rgb), .7); }
.rv.in.prow:hover, .prow:not(.rv):hover { transform: translateY(-2px); }
@media (hover: none) { .rv.in.prow:hover, .prow:not(.rv):hover { transform: none; } }

/* -------------------------------------------------------- experience */
@media (min-width: 621px) {
  .exp { grid-template-columns: 172px minmax(0, 1fr); gap: clamp(20px, 3vw, 40px); }
}
.exp-role { font-size: var(--t-l); font-weight: 600; }
.exp-org { color: var(--fg-2); margin-top: 2px; }
.exp-tag { margin-top: 8px; }
.fold-btn { min-height: 40px; }

/* ------------------------------------------------------------- about */
.col { padding: clamp(20px, 2.4vw, 28px); }
.sk + .sk { margin-top: 14px; }
.sk-i { font-size: var(--t-s); line-height: 1.55; color: var(--fg-2); }

/* ----------------------------------------------------------- contact */
.contact-links .btn { min-height: 48px; }

/* ------------------------------------------------------------ footer */
.footer { border-top: 0; }
.footer-in { color: var(--fg-3); }

/* ------------------------------------------------------- fold controls */
.fold-btn, .fold-btn .t {
  font-family: var(--sans); text-transform: none; letter-spacing: 0;
  font-size: var(--t-s); font-weight: 500;
}
@media (max-width: 620px) {
  .hero .stat:nth-child(odd) { border-left: 0; padding-left: 4px; }
}

/* the contact card's light: one soft warm source at the top, not a blob */
.contact > .wrap::before {
  top: -55%; width: 64%;
  background: radial-gradient(closest-side, rgba(var(--gold-rgb), .11), rgba(var(--gold-rgb), .04) 55%, transparent);
}

/* ------------------------------------------------------------ motion
   Short, interruptible, transform and opacity only. (Reveals: v4 below.) */
.fx-top { transform: translateY(8px) scale(.94); transition: opacity .25s var(--ease-ui), transform .25s var(--ease-ui); }
.fx-top.show { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .btn, .prow, .fx-top { transition: none; }
  .btn:active, .prow:active, .fx-top:active { transform: none; }
}

/* ============================================================ refinement v4 ===
   Round two (2026-10-04), from the owner's review of old against new:
   - the contact card and the hero figures wear the nav bar's glass (tinted
     backing, top highlight, lit rim, and the refraction lens from
     js/glass.js on desktop Chromium), on every graphics level
   - the figures are four cards again, with gold numbers and the tilt
   - repeated cards take the contact card's look: a translucent gradient,
     a lit rim, a faint warm light at the top, a deep soft shadow
   - the page assembles itself on load, and sections rise in as you scroll
   Delete this block to go back to v3. */

:root {
  --navglass-fill: linear-gradient(180deg, rgba(255,255,255,.08), rgba(255,255,255,0) 40%), rgba(8,14,24,.58);
  --navglass-filter: blur(22px) saturate(170%);
  --card-fill:
    radial-gradient(120% 80% at 50% -20%, rgba(var(--gold-rgb), .075), transparent 55%),
    linear-gradient(180deg, rgba(255,255,255,.055), rgba(255,255,255,0) 38%),
    linear-gradient(150deg, rgba(20,33,54,.72), rgba(8,15,28,.84));
  --card-shadow: var(--mat-inner), 0 26px 60px -30px rgba(0,0,0,.65), 0 2px 8px rgba(0,0,0,.16);
  --card-radius: 22px;
  --ease-appear: cubic-bezier(.16, 1, .3, 1);
}
:root[data-theme="light"] {
  --navglass-fill: linear-gradient(180deg, rgba(255,255,255,.82), rgba(255,255,255,.2) 45%), rgba(251,248,242,.74);
  --card-fill:
    radial-gradient(120% 80% at 50% -20%, rgba(var(--gold-rgb), .06), transparent 55%),
    linear-gradient(180deg, rgba(255,255,255,.96), rgba(255,255,255,.72) 45%),
    linear-gradient(150deg, rgba(255,255,255,.9), rgba(250,246,238,.92));
  --card-shadow: var(--mat-inner), 0 1px 2px rgba(70,50,20,.06), 0 22px 46px -26px rgba(70,50,20,.32);
}

/* ------------------------------------------------- nav-bar glass, A ---
   The blur applies where the lens is not running (other browsers, touch,
   or before js/glass.js has measured); a lensed surface keeps its inline
   url() filter and only takes the tinted backing. */
.hero .stat:not(.lg-on), .contact > .wrap:not(.lg-on) {
  background: var(--navglass-fill) !important;
  -webkit-backdrop-filter: var(--navglass-filter) !important; backdrop-filter: var(--navglass-filter) !important;
}
.lg-refract .hero .stat.lg-on, .lg-refract .contact > .wrap.lg-on { background: var(--navglass-fill) !important; }
.contact > .wrap { box-shadow: var(--mat-inner), var(--mat-shadow-regular); }

/* ------------------------------------------------ the figures, B --- */
.hero .stats {
  background: none !important; -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
  box-shadow: none; padding: 0; border-radius: 0; gap: clamp(10px, 1.6vw, 16px);
}
.hero .stats::after { content: none; }
.hero .stat, .hero .stat:first-child {
  position: relative; border-radius: var(--r-m); border: 1px solid transparent;
  padding: clamp(16px, 2.2vw, 22px) clamp(16px, 2vw, 22px);
  box-shadow: var(--mat-inner), var(--mat-shadow-clear);
}
@media (max-width: 620px) { .hero .stat:nth-child(odd) { border-left: 1px solid transparent; padding-left: 16px; } }
.hero .stat-v { color: var(--gold-hi); }
:root[data-theme="light"] .hero .stat-v { color: var(--gold); }

/* ---------------------------------------------- the card look, D --- */
:root .prow, :root .ev, :root .col, :root .moment, :root .mini, :root .case-facts, :root .event {
  position: relative; border-radius: var(--card-radius); border-color: transparent;
  background: var(--card-fill); box-shadow: var(--card-shadow);
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
.prow { padding: 12px; }
.prow-fig { border-radius: 10px; }

/* one lit rim for every glass and card surface (masked ::after) */
.hero .stat::after, .prow::after, .ev::after, .col::after, .moment::after, .mini::after, .case-facts::after, .event::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none;
  background: var(--mat-rim);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  transition: opacity .25s var(--ease-ui);
}
/* on hover the rim warms to gold: the card is something you can open */
.prow::before {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none;
  background: linear-gradient(160deg, rgba(var(--gold-rgb), .75), rgba(var(--gold-rgb), .18) 40%, rgba(var(--gold-rgb), .08) 70%, rgba(var(--gold-rgb), .4));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: 0; transition: opacity .25s var(--ease-ui);
}
.prow:hover::before { opacity: 1; }
.prow:hover::after { opacity: 0; }

/* --------------------------------------------------- motion, F ---
   Load: the hero assembles out of the air: each piece rises a little,
   comes into focus and fades in, one after another (a one-time blur on a
   handful of elements, before anything scrolls).
   Scroll: cards and section heads rise 28px and settle on an expo-out
   curve; what arrives together is staggered by js (70ms apart). */
@keyframes v4Appear {
  from { opacity: 0; transform: translateY(14px); filter: blur(6px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes v4AppearImg {
  from { opacity: 0; transform: scale(.97); filter: blur(8px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}
.hero-text > *, .hero .stats .stat, .case-head > * { animation: v4Appear .7s var(--ease-appear) backwards; }
.hero .portrait, .cg { animation: v4AppearImg .9s var(--ease-appear) .12s backwards; }
.hero-hello   { animation-delay: calc(var(--boot-d, 0s) + .04s); }
.hero h1      { animation-delay: calc(var(--boot-d, 0s) + .10s); }
.hero-tagline { animation-delay: calc(var(--boot-d, 0s) + .20s); }
.hero-role    { animation-delay: calc(var(--boot-d, 0s) + .27s); }
.hero .lanes  { animation-delay: calc(var(--boot-d, 0s) + .31s); }
.hero-cta     { animation-delay: calc(var(--boot-d, 0s) + .34s); }
.hero-glance  { animation-delay: calc(var(--boot-d, 0s) + .42s); }
.hero .stats .stat:nth-child(1) { animation-delay: calc(var(--boot-d, 0s) + .38s); }
.hero .stats .stat:nth-child(2) { animation-delay: calc(var(--boot-d, 0s) + .43s); }
.hero .stats .stat:nth-child(3) { animation-delay: calc(var(--boot-d, 0s) + .48s); }
.hero .stats .stat:nth-child(4) { animation-delay: calc(var(--boot-d, 0s) + .53s); }
.case-head > :nth-child(1) { animation-delay: calc(var(--boot-d, 0s) + .03s); }
.case-head > :nth-child(2) { animation-delay: calc(var(--boot-d, 0s) + .08s); }
.case-head > :nth-child(3) { animation-delay: calc(var(--boot-d, 0s) + .13s); }
.case-head > :nth-child(4) { animation-delay: calc(var(--boot-d, 0s) + .18s); }
.case-head > :nth-child(5) { animation-delay: calc(var(--boot-d, 0s) + .23s); }
.case-head > :nth-child(n+6) { animation-delay: calc(var(--boot-d, 0s) + .28s); }
.cg, .hero .portrait { animation-delay: calc(var(--boot-d, 0s) + .2s); }

.rv {
  opacity: 0; transform: translateY(16px);
  transition: opacity .55s var(--ease-appear), transform .6s var(--ease-appear);
}
.rv.in { opacity: 1; transform: none; }

/* reduced transparency and contrast still win over the glass above */
@media (prefers-reduced-transparency: reduce) {
  .hero .stat, .contact > .wrap { -webkit-backdrop-filter: none !important; backdrop-filter: none !important; background: var(--ink-3) !important; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-text > *, .hero .stats .stat, .case-head > *, .hero .portrait, .cg { animation: v4Fade .3s linear backwards; }
  .rv { transform: none; transition: opacity .3s linear; }
  .prow::before, .prow::after { transition: none; }
}
@keyframes v4Fade { from { opacity: 0; } to { opacity: 1; } }


/* the role tags (experience, beyond) read at --fg-2: --fg-3 fell under AA on the card fill */
.exp-tag { color: var(--fg-2); }

/* ============================================================ A0 fixes ===
   From the 2026-10-04 bug hunt. Delete this block to undo the CSS half. */

/* F1, F2: the console is a terminal: dark and near-solid in both themes and
   at every level, so its pale text always reads (it used the regular glass,
   which is cream in light theme and see-through in lite) */
.fx-uart, :root[data-theme="light"] .fx-uart {
  background: linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,0) 42%), rgba(5, 10, 18, .94);
}
@media (prefers-reduced-transparency: reduce) {
  .fx-uart { background: #050A12 !important; }
}

/* F8: the silkscreen designators (console open) share ::after with the
   cards' lit rim; undo the rim's inset and mask so the label shows as a
   small tag instead of an offset gold frame */
html.silk [data-ref]::after {
  inset: auto; top: -9px; left: 14px; right: auto; bottom: auto;
  -webkit-mask: none; mask: none; opacity: 1; z-index: 5;
}

/* F4: 44px touch targets without changing how the controls look
   (an invisible hit area around the visible control) */
.fold-btn, .ev-from, .fx-uart-x { position: relative; }
.fold-btn::before { content: ''; position: absolute; inset: -2px -4px; }
.ev-from::before { content: ''; position: absolute; inset: -4px -2px; }
.fx-uart-x::before { content: ''; position: absolute; inset: -6px; }
/* the nav's circuit and theme buttons are 32px with a 1px border: -7px makes 44 */
.circuit-btn::before, .theme-btn::before { inset: -7px; }
@media (max-width: 620px) {
  .about-tabs [role="tab"] { min-height: 44px; }
}
@media (max-width: 880px) {
  .nav-links a, .nav-links .nav-status { position: relative; }
  .nav-links a::before { content: ''; position: absolute; inset: -5px 0; }
  .nav-links .nav-status::before { content: ''; position: absolute; inset: -12.5px 0; }
}

/* ======================================================= eggs and VGA ===
   The "n of N secrets found" chip (js/eggs.js) and the footer's VGA port
   (js/fx.js): the page's output connector, which plugs into the board view. */
.egg-chip {
  position: fixed; left: 50%; bottom: clamp(14px, 3vw, 24px); z-index: 130;
  padding: 8px 14px; border-radius: 999px; font-size: 12px; letter-spacing: .04em;
  color: var(--fg-2); background: var(--panel-bg); box-shadow: var(--mat-inner), var(--mat-shadow-clear);
  opacity: 0; transform: translate(-50%, 8px); pointer-events: none;
  transition: opacity .3s var(--ease-ui), transform .3s var(--ease-ui);
}
.egg-chip.show { opacity: 1; transform: translate(-50%, 0); }
.vga-row { flex-basis: 100%; display: flex; justify-content: center; margin-top: 10px; }
.vga-port {
  display: inline-flex; align-items: center; gap: 10px; min-height: 44px; padding: 4px 14px 4px 8px;
  font-size: 12px; letter-spacing: .06em; color: var(--fg-3);
  background: none; border: 1px solid var(--hair-2); border-radius: var(--r-s); cursor: pointer;
  transition: color .2s var(--ease-ui), border-color .2s var(--ease-ui);
}
.vga-port:hover, .vga-port:focus-visible { color: var(--gold-hi); border-color: rgba(var(--gold-rgb), .55); }
.vga-port svg { width: 86px; height: 26px; overflow: visible; }
.vga-port .vga-shell { fill: var(--ink-2); stroke: rgba(var(--gold-rgb), .7); stroke-width: 1.4; stroke-linejoin: round; }
.vga-port circle { fill: rgba(var(--gold-rgb), .8); }
.vga-port .vga-body { fill: var(--fg-3); stroke: rgba(var(--gold-rgb), .5); stroke-width: 1; stroke-linejoin: round; }
.vga-port .vga-cable { fill: none; stroke: var(--fg-3); stroke-width: 3.4; stroke-linecap: round; }
.vga-port .vga-screw { fill: var(--ink-2); }
.vga-port .vga-plug { transform: translateX(10px); transition: transform .34s var(--ease-appear); }
.vga-port:hover .vga-plug { transform: translateX(6px); }
.vga-port.plugged .vga-plug { transform: translateX(-8px); }
.vga-port.plugged .vga-body { fill: var(--gold); }
@media (prefers-reduced-motion: reduce) { .egg-chip, .vga-port .vga-plug { transition: none; } }
/* the end-of-page note sits at the top, clear of the footer and its port */
.fx-toast.at-top { top: 96px; bottom: auto; transform: translate(-50%, -16px); }
.fx-toast.at-top.show { transform: translate(-50%, 0); }
@media (max-width: 560px) {
  .fx-toast.at-top { top: calc(78px + env(safe-area-inset-top, 0px)); transform: translateY(-16px); }
  .fx-toast.at-top.show { transform: none; }
}

/* ------------------------------------------------- beyond: event cards ----
   An event is a card, but it took .exp's timeline padding (top and bottom
   only), so text and photos ran into the rounded edge. Its own padding, a
   steady gap between cards, and photo tiles that sit inside the card. */
:root .event { padding: clamp(18px, 2.6vw, 30px) clamp(16px, 2.6vw, 32px); }
.event + .event { border-top: 0; margin-top: clamp(14px, 2vw, 22px); }
.event .shot { border-radius: var(--r-s); }
/* every photo card on the page is the same size: equal widths in a centred
   wrap (an odd last photo sits centred under the pair above), and every
   caption holds exactly two lines (the full text is in the alt and the
   lightbox), so captions of any length give equal heights */
.event-photos { display: flex; flex-wrap: wrap; justify-content: center; align-items: stretch; gap: 18px; }
.event-photos .shot { flex: 0 1 calc(50% - 9px); min-width: 0; display: flex; flex-direction: column; }
.event-photos .shot figcaption { --cap-l: 2; line-height: 1.5; flex: 1 0 auto; }
.event-photos .cap-t {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: var(--cap-l); line-clamp: var(--cap-l);
  overflow: hidden; min-height: calc(var(--cap-l) * 1.5em);
}
/* narrower two-up tiles (tablets) give the captions a third line */
@media (min-width: 621px) and (max-width: 1100px) { .event-photos .shot figcaption { --cap-l: 3; } }
.event-links { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 18px; }
.event-links .event-link { margin-top: 0; }
@media (max-width: 620px) {
  .event-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px; margin-bottom: 4px; }
  .event-meta .exp-tag { margin-top: 0; }
  .event .exp-org { margin-top: 6px; }
  .event-sum { margin-top: 14px; }
  .event-photos { margin-top: 18px; gap: 12px; }
  .event-photos .shot { flex-basis: 100%; }
}

/* ==========================================================================
   MOTION v5 (2026-10-11): one motion language for the whole site.
   Durations and curves are tokens; everything below uses them. Native
   scroll stays native (no wheel smoothing): fluidity comes from immediate
   feedback, short ease-outs, and reveals that follow the reader.
   ========================================================================== */
:root {
  --d-instant: .12s;   /* press */
  --d-fast: .2s;       /* hover, toggles */
  --d-base: .32s;      /* UI state changes */
  --d-slow: .56s;      /* reveals, layout changes */
  --d-hero: .8s;       /* the first screen */
  --ease-io: cubic-bezier(.65, 0, .35, 1);        /* scroll-linked travel */
  --ease-sheet: cubic-bezier(.32, .72, 0, 1);     /* overlays, sheets */
  --ease-exit: cubic-bezier(.4, 0, 1, 1);         /* leaving */
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1); /* small physical things only */
}

/* ---- A. feedback: the press lands on pointer-down, the return is smooth */
.btn, .nav-cta, .theme-btn, .circuit-btn, .fold-btn, .fx-top, .mini-link, .about-tab, .wv-lab, .copy-btn {
  transition-timing-function: var(--ease-out);
}
.btn:active, .nav-cta:active, .theme-btn:active, .circuit-btn:active, .prow:active, .mini-link:active,
.fold-btn:active, .fx-top:active, .about-tab:active, .wv-lab:active, .copy-btn:active {
  transform: translateY(0) scale(.97); transition-duration: var(--d-instant);
}
/* nav links: the underline grows from the left with transform, not width */
.nav-links a { transition: color var(--d-fast) var(--ease-out); }
.nav-links a::after {
  width: 100%; transform: scaleX(0); transform-origin: left center;
  transition: transform var(--d-base) var(--ease-out), background-color var(--d-fast) var(--ease-out);
}
.nav-links a:hover::after, .nav-links a.on::after { width: 100%; transform: scaleX(1); }
/* the bar is always there; once the page scrolls it sits a little firmer */
.nav-inner.glass { transition: box-shadow var(--d-base) var(--ease-out); }
.nav.stuck .nav-inner.glass { box-shadow: var(--mat-inner), var(--mat-shadow-regular); }
/* links in running text: the underline settles in rather than snapping */
.case-grid a, .event-sum a, .exp-pts a, .contact-p a {
  text-decoration-color: rgba(var(--gold-rgb), .35); text-underline-offset: 3px;
  transition: text-decoration-color var(--d-fast) var(--ease-out), color var(--d-fast) var(--ease-out);
}
.case-grid a:hover, .event-sum a:hover, .exp-pts a:hover, .contact-p a:hover { text-decoration-color: var(--gold-hi); }
@media (prefers-reduced-motion: reduce) {
  .nav-links a::after { transition: opacity var(--d-fast) linear; transform: scaleX(1); opacity: 0; }
  .nav-links a:hover::after, .nav-links a.on::after { opacity: 1; }
}

/* ---- B. reveals: three kinds, chosen by what is arriving ----------------
   .rv           the default: rise 16px and settle (v4, above)
   .rv-line      a heading: its text rises out of a mask, like a line of
                 type sliding up into place (app.js / project.js wrap it)
   .rv-img       a picture: it opens out of a clip and settles from 1.04
   Things that arrive together are staggered 50ms, in reading order. */
.rv.rv-line { opacity: 1; transform: none; transition: none; }
.rv-line .ln { display: block; overflow: clip; padding-bottom: .1em; margin-bottom: -.1em; }
.rv-line .ln-i { display: block; }
.rv.rv-line .ln-i { transform: translateY(108%); transition: transform .7s var(--ease-out); }
.rv.rv-line.in .ln-i { transform: none; }
.rv.rv-img { opacity: 1; transform: none; clip-path: inset(6% 5% 6% 5% round 18px); transition: clip-path .8s var(--ease-out); }
.rv.rv-img.in { clip-path: inset(0 0 0 0 round 0); }
.rv.rv-img img { transform: scale(1.06); transition: transform 1s var(--ease-out); }
.rv.rv-img.in img { transform: none; }
img.rv.rv-img { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .rv.rv-line { opacity: 0; transition: opacity .3s linear; }
  .rv.rv-line.in { opacity: 1; }
  .rv.rv-line .ln-i, .rv.rv-img img { transform: none; transition: none; }
  .rv.rv-img { clip-path: none; opacity: 0; transition: opacity .3s linear; }
  .rv.rv-img.in { opacity: 1; }
}

/* ---- C. scroll-linked, only where the scroll position means something ---
   Native CSS scroll-driven animations (no JS, no loop; browsers without
   them simply show the finished state). */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* the hero hands over to the work: text and portrait lift away at
       slightly different speeds as the first screen leaves (desktop) */
    @media (min-width: 881px) {
      .hero { view-timeline: --hero block; }
      .hero .hero-text { animation: heroOutText linear both; animation-timeline: --hero; animation-range: exit 0% exit 100%; }
      .hero .portrait picture { display: block; animation: heroOutPic linear both; animation-timeline: --hero; animation-range: exit 0% exit 100%; }
      @keyframes heroOutText { to { transform: translateY(-36px); opacity: .25; } }
      @keyframes heroOutPic { to { transform: translateY(-64px) scale(.97); opacity: .4; } }
    }
    /* a case study's pictures settle as they come into view */
    .cg-frame img { animation: caseIn linear both; animation-timeline: view(); animation-range: entry 0% cover 40%; }
    @keyframes caseIn { from { transform: scale(1.04); } to { transform: none; } }
  }
}

/* list mode: a compact index with no pictures, like a datasheet table.
   Number, title, domain and year on one line; the one-line summary and the
   stack underneath. All ten show (the collapsed ones join in). */
.plist.is-list { border-top: 1px solid var(--hair); }
.plist.is-list .conn-wrap, .plist.is-list .plist-stack, .plist.is-list .plist-toggle,
.plist.is-list .prow-media, .plist.is-list .prow-go, .plist.is-list .band-top .via { display: none; }
.plist.is-list .plist-more, .plist.is-list .plist-more-clip { display: contents; }
.plist.is-list .plist-more-clip { visibility: visible; }
.plist.is-list .prow, .plist.is-list .prow.flip {
  display: block; padding: 18px 10px; border-radius: 0; border: 0; border-bottom: 1px solid var(--hair);
  background: none; box-shadow: none; transition: background-color var(--d-fast) var(--ease-out), transform var(--d-base) var(--ease-out);
}
.plist.is-list .prow::before, .plist.is-list .prow::after { display: none; }
.plist.is-list .prow-body {
  display: grid; padding: 0; gap: 4px 20px; align-items: baseline;
  grid-template-columns: 3em minmax(0, 1fr) minmax(0, 14em) 5.5em;
  grid-template-areas: "num title domain year" "num sub tags tags";
}
.plist.is-list .band-top { display: contents; }
.plist.is-list .proj-num { display: block; grid-area: num; font: 500 var(--t-s)/1.6 var(--mono); color: var(--fg-3); }
.plist.is-list .prow-title { grid-area: title; font-size: var(--t-m); line-height: 1.3; }
.plist.is-list .proj-domain { grid-area: domain; font-size: var(--t-s); color: var(--fg-2); }
.plist.is-list .proj-year { grid-area: year; justify-self: end; margin: 0; }
.plist.is-list .prow-sub { grid-area: sub; font-size: var(--t-s); max-width: 70ch; }
.plist.is-list .row-tags { grid-area: tags; margin: 0; font-size: var(--t-xs); color: var(--fg-3); }
.plist.is-list .prow:hover { background: rgba(255, 255, 255, .025); transform: translateX(4px); }
:root[data-theme="light"] .plist.is-list .prow:hover { background: rgba(0, 0, 0, .025); }
@media (max-width: 620px) {
  .plist.is-list .prow, .plist.is-list .prow.flip { padding: 16px 4px; }
  .plist.is-list .prow-body { grid-template-columns: 2.4em minmax(0, 1fr) auto; grid-template-areas: "num title year" "num domain domain" "num sub sub"; }
  .plist.is-list .row-tags { display: none; }
  .plist.is-list .prow:hover { transform: none; }
}
/* the morph between layouts (View Transitions): each tile glides to its new
   place and size; the rest of the page holds still */
html.vt-work::view-transition-group(*) { animation-duration: var(--d-slow); animation-timing-function: var(--ease-out); }
html.vt-work::view-transition-old(root), html.vt-work::view-transition-new(root) { animation: none; }

/* ---- E. formats ------------------------------------------------------ */
/* About, on phones: the tabs' highlight glides between tabs and the
   chosen column eases in instead of snapping */
@media (max-width: 620px) {
  .about-tabs { position: relative; }
  .about-tabs::before {
    content: ''; position: absolute; top: 4px; bottom: 4px; left: 4px;
    width: calc((100% - 8px - 8px) / 3); border-radius: 999px;
    background: rgba(var(--gold-rgb), .16); box-shadow: inset 0 0 0 1px rgba(var(--gold-rgb), .35);
    transform: translateX(calc(var(--tab, 0) * (100% + 4px))); transition: transform var(--d-base) var(--ease-sheet);
  }
  .about-tabs [role="tab"], .about-tabs [aria-selected="true"] { position: relative; background: none; box-shadow: none; }
  .cols > .col.on { animation: tabIn var(--d-base) var(--ease-out); }
}
@keyframes tabIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
/* Case pages: "On this page" inside the sticky facts card */
.case-toc { margin-bottom: 18px; padding-bottom: 16px; border-bottom: 1px solid var(--hair); }
.case-toc ol { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 2px; }
.case-toc a {
  display: flex; align-items: center; gap: 10px; min-height: 36px; padding: 0 8px; border-radius: 8px;
  font-size: var(--t-s); color: var(--fg-2); transition: color var(--d-fast) var(--ease-out), background-color var(--d-fast) var(--ease-out);
}
.case-toc a::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%; flex: none;
  border: 1px solid var(--trace); background: var(--copper);
  transition: background-color var(--d-fast) var(--ease-out), border-color var(--d-fast) var(--ease-out), transform var(--d-base) var(--ease-spring);
}
.case-toc a:hover { color: var(--fg); background: rgba(255, 255, 255, .03); }
.case-toc a.on { color: var(--gold-hi); }
.case-toc a.on::before { background: var(--gold-hi); border-color: var(--gold-hi); transform: scale(1.25); }
@media (max-width: 1023px) { .case-toc { display: none; } }
.case-grid section { scroll-margin-top: 110px; }
@media (prefers-reduced-motion: reduce) {
  .about-tabs::before { transition: none; }
  .cols > .col.on { animation: none; }
}

/* ---- F. overlays, theme, contact -------------------------------------- */
/* theme switch from a button: the new theme grows out of it as a circle */
html.vt-theme::view-transition-old(root), html.vt-theme::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
html.vt-theme::view-transition-new(root) { z-index: 2; }
/* copy email: an icon button beside the address; the icon turns to a tick */
.copy-btn { display: inline-flex; align-items: center; gap: 8px; }
.copy-btn svg { width: 16px; height: 16px; }
.copy-btn .i-ok { display: none; color: var(--gold-hi); }
.copy-btn.copied .i-copy { display: none; }
.copy-btn.copied .i-ok { display: block; animation: okPop var(--d-base) var(--ease-spring); }
@keyframes okPop { from { transform: scale(.4); opacity: 0; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .copy-btn.copied .i-ok { animation: none; } }

/* ---- the loader (first page of a visit) --------------------------------
   A chip powers up. The package fades in, its traces draw out to the edges
   of the screen, the die's floor plan lights block by block, then light
   races out along the traces (gold and cyan, the site's two colours) and a
   sheen crosses the lid. A bar fills under it; when the page is ready
   (fx.js adds .ready) it completes, the chip pushes forward and fades, and
   the screen lifts like a curtain. The traces start at about 1.45s, after
   the page's own first layout and scripts (up to ~1.4s on a desktop), so
   they don't stall. The head snippet adds html.booted after a click within
   the site or Back/Forward; a CSS fade clears it at 6s if fx.js never runs. */
@property --bt-pct { syntax: '<integer>'; inherits: true; initial-value: 0; }
.boot {
  position: fixed; inset: 0; z-index: 1000; overflow: hidden; background: #04080F;
  --bt-pct: 0; animation: btPct 3.7s cubic-bezier(.55, .05, .4, 1) .2s forwards, bootFailsafe .5s linear 6s forwards;
}
html.booted .boot { display: none; }
html:not(.booted) { --boot-d: 4.1s; }
@keyframes bootFailsafe { to { opacity: 0; visibility: hidden; } }
@keyframes btPct { to { --bt-pct: 90; } }
.boot.ready { animation: btPctDone .35s ease-out forwards, bootFailsafe .5s linear 6s forwards; --bt-pct: 90; }
@keyframes btPctDone { from { --bt-pct: 90; } to { --bt-pct: 100; } }
.boot-art { position: absolute; inset: 0; width: 100%; height: 100%; }
.boot-art .bt-glow { opacity: 0; animation: btFade 1.2s ease-out 2s forwards; }
.bt-tr { fill: none; stroke: rgba(201, 164, 92, .34); stroke-width: 1.4; stroke-dasharray: 1; stroke-dashoffset: 1; animation: btDraw .9s cubic-bezier(.65, 0, .35, 1) forwards; }
.bt-st { fill: none; stroke-width: 2.4; stroke-linecap: round; stroke-dasharray: .07 .93; stroke-dashoffset: .07; opacity: 0;
  animation-name: btRun; animation-timing-function: cubic-bezier(.5, 0, .3, 1); animation-iteration-count: infinite; animation-fill-mode: backwards; }
.bt-st.g { stroke: #F6D88E; }
.bt-st.c { stroke: #7FDCEB; }
@keyframes btDraw { to { stroke-dashoffset: 0; } }
@keyframes btRun { 0% { stroke-dashoffset: .07; opacity: 0; } 8% { opacity: 1; } 85% { opacity: .9; } 100% { stroke-dashoffset: -.95; opacity: 0; } }
@keyframes btFade { to { opacity: 1; } }
.bt-chip { opacity: 0; transform-box: fill-box; transform-origin: center; animation: btChip .7s cubic-bezier(.16, 1, .3, 1) .1s forwards; }
@keyframes btChip { from { opacity: 0; transform: scale(.96); } to { opacity: 1; transform: none; } }
.bt-sub { fill: #0D141E; stroke: #2E3A4A; stroke-width: 1.2; }
.bt-pads rect { fill: #C9A45C; }
.bt-lid { fill: url(#btLid); stroke: rgba(201, 164, 92, .55); stroke-width: 1.2; }
.bt-die { fill: #060A10; stroke: #1E2A38; stroke-width: 1; }
.fb { opacity: 0; animation: btBlock .5s ease-out forwards; }
.fb.c { fill: rgba(127, 220, 235, .55); }
.fb.g { fill: rgba(243, 207, 122, .5); }
.fb.n { fill: rgba(216, 209, 190, .22); }
@keyframes btBlock { 0% { opacity: 0; } 40% { opacity: 1; } 100% { opacity: .8; } }
.bt-mark { font: 600 13px var(--mono); letter-spacing: .18em; fill: rgba(216, 209, 190, .35); }
.bt-sheen { transform: translateX(0); animation: btSheen 1.1s cubic-bezier(.45, 0, .2, 1) 2.9s forwards; }
@keyframes btSheen { to { transform: translateX(420px); } }
/* the name, the bar and the status line, just under the chip (the chip is
   300 viewBox units; the art is scaled to cover the screen) */
.boot-ui {
  position: absolute; left: 50%; top: calc(50% + max(100vw / 1600 * 150, 100vh / 900 * 150) + 26px); translate: -50% 0;
  display: grid; justify-items: center; gap: 12px; width: min(280px, 80vw); opacity: 0; animation: btFade .6s ease-out .5s forwards;
  padding: 14px 18px; border-radius: 14px; background: rgba(4, 8, 15, .92); box-shadow: 0 0 28px 22px rgba(4, 8, 15, .92);
}
.boot-name { margin: 0; font: 500 12px/1 var(--sans); letter-spacing: .38em; padding-left: .38em; text-transform: uppercase; color: #C8CDD6; white-space: nowrap; }
.boot-bar { position: relative; display: block; width: 100%; height: 2px; border-radius: 2px; background: rgba(255, 255, 255, .1); overflow: hidden; }
.boot-bar i { position: absolute; inset: 0; transform-origin: 0 50%; transform: scaleX(calc(var(--bt-pct) / 100)); background: linear-gradient(90deg, #A88444, #F3CF7A); }
.boot-st { position: relative; margin: 0; width: 100%; display: flex; justify-content: space-between; font: 500 11px/1 var(--mono); letter-spacing: .1em; color: #8A93A2; height: 12px; }
.boot-pct { counter-reset: btp var(--bt-pct); color: #F3CF7A; }
.boot-pct::after { content: counter(btp) '%'; }
.boot-st .s1, .boot-st .s2, .boot-st .s3 { position: absolute; right: 0; top: 0; opacity: 0; }
.boot-st .s1 { animation: btFade .3s ease-out .5s forwards, btOut .3s ease-out 2.6s forwards; }
.boot-st .s2 { animation: btFade .3s ease-out 2.95s forwards; }
.boot.ready .boot-st .s2 { animation: btOut .2s ease-out forwards; }
.boot.ready .boot-st .s3 { animation: btFade .2s ease-out .1s forwards; }
@keyframes btOut { from { opacity: 1; } to { opacity: 0; } }
/* exit: the chip pushes forward and fades, then the screen lifts */
.boot.out { transform: translateY(-100%); transition: transform .8s var(--ease-sheet) .18s; pointer-events: none; }
.boot.out .boot-art { transform: scale(1.06); opacity: 0; transition: transform .7s cubic-bezier(.3, 0, .2, 1), opacity .5s ease-in .15s; }
.boot.out .boot-ui { opacity: 0; transition: opacity .25s ease-in; }
@media (prefers-reduced-motion: reduce) {
  .boot, .boot.ready { animation: bootFailsafe .5s linear 5s forwards; --bt-pct: 100; }
  .bt-tr { stroke-dashoffset: 0; animation: none; }
  .bt-st, .bt-sheen { display: none; }
  .bt-chip, .fb, .boot-ui, .boot-art .bt-glow, .boot-st .s3 { opacity: 1; animation: none; transform: none; }
  .boot-st .s1, .boot-st .s2 { display: none; }
  .boot.out, .boot.out .boot-art { transform: none; opacity: 0; transition: opacity .3s linear; }
  html:not(.booted) { --boot-d: .6s; }
}

/* ---- C. smooth scrolling (Lenis, desktop) and page transitions ---------- */
html.lenis, html.lenis body { height: auto; }
html.lenis { scroll-behavior: auto; }
.lenis:not(.lenis-autoToggle).lenis-stopped { overflow: clip; }
.lenis [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-smooth iframe { pointer-events: none; }
/* Moving between pages (home, case studies, beyond): the bar stays put and
   the content crossfades with a short rise. Browsers without cross-page View
   Transitions simply navigate. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; types: page; }
  .nav { view-transition-name: site-nav; }
  html.vt-theme .nav, html.vt-work .nav { view-transition-name: none; }
  html:active-view-transition-type(page)::view-transition-old(root) { animation: vtOut .22s var(--ease-exit) both; }
  html:active-view-transition-type(page)::view-transition-new(root) { animation: vtIn .34s var(--ease-out) both; }
  html:active-view-transition-type(page)::view-transition-group(case-pic) { animation-duration: .42s; animation-timing-function: var(--ease-sheet); }
}
@keyframes vtOut { to { opacity: 0; } }
@keyframes vtIn { from { opacity: 0; transform: translateY(10px); } }

/* ---- D. the hero's layers ------------------------------------------------
   A warm light behind the portrait (the same kind of light as the contact
   card's), lane labels on the portrait frame, and a few pixels of pointer
   depth (desktop): light -6px, traces -2px, portrait 4px, labels 6px. */
.hero { position: relative; --px: 0; --py: 0; }
.hero-light {
  position: absolute; z-index: 0; pointer-events: none;
  top: 6%; right: -4%; width: min(780px, 62vw); aspect-ratio: 1;
  background: radial-gradient(closest-side, rgba(var(--gold-rgb), .13), rgba(var(--gold-rgb), .05) 45%, transparent 72%);
}
:root[data-theme="light"] .hero-light { background: radial-gradient(closest-side, rgba(var(--gold-rgb), .16), rgba(var(--gold-rgb), .06) 45%, transparent 72%); }
.hero .hero-wrap { position: relative; z-index: 1; }


/* the labels share the portrait's grid cell (a sibling, so the frame
   does not clip them) and overhang its edges */
.hero-chips { position: relative; pointer-events: none; z-index: 3; }
@media (min-width: 881px) {
  .hero-chips { grid-column: 2; grid-row: 1; align-self: stretch; }
  .hero .portrait { grid-column: 2; grid-row: 1; }
}
.hero-chip {
  position: absolute; display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
  padding: 7px 12px 7px 10px; border-radius: 999px;
  font: 500 11px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--fg);
  background: var(--navglass-fill); -webkit-backdrop-filter: var(--navglass-filter); backdrop-filter: var(--navglass-filter);
  box-shadow: var(--mat-inner), 0 8px 24px rgba(0, 0, 0, .28);
  opacity: 0; animation: chipIn .7s var(--ease-out) forwards;
}
.hero-chip i { width: 6px; height: 6px; border-radius: 50%; background: var(--gold-hi); box-shadow: 0 0 0 3px rgba(var(--gold-rgb), .18); }
/* callouts: each label sits outside the frame on its left, joined to the
   frame edge by a short gold lead with a pad, like a part annotation on a
   board. Nothing is drawn over the photo. */
.hero-chip.c0, .hero-chip.c1, .hero-chip.c2 { right: calc(100% + 30px); left: auto; bottom: auto; }
.hero-chip.c0 { top: 16%; animation-delay: calc(var(--boot-d, 0s) + .7s); }
.hero-chip.c1 { top: 47%; animation-delay: calc(var(--boot-d, 0s) + .82s); }
.hero-chip.c2 { top: 78%; animation-delay: calc(var(--boot-d, 0s) + .94s); }
.hero-chip::after {
  content: ''; position: absolute; left: 100%; top: 50%; width: 30px; height: 7px; margin-top: -3.5px; pointer-events: none;
  background: linear-gradient(rgba(var(--gold-rgb), .5), rgba(var(--gold-rgb), .5)) left center / calc(100% - 5px) 1px no-repeat,
              radial-gradient(circle, var(--gold-hi) 2.6px, transparent 3.2px) right center / 7px 7px no-repeat;
}
/* where the gutter beside the frame is too narrow, the labels sit as one
   row under the frame instead */
@media (min-width: 881px) and (max-width: 1279px) {
  .hero-chips { grid-row: 2; align-self: start; display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: calc(18px - clamp(30px, 5vw, 70px)); }
  .hero-chip, .hero-chip.c0, .hero-chip.c1, .hero-chip.c2 { position: static; }
  .hero-chip::after { display: none; }
}
@keyframes chipIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (max-width: 880px) { .hero-chips, .hero-light { display: none; } }
.gfx-lite .hero-chip { -webkit-backdrop-filter: none; backdrop-filter: none; background: var(--panel-bg); }
@media (prefers-reduced-motion: reduce) { .hero-chip { animation: none; opacity: 1; } }

/* ambient dust: a dozen faint gold points that brighten and fade very
   slowly, behind everything (desktop, standard level) */
.dust { position: absolute; inset: 0; pointer-events: none; }
.dust i {
  position: absolute; border-radius: 50%; background: var(--gold-hi); opacity: 0;
  will-change: opacity; animation: dustTw 9s ease-in-out infinite;
}
@keyframes dustTw { 0%, 100% { opacity: 0; } 50% { opacity: .38; } }
:root[data-theme="light"] .dust i { background: var(--gold); }
html.cv-open .dust { display: none; }

/* ---- E. Teaching & community: the photo ring -----------------------------
   The photos stand on a ring seen from the front, each in a thin glass
   frame with its reflection on the floor below. The front photo is the main
   one: a gold rim and a pool of warm light under it. A fine orbit on the
   floor marks the ring. app.js places each photo (transform and opacity);
   without JS it is a plain strip. */
.cflow { --cfw: clamp(260px, 38vw, 520px); position: relative; margin-top: clamp(8px, 1.4vw, 18px); }
.cf-stage { display: flex; gap: 16px; overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: 6px; }
.cf-card { flex: 0 0 var(--cfw); margin: 0; scroll-snap-align: center; position: relative; }
.cf-frame { position: relative; padding: 6px; border-radius: 16px; background: linear-gradient(160deg, rgba(255, 255, 255, .07), rgba(255, 255, 255, .02)); box-shadow: 0 22px 44px -18px rgba(0, 0, 0, .7); }
.cf-frame::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none; background: var(--mat-rim);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude;
  transition: opacity var(--d-base) var(--ease-out);
}
.cf-frame::before {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none; opacity: 0;
  background: linear-gradient(160deg, rgba(var(--gold-rgb), .9), rgba(var(--gold-rgb), .25) 40%, rgba(var(--gold-rgb), .1) 70%, rgba(var(--gold-rgb), .6));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude;
  transition: opacity var(--d-base) var(--ease-out);
}
.cf-img { display: block; width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover; border-radius: 11px; filter: var(--img-dim); cursor: zoom-in; }
.cf-ref, .cf-orbit, .cf-pool, .cf-via { display: none; }
.cf-card figcaption { display: none; }
.cf-bar { display: none; }
/* with JS: the ring */
.cflow.cf-on .cf-stage {
  display: block; position: relative; overflow: visible; overflow-x: clip; overflow-clip-margin: 0; padding: 0;
  height: calc((var(--cfw) - 12px) * 2 / 3 + 12px + (var(--cfw) - 12px) * 2 / 3 * .34 + 30px);
  perspective: 1500px; perspective-origin: 50% 35%;
  touch-action: pan-y; cursor: grab; outline-offset: 6px; scroll-snap-type: none;
}
.cflow.cf-on .cf-stage.is-drag { cursor: grabbing; }
.cflow.cf-on .cf-card {
  position: absolute; left: 0; top: 0; width: var(--cfw); transform-origin: 50% 40%;
  will-change: transform, opacity; -webkit-user-select: none; user-select: none;
}
.cflow.cf-on .cf-img { -webkit-user-drag: none; }
.cflow.cf-on .cf-card:not(.is-active) .cf-img { cursor: pointer; }
.cflow.cf-on .cf-card.is-active .cf-frame::before { opacity: 1; }
.cflow.cf-on .cf-card.is-active .cf-frame::after { opacity: 0; }
.cflow.cf-on .cf-ref {
  display: block; width: calc(100% - 12px); margin: 10px auto 0; height: auto; aspect-ratio: 3 / 2; object-fit: cover; border-radius: 11px;
  transform: scaleY(-1); opacity: .42; pointer-events: none; filter: var(--img-dim);
  -webkit-mask-image: linear-gradient(to top, rgba(0, 0, 0, .5), transparent 42%); mask-image: linear-gradient(to top, rgba(0, 0, 0, .5), transparent 42%);
}
/* the floor: the orbit, the pool of light and the via under the front photo */
.cflow.cf-on .cf-orbit {
  display: block; position: absolute; left: 50%; translate: -50% 0; width: min(100%, calc(var(--cfw) * 2.5)); height: calc(var(--cfw) * .2);
  top: calc((var(--cfw) - 12px) * 2 / 3 + 12px - var(--cfw) * .16); pointer-events: none; overflow: visible;
}
.cflow.cf-on .cf-pool {
  display: block; position: absolute; left: 50%; translate: -50% 0; width: calc(var(--cfw) * 1.1); height: calc(var(--cfw) * .22); pointer-events: none;
  top: calc((var(--cfw) - 12px) * 2 / 3 + 12px - var(--cfw) * .08);
  background: radial-gradient(closest-side, rgba(var(--gold-rgb), .16), rgba(var(--gold-rgb), .05) 55%, transparent);
}
.cflow.cf-on .cf-via {
  display: block; position: absolute; left: 50%; width: 9px; height: 9px; margin-left: -4.5px; border-radius: 50%; pointer-events: none; z-index: 300;
  top: calc((var(--cfw) - 12px) * 2 / 3 + 12px + var(--cfw) * .04 - 4.5px);
  background: #F3CF7A; box-shadow: 0 0 0 3px rgba(var(--gold-rgb), .18), 0 0 12px rgba(var(--gold-rgb), .6);
}
.cflow.cf-on .cf-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px; margin-top: 4px; }
.cflow.cf-on .cf-cap { flex: 1 1 260px; }
.cf-count { font: 500 var(--t-xs)/1 var(--mono); letter-spacing: .12em; color: var(--fg-3); }
.cf-cap { margin: 0; font-size: var(--t-s); color: var(--fg-2); line-height: 1.5; max-width: 60ch; }
/* the feedback, as three readouts */
.moments-stats { margin: clamp(18px, 2.4vw, 26px) 0 0; display: grid; gap: 10px; color: var(--fg-2); }
.ms-from { font-size: var(--t-s); color: var(--fg-2); }
.ms-list { display: flex; flex-wrap: wrap; gap: 10px 28px; }
.ms-r { display: inline-flex; align-items: baseline; gap: 10px; }
.ms-v { font: 500 var(--t-l)/1 var(--mono); color: var(--cyan-hi); letter-spacing: -.01em; }
:root[data-theme="light"] .ms-v { color: var(--cyan); }
.ms-l { font-size: var(--t-s); color: var(--fg-2); }
@media (max-width: 620px) {
  .cflow { --cfw: 74vw; }
  .cflow.cf-on .cf-cap { flex-basis: 100%; }
  .ms-list { display: grid; gap: 8px; }
}
:root[data-theme="light"] .cflow.cf-on .cf-ref { opacity: .28; }
:root[data-theme="light"] .cf-frame { background: linear-gradient(160deg, rgba(255, 255, 255, .8), rgba(255, 255, 255, .4)); box-shadow: 0 22px 44px -20px rgba(60, 40, 10, .3); }
@media (prefers-reduced-motion: reduce) { .cflow.cf-on .cf-card { will-change: auto; } }

/* ---- E. the timeline rail -------------------------------------------------
   From the first node's centre to the last (lengths from fx.js railFill), a
   gold line grows down the rail; its tip, a gold via like the nodes, sits
   on a reading line 55% down the screen. Each node and branch turn gold as
   the tip reaches them. With reduced motion (or no scroll timelines) the
   rail is simply the plain rail. */
.trk-fill, .trk-head { display: none; }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .track.trk-on { view-timeline: --trk block; }
    .trk-on > .trk-fill {
      display: block; position: absolute; left: 0; width: 1px; pointer-events: none; overflow: clip;
      top: var(--trk-a); height: calc(var(--trk-b) - var(--trk-a));
    }
    .trk-on .trk-line {
      position: absolute; inset: 0; background: linear-gradient(180deg, rgba(var(--gold-rgb), .55), var(--gold-hi));
      transform: translateY(-100%);
      animation: trkLine linear both; animation-timeline: --trk;
      animation-range: cover calc(var(--trk-a) + 45vh) cover calc(var(--trk-b) + 45vh);
    }
    .trk-on > .trk-head {
      display: block; position: absolute; left: -4.5px; top: calc(var(--trk-a) - 5px); width: 10px; height: 10px; border-radius: 50%;
      background: var(--gold-hi); box-shadow: 0 0 0 4px var(--ink); pointer-events: none; z-index: 2;
      animation: trkHead linear both; animation-timeline: --trk;
      animation-range: cover calc(var(--trk-a) + 45vh) cover calc(var(--trk-b) + 45vh);
    }
    @keyframes trkLine { to { transform: none; } }
    @keyframes trkHead { from { transform: translateY(0); opacity: 0; } 4% { opacity: 1; } 96% { opacity: 1; } to { transform: translateY(calc(var(--trk-b) - var(--trk-a))); opacity: 0; } }
    /* each node and its branch light as the tip passes */
    .trk-on > .exp::before { animation: nodeOn linear both; animation-timeline: --trk; animation-range: cover calc(var(--n) + 45vh) cover calc(var(--n) + 45vh + 2px); }
    .trk-on > .exp::after { animation: branchOn linear both; animation-timeline: --trk; animation-range: cover calc(var(--n) + 45vh) cover calc(var(--n) + 45vh + 2px); }
    @keyframes nodeOn { from { background: var(--copper); border-color: var(--trace-gold); } to { background: var(--gold-hi); border-color: var(--gold-hi); } }
    @keyframes branchOn { from { background: var(--trace-dim); } to { background: rgba(var(--gold-rgb), .7); } }
  }
}

/* ---- E. About: an editorial page --------------------------------------
   The lede is set large; Education and Leadership stand open beside each
   other, divided by a hairline; Skills runs underneath across the full
   width as six group cards (the phone version's card, laid out for a wide
   screen): the group, a count, and the items. On phones the tabs show one
   column at a time. */
.sk-n { display: none; }
@media (min-width: 621px) {
  #about .about-lede { font-size: clamp(21px, 2.3vw, 28px); line-height: 1.42; max-width: 40ch; letter-spacing: -.012em; }
  #about .cols { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); align-items: start; }
  :root #about .col {
    background: none; box-shadow: none; border: 0; border-radius: 0; backdrop-filter: none; -webkit-backdrop-filter: none;
    padding: 4px clamp(18px, 2.4vw, 34px) 8px;
  }
  #about .col::before, #about .col::after { display: none; }
  #about .col:nth-child(1) { grid-column: 1; grid-row: 1; padding-left: 0; }
  #about .col:nth-child(3) { grid-column: 2; grid-row: 1; border-left: 1px solid var(--hair); }
  #about .col h3 { margin-bottom: 14px; }
  /* Skills: the full width, below */
  :root #about .col:nth-child(2) { grid-column: 1 / -1; grid-row: 2; padding: 0; margin-top: clamp(26px, 3vw, 40px); }
  #about .sk-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(12px, 1.4vw, 18px); }
  #about .sk {
    position: relative; display: grid; align-content: start; gap: 10px; margin: 0; padding: 18px 20px 20px;
    border-radius: var(--r-m); background: var(--card-fill); box-shadow: var(--card-shadow);
    transition: transform var(--d-fast) var(--ease-out);
  }
  #about .sk::after {
    content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none; background: var(--mat-rim);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude;
  }
  #about .sk-g {
    display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin: 0; padding-bottom: 10px; border-bottom: 1px solid var(--hair);
    font: 600 var(--t-b)/1.3 var(--sans); letter-spacing: -.01em; text-transform: none; color: var(--fg);
  }
  #about .sk-n { display: inline; font: 500 var(--t-xs)/1 var(--mono); color: var(--cyan-hi); letter-spacing: .04em; }
  :root[data-theme="light"] #about .sk-n { color: var(--cyan); }
  #about .sk-i { font-size: var(--t-s); line-height: 1.65; color: var(--fg-2); }
}
@media (min-width: 621px) and (hover: hover) and (pointer: fine) { #about .sk:hover { transform: translateY(-2px); } }
/* tablets: two cards to a row */
@media (min-width: 621px) and (max-width: 1024px) {
  #about .sk-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---- E. Contact: a closing panel with two halves ------------------------
   The pitch on the left (headline, sentence, note), the ways to reach me on
   the right as a clear stack. Same card, same content. */
@media (min-width: 900px) {
  .contact { text-align: left; }
  .contact > .wrap {
    display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, .85fr); column-gap: clamp(32px, 5vw, 72px);
    grid-template-areas: "h links" "p links" "note links"; align-items: start; max-width: 1100px;
  }
  .contact-h { grid-area: h; margin: 0 0 16px; font-size: clamp(38px, 4.6vw, 60px); line-height: 1.04; }
  .contact-p { grid-area: p; margin: 0; max-width: 40ch; }
  .contact-note { grid-area: note; margin-top: 18px; }
  .contact-links { grid-area: links; align-self: center; display: grid; grid-template-columns: 1fr 1fr; gap: 10px; justify-content: stretch; min-width: 0; }
  .contact-links > .btn { justify-content: space-between; min-height: 50px; min-width: 0; }
  .contact-links > .btn-primary { grid-column: 1 / -1; justify-content: center; overflow-wrap: anywhere; }
}

/* ---- E. How I debug: the SK-1 bench scope -------------------------------
   One instrument, drawn as a device (dark in both themes): a screen with the
   trace, a MEASURE pane and a decode line; lit softkeys under it (the three
   findings); two knobs that really turn (zoom, position); and the tools as
   rocker switches along the bottom. Cyan is the measured value, gold what
   you can act on. */
.approach .sec-head h2 { font-size: var(--t-2xl); font-style: normal; max-width: none; line-height: 1.1; }
.approach .sec-lede { font-size: var(--t-m); color: var(--fg-2); max-width: 46ch; }
.sk1 {
  --c: #8FD3DE; --g: #EBD298; --ink-d: #05090C; --edge: #232D39;
  position: relative; display: grid; gap: 14px; color: #E8E6E0;
  grid-template-columns: minmax(0, 1fr) 176px; grid-template-areas: "top top" "screen ctrl" "keys ctrl" "tools tools";
  padding: clamp(14px, 1.8vw, 22px); border-radius: 26px;
  background: linear-gradient(180deg, #1B222B, #11161D 55%, #0C1016);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .08), inset 0 0 0 1px #222B36, inset 0 -2px 0 rgba(0, 0, 0, .5), 0 40px 80px -36px rgba(0, 0, 0, .7), 0 2px 10px rgba(0, 0, 0, .25);
}
.sk1-top { grid-area: top; display: flex; align-items: center; justify-content: space-between; padding: 0 4px; font: 500 11px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase; color: #6F7988; }
.sk1-brand b { color: #D9D6CE; font-weight: 600; margin-right: 8px; }
.sk1-pwr { display: inline-flex; align-items: center; gap: 8px; }
.sk1-pwr i { width: 6px; height: 6px; border-radius: 50%; background: var(--g); box-shadow: 0 0 0 3px rgba(var(--gold-rgb), .15), 0 0 8px rgba(var(--gold-rgb), .5); }
/* the screen: a recessed black glass in its bezel, with a reflection */
.sk1-screen {
  grid-area: screen; position: relative; display: grid; grid-template-rows: auto 1fr auto; min-height: 380px; overflow: hidden;
  border-radius: 14px; background: var(--ink-d);
  box-shadow: 0 0 0 1px #1C2630, 0 0 0 6px #0A0E13, 0 0 0 7px #232D39, inset 0 2px 24px rgba(0, 0, 0, .9);
  margin: 7px;
}
.sk1-screen::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; border-radius: inherit;
  background: linear-gradient(118deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, .02) 30%, transparent 30.4%), radial-gradient(120% 70% at 50% 40%, rgba(95, 208, 200, .06), transparent 70%);
}
.sk1-status { display: flex; align-items: center; gap: 14px; padding: 10px 16px; border-bottom: 1px solid rgba(143, 211, 222, .1); font: 500 11px/1 var(--mono); letter-spacing: .08em; color: #7E8A97; white-space: nowrap; overflow: hidden; }
.sk1-run { display: inline-flex; align-items: center; gap: 6px; color: var(--c); text-transform: uppercase; }
.sk1-run i { width: 6px; height: 6px; border-radius: 50%; background: var(--c); }
.sk1-ch { font: 600 12px/1 var(--mono); color: #E8E6E0; letter-spacing: .06em; }
.sk1-proj { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.sk1-zr { margin-left: auto; color: var(--g); }
.sk1-view { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 300px); min-height: 0; }
.sk1-plot { position: relative; min-height: 250px; overflow: hidden; border-right: 1px solid rgba(143, 211, 222, .1); }
.sk1-grid { position: absolute; inset: 0; width: 100%; height: 100%; }
.sk1-grid path { stroke: rgba(143, 211, 222, .07); stroke-width: 1; vector-effect: non-scaling-stroke; fill: none; }
.sk1-grid .sk1-axis { stroke: rgba(143, 211, 222, .15); }
.sk1-band { position: absolute; left: 0; right: 0; top: 14%; bottom: 8%; }
.sk1-wave { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.sk1-w { display: none; }
.sk1-w.on { display: inline; }
.sk1-tr { fill: none; stroke: var(--c); stroke-width: 2; vector-effect: non-scaling-stroke; stroke-linejoin: round; }
.sk1-tr.ref { stroke: rgba(var(--gold-rgb), .85); stroke-width: 1.5; }
.sk1-lim { stroke: rgba(var(--gold-rgb), .55); stroke-width: 1; stroke-dasharray: 6 5; vector-effect: non-scaling-stroke; fill: none; }
.sk1-span { stroke: rgba(var(--gold-rgb), .7); stroke-width: 1; vector-effect: non-scaling-stroke; fill: none; }
.sk1-mks { display: none; }
.sk1-mks.on { display: block; }
.sk1-mk { position: absolute; transform: translate(-50%, -100%); font: 500 11px/1 var(--mono); letter-spacing: .06em; color: var(--g); white-space: nowrap; transition: opacity var(--d-fast) var(--ease-out); }
.sk1-mk.dim { color: #B9BCC2; }
.sk1-meas { position: relative; padding: 18px 20px; }
.sk1-m { display: none; }
.sk1-m.on { display: grid; gap: 8px; align-content: start; }
.sk1-lab { font: 500 var(--t-xs)/1.4 var(--mono); letter-spacing: .06em; color: #8C96A3; }
.sk1-lab::first-letter { text-transform: uppercase; }
.sk1-metric { font: 500 var(--t-2xl)/1 var(--mono); letter-spacing: -.03em; color: var(--c); }
.sk1-find { margin: 4px 0 0; font-size: var(--t-s); line-height: 1.6; color: #C9CDD3; }
.sk1-from { justify-self: start; margin-top: 4px; color: var(--g); }
.sk1-decode { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; min-height: 46px; padding: 8px 16px; border-top: 1px solid rgba(143, 211, 222, .1); font-size: var(--t-s); color: #8C96A3; }
.sk1-dk { font: 500 11px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--c); margin-right: 6px; }
.sk1-dn { font: 500 11px/1 var(--mono); letter-spacing: .06em; color: #7E8A97; }
.sk1-hit {
  position: relative; z-index: 1; min-height: 30px; padding: 0 10px; border-radius: 8px; border: 1px solid rgba(var(--gold-rgb), .35); background: rgba(var(--gold-rgb), .06);
  color: #F2EFE7; font: 500 var(--t-s)/1 var(--sans); cursor: pointer; transition: background-color var(--d-fast) var(--ease-out), border-color var(--d-fast) var(--ease-out);
}
.sk1-hit::before { content: ''; position: absolute; inset: -7px 0; }
.sk1-hit:hover { background: rgba(var(--gold-rgb), .14); border-color: rgba(var(--gold-rgb), .7); }
.sk1-hit:focus-visible { outline: 2px solid var(--gold-hi); outline-offset: 2px; }
/* the knobs: knurled metal caps over a scale of ticks */
.sk1-ctrl {
  grid-area: ctrl; display: grid; align-content: center; justify-items: center; gap: 18px; padding: 16px 8px;
  border-radius: 16px; background: linear-gradient(180deg, #151B23, #0F141A); box-shadow: inset 0 0 0 1px #1E2731, inset 0 1px 0 rgba(255, 255, 255, .04);
}
.sk1-kw { display: grid; justify-items: center; gap: 10px; }
.sk1-kn {
  position: relative; width: 84px; height: 84px; border-radius: 50%; cursor: grab; touch-action: none;
  background: repeating-conic-gradient(from -135.6deg, rgba(216, 209, 190, .4) 0 1.2deg, transparent 1.2deg 27deg);
}
/* the scale runs 270 degrees: the bottom quarter has no ticks */
.sk1-kn::before { content: ''; position: absolute; inset: -1px; border-radius: 50%; background: conic-gradient(from 134deg, #11171E 0 92deg, transparent 92deg); }
.sk1-kn:active, .sk1-kn.is-turning { cursor: grabbing; }
.sk1-kn.is-turning .sk1-cap { transition: none; }
.sk1-kn:focus-visible { outline: 2px solid var(--gold-hi); outline-offset: 4px; }
.sk1-cap {
  position: absolute; inset: 12px; border-radius: 50%;
  background:
    radial-gradient(circle at 38% 30%, rgba(255, 255, 255, .22), transparent 42%),
    repeating-conic-gradient(#2A323D 0 4deg, #1A2028 4deg 8deg);
  box-shadow: inset 0 0 0 1px #3A4553, inset 0 -3px 6px rgba(0, 0, 0, .6), 0 6px 14px rgba(0, 0, 0, .6), 0 0 0 4px #0B0F14;
  transition: transform .12s ease-out;
}
.sk1-cap::after { content: ''; position: absolute; inset: 9px; border-radius: 50%; background: radial-gradient(circle at 40% 32%, #39424E, #161B22 70%); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .12); }
.sk1-ptr { position: absolute; z-index: 1; left: 50%; top: 6px; width: 3px; height: 16px; margin-left: -1.5px; border-radius: 2px; background: var(--g); box-shadow: 0 0 6px rgba(var(--gold-rgb), .5); }
.sk1-kl { font: 500 11px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase; color: #8C96A3; }
/* the softkeys: keycaps with a status LED */
.sk1-keys { grid-area: keys; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; padding: 0 7px; }
.sk1-key {
  position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 2px 12px; min-height: 60px; padding: 10px 14px;
  text-align: left; cursor: pointer; color: #D9D6CE; font: inherit; border: 0; border-radius: 12px;
  background: linear-gradient(180deg, #232B35, #171D25);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .07), inset 0 0 0 1px #2B3541, 0 3px 0 #070A0E, 0 6px 12px rgba(0, 0, 0, .35);
  transition: transform 100ms var(--ease-out), box-shadow 100ms var(--ease-out);
}
.sk1-key:active { transform: translateY(2px); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), inset 0 0 0 1px #2B3541, 0 1px 0 #070A0E, 0 3px 6px rgba(0, 0, 0, .3); }
.sk1-key:focus-visible { outline: 2px solid var(--gold-hi); outline-offset: 3px; }
.sk1-led { grid-row: span 2; width: 8px; height: 8px; border-radius: 50%; background: #2A323D; box-shadow: inset 0 1px 1px rgba(0, 0, 0, .6); transition: background-color var(--d-fast) var(--ease-out), box-shadow var(--d-fast) var(--ease-out); }
.sk1-key-n { font: 600 var(--t-b)/1.2 var(--sans); letter-spacing: -.01em; }
.sk1-key-p { font-size: var(--t-xs); color: #7E8A97; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sk1-key[aria-selected="true"] { box-shadow: inset 0 1px 0 rgba(255, 255, 255, .07), inset 0 0 0 1px rgba(var(--gold-rgb), .55), 0 3px 0 #070A0E, 0 6px 12px rgba(0, 0, 0, .35); }
.sk1-key[aria-selected="true"] .sk1-led { background: var(--g); box-shadow: 0 0 0 3px rgba(var(--gold-rgb), .15), 0 0 10px rgba(var(--gold-rgb), .7); }
.sk1-key[aria-selected="true"] .sk1-key-n { color: #F6E7BF; }
/* the tools: rocker switches (I up when on) */
.sk1-tools { grid-area: tools; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px; padding: 14px 7px 2px; border-top: 1px solid #1E2731; }
.sk1-tools-h { font: 600 var(--t-s)/1.2 var(--sans); color: #D9D6CE; margin-right: 6px; }
.sk1-rks { display: flex; flex-wrap: wrap; gap: 6px 16px; }
.sk1-rk { display: inline-flex; align-items: center; gap: 10px; min-height: 44px; padding: 0 4px; border: 0; background: none; color: #A7AFBA; font: 500 var(--t-s)/1 var(--sans); cursor: pointer; }
.sk1-rk:focus-visible { outline: 2px solid var(--gold-hi); outline-offset: 2px; border-radius: 8px; }
.sk1-rk-sw { position: relative; width: 20px; height: 32px; border-radius: 5px; background: #05080C; box-shadow: inset 0 0 0 1px #2B3644, 0 1px 0 rgba(255, 255, 255, .05); }
.sk1-rk-sw i {
  position: absolute; inset: 3px; border-radius: 3px;
  background: linear-gradient(180deg, #1B222B 0 46%, #39434F 54% 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .08);
  transition: background var(--d-fast) var(--ease-out);
}
.sk1-rk-sw i::before { content: ''; position: absolute; left: 50%; top: 4px; width: 2px; height: 6px; margin-left: -1px; border-radius: 1px; background: #4A5564; }
.sk1-rk[aria-checked="true"] { color: #F2EFE7; }
.sk1-rk[aria-checked="true"] .sk1-rk-sw i { background: linear-gradient(180deg, #4A4230 0 46%, #241F16 54% 100%); }
.sk1-rk[aria-checked="true"] .sk1-rk-sw i::before { background: var(--g); box-shadow: 0 0 6px rgba(var(--gold-rgb), .8); }
/* without JS: every reading shows */
.sk1:not(.sk1-on) .sk1-m { display: grid; gap: 8px; }
.sk1:not(.sk1-on) .sk1-m + .sk1-m { margin-top: 18px; }
/* narrower: the MEASURE pane goes under the trace */
@media (max-width: 989px) {
  .sk1-view { grid-template-columns: minmax(0, 1fr); }
  .sk1-plot { min-height: 210px; border-right: 0; border-bottom: 1px solid rgba(143, 211, 222, .1); }
  .sk1 { grid-template-columns: minmax(0, 1fr) 150px; }
  .sk1-kn { width: 72px; height: 72px; }
  .sk1-cap { inset: 9px; }
}
/* phones: one column; the knobs side by side */
@media (max-width: 680px) {
  .sk1 { grid-template-columns: minmax(0, 1fr); grid-template-areas: "top" "screen" "keys" "ctrl" "tools"; padding: 10px; border-radius: 20px; }
  .sk1-screen { margin: 6px; min-height: 0; }
  .sk1-plot { min-height: 170px; }
  .sk1-status { gap: 10px; padding: 9px 12px; }
  .sk1-proj { display: none; }
  .sk1-meas { padding: 14px 14px 16px; }
  .sk1-keys { padding: 0 2px; gap: 6px; }
  .sk1-key { grid-template-columns: minmax(0, 1fr); justify-items: center; text-align: center; gap: 8px; padding: 10px 6px; }
  .sk1-led { grid-row: auto; }
  .sk1-key-p { display: none; }
  .sk1-ctrl { grid-auto-flow: column; justify-content: space-evenly; padding: 14px 8px; }
  .sk1-kn { width: 70px; height: 70px; }
  .sk1-tools { padding: 10px 2px 0; }
  .sk1-rks { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; width: 100%; }
}
@media (prefers-reduced-motion: reduce) { .sk1-cap, .sk1-key, .sk1-rk-sw i { transition: none; } }

/* About, 621-760px: one column (two were cramped at about 300px each) */
@media (min-width: 621px) and (max-width: 760px) {
  #about .cols { grid-template-columns: 1fr; }
  #about .col:nth-child(1), #about .col:nth-child(3) { grid-column: 1; grid-row: auto; border-left: 0; padding-left: 0; margin-top: 0; }
  #about .col:nth-child(3) { order: 2; padding-top: 18px; border-top: 1px solid var(--hair); }
  :root #about .col:nth-child(2) { grid-row: auto; order: 3; margin-top: 22px; }
}

/* ---- the pill controls: Cards/List and the photo ring --------------------
   One glass pill holding the choices; a gold highlight (a soft gold fill
   with a gold inset rim) glides to the current one. */
.work-view, .cf-ctl {
  position: relative; display: inline-grid; align-items: center; padding: 4px; border-radius: 999px;
  border: 1px solid var(--glass-edge); background: var(--panel-bg); box-shadow: var(--mat-inner, none);
}
.work-view { grid-template-columns: 1fr 1fr; margin: 18px 0 2px; }
.work-view::before, .cf-hl {
  content: ''; position: absolute; border-radius: 999px; pointer-events: none;
  background: rgba(var(--gold-rgb), .16); box-shadow: inset 0 0 0 1px rgba(var(--gold-rgb), .45);
  transition: transform var(--d-base) var(--ease-sheet);
}
.work-view::before { top: 4px; bottom: 4px; left: 4px; width: calc(50% - 4px); }
.work-view[data-mode="list"]::before { transform: translateX(100%); }
.wv-lab {
  position: relative; z-index: 1; min-width: 92px; min-height: 40px; padding: 0 18px; border: 0; border-radius: 999px; background: none; cursor: pointer;
  font: 500 var(--t-s)/1 var(--sans); color: var(--fg-3); transition: color var(--d-fast) var(--ease-out);
}
.wv-lab:hover, .wv-lab[aria-pressed="true"] { color: var(--fg); }
.wv-lab[aria-pressed="true"] { color: var(--gold-hi); }
:root[data-theme="light"] .wv-lab[aria-pressed="true"] { color: var(--gold); }
.wv-lab:focus-visible, .cf-arrow:focus-visible, .cf-dot:focus-visible { outline: 2px solid var(--gold-hi); outline-offset: 2px; }
/* the ring's pill: arrow, dots, arrow */
.cf-ctl { grid-auto-flow: column; gap: 0; }
.cf-arrow {
  position: relative; z-index: 1; display: grid; place-items: center; width: 40px; height: 40px; padding: 0; border: 0; border-radius: 999px;
  background: none; color: var(--fg-2); cursor: pointer; transition: color var(--d-fast) var(--ease-out), background-color var(--d-fast) var(--ease-out);
}
.cf-arrow::before { content: ''; position: absolute; inset: -2px; }
.cf-arrow svg { width: 18px; height: 18px; }
.cf-arrow:hover { color: var(--gold-hi); background: rgba(var(--gold-rgb), .08); }
:root[data-theme="light"] .cf-arrow:hover { color: var(--gold); }
.cf-dots { position: relative; display: flex; align-items: center; margin: 0 2px; }
.cf-hl { left: 0; top: 50%; width: 24px; height: 32px; margin-top: -16px; }
.cf-dot { position: relative; z-index: 1; display: grid; place-items: center; width: 24px; height: 44px; padding: 0; border: 0; background: none; cursor: pointer; }
.cf-dot::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--fg-3); opacity: .55; transition: background-color var(--d-fast) var(--ease-out), opacity var(--d-fast) var(--ease-out), transform var(--d-base) var(--ease-out); }
.cf-dot:hover::before { opacity: 1; }
.cf-dot.on::before { background: var(--gold-hi); opacity: 1; transform: scale(1.25); }
:root[data-theme="light"] .cf-dot.on::before { background: var(--gold); }
.cf-dot:focus-visible { outline-offset: -6px; border-radius: 999px; }

/* ---- case pages: the gallery, the story and the block diagram -------------
   Every picture of a project fills an equal 4:3 frame (cropped to fit, so
   the grid is even, owner's choice); a click opens the whole picture at
   full size (the lightbox in fx.js). The story runs Overview, Problem, System (with its
   block diagram), How it works, Hardware, Software, My part, Challenges,
   Result, What's next: only the parts a project has. */
.cg { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(12px, 1.6vw, 20px); margin: clamp(6px, 1.2vw, 14px) 0 var(--s3); }
.cg-1 { grid-template-columns: minmax(0, 860px); justify-content: center; }
.cg-tile { margin: 0; display: grid; gap: 10px; align-content: start; }
.cg-frame {
  position: relative; aspect-ratio: 4 / 3; overflow: hidden;
  border-radius: var(--r-m); background: var(--ink-2); box-shadow: var(--card-shadow);
  transition: transform var(--d-fast) var(--ease-out);
}
.cg-1 .cg-frame { aspect-ratio: 16 / 9; }
.cg-frame::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none; background: var(--mat-rim);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude;
}
.cg-frame.is-svg { background: #0D1B2A; }
.cg-frame img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center; filter: var(--img-dim); cursor: zoom-in; }
.cg-frame::after { z-index: 1; }
.cg-tile figcaption { padding: 0 4px; font-size: var(--t-s); line-height: 1.55; color: var(--fg-3); }
@media (hover: hover) and (pointer: fine) { .cg-tile:hover .cg-frame { transform: translateY(-2px); } }
@media (max-width: 989px) { .cg { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .cg { grid-template-columns: minmax(0, 1fr); } }

.case-main .case-grid h3 { font: 600 var(--t-b)/1.35 var(--sans); color: var(--fg); letter-spacing: -.01em; margin: 0; }
.case-steps { list-style: none; counter-reset: st; margin: 0; padding: 0; display: grid; gap: 12px; }
.case-steps li { counter-increment: st; position: relative; padding-left: 38px; font-size: var(--t-b); line-height: 1.68; color: var(--fg-2); max-width: 68ch; }
.case-steps li::before { content: counter(st, decimal-leading-zero); position: absolute; left: 0; top: .2em; font: 500 var(--t-xs)/1.6 var(--mono); color: var(--cyan-hi); }
.case-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.case-list li { position: relative; padding-left: 20px; font-size: var(--t-b); line-height: 1.68; color: var(--fg-2); max-width: 68ch; }
.case-list li::before { content: ''; position: absolute; left: 2px; top: .72em; width: 6px; height: 6px; border-radius: 50%; background: var(--gold); opacity: .8; }
.case-parts { width: 100%; max-width: 720px; border-collapse: collapse; font-size: var(--t-s); }
.case-parts thead th { text-align: left; font-weight: 500; color: var(--fg-3); padding: 0 12px 8px 0; border-bottom: 1px solid var(--hair-2); }
.case-parts tbody th, .case-parts td { text-align: left; vertical-align: baseline; padding: 10px 12px 10px 0; border-bottom: 1px solid var(--hair); line-height: 1.5; }
.case-parts tbody tr:last-child > * { border-bottom: 0; }
.case-parts tbody th { font-weight: 600; color: var(--fg); width: 38%; }
.case-parts td { color: var(--fg-2); }
.case-ch { display: grid; gap: 12px; }
.ch { padding: 16px 18px; border-radius: var(--r-s); background: rgba(var(--gold-rgb), .035); border: 1px solid var(--hair); }
.ch p { margin-top: 6px; }
:root[data-theme="light"] .ch { background: rgba(255, 255, 255, .55); }
/* the block diagram (it scrolls inside its own box on narrow screens; the
   column must be allowed to be narrower than the drawing) */
.case-layout > *, .case-main, .case-grid > section { min-width: 0; }
.dg { margin: 20px 0 0; max-width: 100%; }
.dg-scroll { overflow-x: auto; padding: 14px; border-radius: var(--r-m); background: var(--card-fill); box-shadow: var(--card-shadow); scrollbar-width: thin; }
.dg svg { display: block; width: 100%; height: auto; min-width: 560px; }
.dg-n rect { fill: var(--ink-2); stroke: var(--hair-2); stroke-width: 1.2; }
.dg-n.hl rect { fill: rgba(var(--gold-rgb), .09); stroke: rgba(var(--gold-rgb), .75); }
.dg-t { fill: var(--fg); font: 600 14px var(--sans); }
.dg-s { fill: var(--fg-3); font: 500 10.5px var(--mono); }
.dg-l { fill: none; stroke: rgba(var(--gold-rgb), .7); stroke-width: 1.5; }
.dg-ah { fill: rgba(var(--gold-rgb), .9); }
.dg-lab { fill: var(--cyan-hi); font: 500 10.5px var(--mono); }
:root[data-theme="light"] .dg-lab { fill: var(--cyan); }

/* ---- light theme: the parts drawn with fixed dark values -----------------
   Shadows turn warm and lighter, white-on-white highlights become a faint
   warm tint, and the devices that stay dark (the SK-1, the console, the
   loader, the circuit board) sit on a soft warm shadow. */
:root[data-theme="light"] .btn:hover, :root[data-theme="light"] .nav-cta:hover { box-shadow: 0 0 0 1px rgba(var(--gold-rgb), .35), 0 12px 24px -14px rgba(70, 50, 20, .35); }
:root[data-theme="light"] .fx-top:hover { box-shadow: var(--glass-spec), 0 0 0 1px rgba(var(--gold-rgb), .35), 0 12px 24px -12px rgba(70, 50, 20, .3); }
:root[data-theme="light"] .pop-in { box-shadow: var(--glass-spec), 0 34px 80px -30px rgba(70, 50, 20, .4); }
:root[data-theme="light"] .case-toc a:hover { background: rgba(var(--gold-rgb), .06); }
:root[data-theme="light"] .hero-chip { box-shadow: var(--mat-inner), 0 10px 24px -12px rgba(70, 50, 20, .3); }
:root[data-theme="light"] .fx-glare { background: radial-gradient(circle at var(--mx, 50%) var(--my, 50%), rgba(255, 255, 255, .55), transparent 55%); mix-blend-mode: soft-light; }
:root[data-theme="light"] .cflow.cf-on .cf-via { background: var(--gold); box-shadow: 0 0 0 3px rgba(var(--gold-rgb), .16), 0 0 10px rgba(var(--gold-rgb), .35); }
:root[data-theme="light"] .cflow.cf-on .cf-pool { background: radial-gradient(closest-side, rgba(var(--gold-rgb), .12), rgba(var(--gold-rgb), .04) 55%, transparent); }
:root[data-theme="light"] .sk1 { box-shadow: inset 0 1px 0 rgba(255, 255, 255, .08), inset 0 0 0 1px #222B36, inset 0 -2px 0 rgba(0, 0, 0, .5), 0 40px 70px -34px rgba(70, 50, 20, .55), 0 2px 10px rgba(70, 50, 20, .14); }
:root[data-theme="light"] .pop-fig { box-shadow: inset 0 0 0 1px var(--hair-2), 0 12px 26px -16px rgba(70, 50, 20, .4); }
:root[data-theme="light"] .tag { background: rgba(255, 255, 255, .6); }
:root[data-theme="light"] .nav-inner.glass, :root[data-theme="light"] .nav.stuck .nav-inner.glass {
  box-shadow: var(--mat-inner), 0 0 0 1px rgba(70, 50, 20, .05), 0 10px 24px -16px rgba(70, 50, 20, .28);
}
:root[data-theme="light"] .btn-primary {
  background: linear-gradient(180deg, #9A7222, #7C5A14); border-color: #7C5A14;
  box-shadow: inset 0 1px 0 rgba(255, 236, 190, .35), 0 8px 18px -10px rgba(131, 95, 20, .6);
}
:root[data-theme="light"] .btn-primary:hover { background: linear-gradient(180deg, #8A6519, #6B4C0D); border-color: #6B4C0D; }

/* the case facts card: sticky beside the story on wide screens (the card
   look above sets position: relative for its rim, which had cancelled the
   sticky and left its top offset pushing it down over the text); in flow,
   first, on narrower ones */
@media (min-width: 1025px) { :root .case-facts { position: sticky; top: calc(var(--navh) + 30px); } }
@media (max-width: 1024px) { :root .case-facts { position: relative; top: auto; } }

/* ---- headings that react to the mouse (fx.js letters()) ----------------
   The letters layer is aria-hidden; a visually hidden copy carries the
   text. Letters are inline-blocks grouped by word, so wrapping and spacing
   stay as they were; only transform moves. */
.sr-only { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
.hero h1, .sec-head h2, .case-head h1 { position: relative; }
.lt-w { display: inline-block; white-space: nowrap; }
.lt-c { display: inline-block; transform-origin: 50% 80%; }
/* while a heading's letters move, each is its own layer (no repaint) */
.lt-on .lt-c { will-change: transform; }
.lt { -webkit-user-select: none; user-select: none; }
/* the faint light that follows the pointer, behind everything */
.fx-glow {
  position: absolute; left: -320px; top: -320px; width: 640px; height: 640px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(closest-side, rgba(var(--gold-rgb), .07), rgba(var(--gold-rgb), .025) 55%, transparent);
  transition: translate .45s cubic-bezier(.22, 1, .36, 1); translate: -2000px -2000px;
}
:root[data-theme="light"] .fx-glow { background: radial-gradient(closest-side, rgba(var(--gold-rgb), .06), rgba(var(--gold-rgb), .02) 55%, transparent); }
html.cv-open .fx-glow { display: none; }
@media (prefers-reduced-motion: reduce) { .fx-glow { display: none; } }
/* links with an arrow nudge it, like the buttons */
.ev-from svg, .mini-link svg, .sk1-from svg { transition: transform .3s cubic-bezier(.22, 1, .36, 1); }
.ev-from:hover svg, .mini-link:hover svg, .sk1-from:hover svg { transform: translate(2px, -2px); }
/* the hero's depth layers move on a mouse: each its own layer there, so the
   pointer parallax never repaints them */
@media (hover: hover) and (pointer: fine) and (min-width: 881px) {
  html:not(.gfx-lite) .hero-light, html:not(.gfx-lite) .hero-circuit, html:not(.gfx-lite) .hero .portrait, html:not(.gfx-lite) .hero-chips { will-change: translate; }
}

/* ---- the board section (#board, js/hero.js) -------------------------------
   The SK board as the site's map: a stage with the board lying free over the
   page (no frame), a small bar (the hint, zoom out, zoom in, reset), then the
   readout of the picked part beside the legend of every part that holds
   something. Tier 0-1: the baked poster on a CSS-3D plane with a contact
   shadow; tiers 2-3: the WebGL board (js/vendor/hero3d.js) fades in over it.
   The board stays a dark device in both themes, like the SK-1. */
.bs-stage { position: relative; }
.board-hero {
  position: relative; display: grid; place-items: center; width: 100%; aspect-ratio: 16 / 9; max-height: 78svh;
  perspective: 1700px; cursor: grab; touch-action: pan-y; -webkit-tap-highlight-color: transparent; outline: none;
  border-radius: var(--r-m); -webkit-user-select: none; user-select: none;
}
.board-hero.is-part { cursor: pointer; }
.board-hero.is-grab { cursor: grabbing; }
.board-hero:focus-visible { box-shadow: inset 0 0 0 2px var(--gold-hi); }
.bh-float { display: block; width: min(86%, 940px); transform-style: preserve-3d; transform: rotateX(30deg) rotateZ(-9deg); transition: opacity .6s ease; }
.bh-tilt { position: relative; display: block; transform-style: preserve-3d; border-radius: 1.4% / 2.2%; }
.bh-tilt img { position: relative; display: block; width: 100%; height: auto; border-radius: inherit; -webkit-user-drag: none; user-select: none; }
/* the slab: a darker plate a few px behind the art reads as the board's edge */
.bh-tilt::before { content: ""; position: absolute; inset: 0; border-radius: inherit; background: #030814; transform: translate3d(0, 3px, -9px); }
.bh-tilt::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; transform: translateZ(.5px);
  box-shadow: inset 1px 1px 0 rgba(var(--gold-rgb), .32), inset -1px -1px 0 rgba(0, 0, 0, .5); }
.bh-shadow { position: absolute; left: 20%; right: 20%; bottom: 4%; height: 22%; pointer-events: none; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(0, 0, 0, .55), rgba(0, 0, 0, .18) 60%, transparent); transform: translateZ(-80px); }
:root[data-theme="light"] .bh-shadow { background: radial-gradient(closest-side, rgba(70, 50, 20, .34), rgba(70, 50, 20, .1) 60%, transparent); }
@keyframes bhFloat { 0%, 100% { translate: 0 0; } 50% { translate: 0 -8px; } }
@keyframes bhShadow { 0%, 100% { scale: 1; opacity: 1; } 50% { scale: .93; opacity: .78; } }
#board[data-tier="1"] .bh-float { animation: bhFloat 5.7s ease-in-out infinite; }
#board[data-tier="1"] .bh-shadow { animation: bhShadow 5.7s ease-in-out infinite; }
#board.is-off .bh-float, #board.is-off .bh-shadow { animation-play-state: paused; }
#board.bh-still .bh-float, #board.bh-still .bh-shadow { animation: none; }
/* tiers 2-3: the WebGL board fills the stage and fades in over the poster */
/* full-bleed: the page's whole width (hero3d.js sets left and width) and a little above and
   below the stage, with soft edges, so a zoomed board grows past the stage and melts into the
   page instead of meeting a hard edge. The fit at 1x is still the stage's. */
.bh-canvas {
  position: absolute; left: 0; top: -7%; width: 100%; height: 114%; opacity: 0; transition: opacity .7s ease; pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 9%, #000 91%, transparent), linear-gradient(to right, transparent, #000 3%, #000 97%, transparent);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to bottom, transparent, #000 9%, #000 91%, transparent), linear-gradient(to right, transparent, #000 3%, #000 97%, transparent);
  mask-composite: intersect;
}
.bh-3d-on .bh-canvas { opacity: 1; }
.bh-3d-on .bh-float, .bh-3d-on .bh-shadow { opacity: 0; animation: none; }
.bh-3d .bh-float, .bh-3d .bh-shadow { animation: none; }
/* the part under the pointer: its designator pinned over it (3D only) */
.bh-tag {
  position: absolute; left: 0; top: 0; z-index: 2; pointer-events: none; opacity: 0; white-space: nowrap;
  padding: 5px 10px; border-radius: 999px; font: 500 var(--t-xs)/1 var(--mono); letter-spacing: .02em; color: #F3E3BC;
  background: rgba(7, 13, 26, .88); box-shadow: 0 0 0 1px rgba(201, 164, 92, .45), 0 8px 20px rgba(0, 0, 0, .35);
  transition: opacity var(--d-instant) linear;
}
.bh-tag.is-on { opacity: 1; }
/* the bar under the stage */
.bs-bar { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-top: 12px; }
.bs-hint { margin: 0; color: var(--fg-3); font-size: var(--t-s); transition: color var(--d-base) var(--ease-out); }
.bs-hint.is-flash { color: var(--gold-hi); }
:root[data-theme="light"] .bs-hint.is-flash { color: var(--gold); }
/* the zoom buttons only mean something on the 3D board */
#board:not(.bh-3d-on) .bs-zoom { visibility: hidden; }
.bs-zoom { display: flex; gap: 8px; flex: none; }
.bs-b {
  display: grid; place-items: center; width: 44px; height: 44px; padding: 0; border: 0; border-radius: var(--r-s); cursor: pointer;
  color: var(--fg); background: var(--card-fill); box-shadow: var(--card-shadow); transition: box-shadow var(--d-fast) var(--ease-out), translate var(--d-fast) var(--ease-out);
}
.bs-b svg { width: 18px; height: 18px; }
.bs-b:active { scale: .97; }
.bs-b:focus-visible { outline: 2px solid var(--gold-hi); outline-offset: 2px; }
.bs-b:disabled { opacity: .4; cursor: default; }
@media (hover: hover) and (pointer: fine) { .bs-b:not(:disabled):hover { translate: 0 -1px; box-shadow: var(--card-shadow), inset 0 0 0 1px rgba(var(--gold-rgb), .55); } }
/* the readout and the legend */
.bs-info { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: clamp(18px, 2.6vw, 32px); margin-top: clamp(20px, 2.6vw, 32px); align-items: start; }
.bs-read { position: relative; border-radius: var(--card-radius); background: var(--card-fill); box-shadow: var(--card-shadow); padding: clamp(18px, 2.2vw, 26px); }
.bs-read::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none; background: var(--mat-rim);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude;
}
.bs-ref { margin: 0 0 10px; font: 500 var(--t-xs)/1.2 var(--mono); letter-spacing: .03em; color: var(--fg-3); }
.bs-title { margin: 0 0 8px; font-size: var(--t-xl); font-weight: 600; letter-spacing: -.018em; line-height: 1.15; }
.bs-sub { margin: 0 0 18px; color: var(--fg-2); font-size: var(--t-s); line-height: 1.55; }
.bs-acts { display: flex; flex-wrap: wrap; gap: 8px; }
.bs-legend { display: grid; grid-template-columns: 1.35fr 1fr 1fr; gap: 18px clamp(16px, 2vw, 28px); }
.bs-gl { margin: 0 0 8px; color: var(--fg-3); font-size: var(--t-s); }
.bs-legend ul { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; }
.bs-p {
  display: flex; align-items: baseline; gap: 10px; min-height: 36px; padding: 8px 10px; border-radius: 10px;
  color: var(--fg-2); text-decoration: none; transition: background-color var(--d-fast) var(--ease-out), color var(--d-fast) var(--ease-out);
}
.bs-p:hover, .bs-p.is-sel { color: var(--fg); background: rgba(var(--gold-rgb), .1); }
.bs-p:focus-visible { outline: 2px solid var(--gold-hi); outline-offset: 1px; }
.bs-id { flex: none; min-width: 3.4em; font: 500 var(--t-xs)/1.3 var(--mono); color: var(--fg-3); }
.bs-p.is-sel .bs-id { color: var(--gold-hi); }
:root[data-theme="light"] .bs-p.is-sel .bs-id { color: var(--gold); }
.bs-t { font-size: var(--t-s); line-height: 1.35; }
@media (pointer: coarse) { .bs-p { min-height: 44px; align-items: center; } }
@media (max-width: 990px) {
  .bs-info { grid-template-columns: 1fr; }
  .bs-legend { grid-template-columns: 1fr 1fr; }
  .bs-g-work { grid-column: 1 / -1; }
  .bs-g-work ul { grid-template-columns: 1fr 1fr; column-gap: 12px; }
}
@media (max-width: 620px) {
  .board-hero { aspect-ratio: 1 / 1; max-height: 86svh; }
  .bh-float { width: 94%; transform: rotateX(26deg) rotateZ(-7deg); }
  .bs-legend, .bs-g-work ul { grid-template-columns: 1fr; }
  .bs-hint { font-size: var(--t-xs); }
}
@media (prefers-reduced-motion: reduce) { .bh-float, .bh-shadow { animation: none !important; } }

/* ---- the certificates strip (beyond.html, under the smaller competitions) ----
   The certificate photos, small, in one row of equal 4:3 frames (each
   filled edge to edge, like the case galleries); a click opens the whole
   certificate at its real proportions in the lightbox (their own group). */
.cert-strip { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(10px, 1.4vw, 16px); margin-top: clamp(18px, 2.4vw, 26px); }
.cert-strip .shot { margin: 0; max-width: none; border-radius: var(--r-s); transition: box-shadow var(--d-fast) var(--ease-out), translate var(--d-fast) var(--ease-out); }
.cert-strip .shot img { aspect-ratio: 4 / 3; height: auto; object-fit: cover; }
.cert-strip .shot figcaption { padding: 9px 12px; font-size: var(--t-xs); line-height: 1.35; }
@media (hover: hover) and (pointer: fine) { .cert-strip .shot:hover { translate: 0 -1px; box-shadow: 0 0 0 1px rgba(var(--gold-rgb), .5), var(--shadow-md); } }
.cert-strip .shot img:focus-visible { outline: 2px solid var(--gold-hi); outline-offset: -2px; }
@media (max-width: 720px) {
  .cert-strip { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 44%; overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: 6px; scrollbar-width: thin; }
  .cert-strip .shot { scroll-snap-align: start; }
}
