/* ============================================================
   Youssef Khoury — Analyst portfolio v2
   Single dark theme: warm charcoal + amber, terminal chrome
   ============================================================ */

:root {
  --bg: #100E0C;
  --surface: #191512;
  --surface-2: #14100D;
  --line: #322A24;
  --ink: #ECE3D6;
  --muted: #ADA192;
  --faint: #9C9080;
  --accent: #E8B15A;
  --accent-2: #C97F4B;

  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --display: "Chivo", "Inter", system-ui, sans-serif;
  --body: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;

  --shell: min(100% - 48px, 1200px);
  --ease: cubic-bezier(.22, .61, .36, 1);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; overflow-x: clip; scrollbar-gutter: stable both-edges; }

body {
  margin: 0;
  max-width: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--body);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: fixed; z-index: 999; top: 10px; left: 10px; padding: 9px 14px;
  background: var(--accent); color: #1a1204; border-radius: 6px;
  font-family: var(--mono); font-size: 12px; transform: translateY(-160%);
}
.skip-link:focus { transform: none; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.shell { width: var(--shell); margin-inline: auto; }

.mono {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

/* ---------- decorative layers ---------- */
.grain {
  position: fixed; inset: 0; z-index: 200; pointer-events: none;
  opacity: 0.05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.frame {
  position: fixed; z-index: 150; width: 15px; height: 15px;
  border: 1px solid var(--faint); pointer-events: none;
}
.frame.tl { top: 13px; left: 13px; border-right: 0; border-bottom: 0; }
.frame.tr { top: 13px; right: 13px; border-left: 0; border-bottom: 0; }
.frame.bl { bottom: 13px; left: 13px; border-right: 0; border-top: 0; }
.frame.br { bottom: 13px; right: 13px; border-left: 0; border-top: 0; }

.scroll-progress {
  position: fixed; top: 0; left: 0; z-index: 130;
  width: 0; height: 2px; background: var(--accent);
  box-shadow: 0 0 8px color-mix(in srgb, var(--accent) 60%, transparent);
  will-change: width;
}

/* ---------- top bar ---------- */
.topbar {
  position: sticky; top: 0; z-index: 100;
  /* mostly see-through at rest so the hero fog drifts behind the nav */
  background: color-mix(in srgb, var(--bg) 55%, transparent);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid transparent;
  transition: border-color .25s ease, background .25s ease;
}
/* once past the hero, go opaque again for legibility over real content */
.topbar.scrolled {
  border-color: var(--line);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
}
.topbar .shell { display: flex; align-items: center; justify-content: space-between; height: 54px; }
.topbar .id { color: var(--ink); font-size: 11px; letter-spacing: 0.1em; }
.topbar .id b { color: var(--accent); font-weight: 600; }
.topbar .topnav { position: relative; display: flex; gap: 26px; }
.topbar .topnav a {
  position: relative; color: var(--muted); padding: 6px 9px;
  transition: color .2s ease;
}
.topbar .topnav a:hover, .topbar .topnav a.active { color: var(--ink); }
/* corner brackets — only on the hovered / active link */
.topbar .topnav a::before, .topbar .topnav a::after {
  content: ""; position: absolute; width: 6px; height: 6px;
  border: 1px solid var(--accent); opacity: 0; transition: opacity .2s ease;
}
.topbar .topnav a::before { top: 0; left: 0; border-right: 0; border-bottom: 0; }
.topbar .topnav a::after { bottom: 0; right: 0; border-left: 0; border-top: 0; }
.topbar .topnav a:hover::before, .topbar .topnav a:hover::after,
.topbar .topnav a.active::before, .topbar .topnav a.active::after { opacity: 1; }

.index-btn {
  position: relative;
  display: inline-flex; align-items: center; padding: 5px 12px;
  background: transparent; border: 0; border-radius: 0;
  color: var(--ink); font-size: 11px; letter-spacing: 0.06em;
  cursor: pointer; transition: color .2s ease;
}
/* corner brackets instead of a box: top-left + bottom-right */
.index-btn::before, .index-btn::after {
  content: ""; position: absolute; width: 7px; height: 7px;
  border: 1px solid color-mix(in srgb, var(--accent) 58%, transparent);
  transition: border-color .2s ease;
}
.index-btn::before { top: 0; left: 0; border-right: 0; border-bottom: 0; }
.index-btn::after { bottom: 0; right: 0; border-left: 0; border-top: 0; }
.index-btn:hover,
.index-btn[aria-expanded="true"] { color: var(--accent); }
.index-btn:hover::before, .index-btn:hover::after,
.index-btn[aria-expanded="true"]::before,
.index-btn[aria-expanded="true"]::after { border-color: var(--accent); }

/* ---------- mobile section strip (shown only < 720px, after the hero) ---------- */
.secnav { display: none; }

/* ---------- full-screen index overlay (game-menu style) ---------- */
.overlay {
  position: fixed; inset: 0; z-index: 300;
  background: color-mix(in srgb, var(--bg) 96%, transparent);
  backdrop-filter: blur(3px);
  opacity: 0; visibility: hidden;
  overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
  transform: translateY(-10px); transform-origin: top center;
  transition: opacity .34s var(--ease), transform .34s var(--ease), visibility .34s;
  scrollbar-width: thin;
  scrollbar-color: var(--accent-2) var(--surface-2);
}
.overlay::-webkit-scrollbar { width: 10px; }
.overlay::-webkit-scrollbar-track { background: var(--surface-2); }
.overlay::-webkit-scrollbar-thumb { background: var(--accent-2); border: 2px solid var(--surface-2); }
.overlay::-webkit-scrollbar-thumb:hover { background: var(--accent); }
.overlay.open { opacity: 1; visibility: visible; transform: translateY(0); }
html.menu-open .topbar {
  /* sticky stops tracking the viewport once the scroll container is locked with
     overflow:hidden (mobile Safari/Chrome), so Close scrolls away with the page.
     Pin it instead and backfill the 55px it leaves in flow, so nothing shifts. */
  position: fixed; top: 0; left: 0; right: 0;
  z-index: 400;
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  border-color: var(--line);
}
html.menu-open body { padding-top: 55px; }
/* one exit at a time: the menu owns the screen, back-to-top waits */
html.menu-open .to-top { opacity: 0; transform: translateY(14px); pointer-events: none; }
/* lock the page scrollbar while the menu is open — one scroll area, not two.
   scrollbar-gutter: stable both-edges keeps the gutter reserved, so nothing reflows */
html.menu-open, html.menu-open body { overflow: hidden; }
.ov-inner {
  width: var(--shell); margin-inline: auto; min-height: 100%;
  display: grid; grid-template-columns: 1fr 300px; gap: 48px; align-content: center;
  padding-block: 80px;
}

.ov-nav { display: flex; flex-direction: column; }
.ov-nav a {
  position: relative;
  display: flex; align-items: baseline; gap: 18px;
  padding: 14px 12px; border-bottom: 1px solid var(--line);
  font-family: var(--display); font-weight: 600; font-size: clamp(26px, 4.4vw, 44px);
  letter-spacing: -0.02em; color: var(--ink);
  opacity: 0; transform: translateX(-14px);
  transition: opacity .3s var(--ease), transform .3s var(--ease), color .2s ease;
}
.ov-nav a i { font-size: 13px; font-style: normal; color: var(--faint); font-weight: 400; }
.ov-nav a:hover, .ov-nav a:focus-visible { color: var(--accent); }
/* corner-lock: brackets snap inward onto the hovered / focused entry */
.ov-nav a::before, .ov-nav a::after {
  content: ""; position: absolute; width: 16px; height: 16px;
  border: 1.5px solid var(--accent); opacity: 0; pointer-events: none;
  transition: opacity .2s ease, transform .28s var(--ease);
}
.ov-nav a::before { top: 8px; left: 0; border-right: 0; border-bottom: 0; transform: translate(-10px, -10px); }
.ov-nav a::after { bottom: 8px; right: 0; border-left: 0; border-top: 0; transform: translate(10px, 10px); }
.ov-nav a:hover::before, .ov-nav a:hover::after,
.ov-nav a:focus-visible::before, .ov-nav a:focus-visible::after { opacity: 1; transform: translate(0, 0); }
.overlay.open .ov-nav a { opacity: 1; transform: none; }
.overlay.open .ov-nav a:nth-child(1) { transition-delay: .08s; }
.overlay.open .ov-nav a:nth-child(2) { transition-delay: .12s; }
.overlay.open .ov-nav a:nth-child(3) { transition-delay: .16s; }
.overlay.open .ov-nav a:nth-child(4) { transition-delay: .20s; }
.overlay.open .ov-nav a:nth-child(5) { transition-delay: .24s; }
.overlay.open .ov-nav a:nth-child(6) { transition-delay: .28s; }
.overlay.open .ov-nav a:nth-child(7) { transition-delay: .32s; }

.ov-side { display: flex; flex-direction: column; gap: 16px; align-self: center; color: var(--muted); opacity: 0; transition: opacity .4s ease .3s; }
.overlay.open .ov-side { opacity: 1; }
.ov-side > div { display: flex; flex-direction: column; gap: 4px; }
.ov-side span { font-size: 11px; letter-spacing: 0.16em; color: var(--faint); }
.ov-side b { font-size: 12px; font-weight: 500; color: var(--ink); font-variant-numeric: tabular-nums; }
.ov-social { flex-direction: column !important; gap: 6px !important; margin-top: 6px; }
.ov-social a { display: flex; gap: 8px; font-size: 12px; letter-spacing: 0.06em; color: var(--muted); }
.ov-social a .ar { color: var(--accent); }
.ov-social a:hover { color: var(--ink); }
.ov-stamp { font-size: 11px; letter-spacing: 0.14em; color: var(--faint); margin: 8px 0 0; }

/* ---------- reveal (only hidden once JS confirms it can un-hide them) ---------- */
.js .reveal { opacity: 0; transform: translateY(20px); transition: opacity .6s var(--ease), transform .6s var(--ease); }
.js .reveal.visible { opacity: 1; transform: none; }

/* section-aware scroll reveal: headings wipe in as you reach them */

/* small amber section labels type-wipe left to right */
.js .sec-head.reveal .sk,
.js .sec-head.reveal > span:first-child {
  clip-path: inset(0 105% 0 -2px);
  transition: clip-path .7s var(--ease);
}
.js .sec-head.reveal.visible .sk,
.js .sec-head.reveal.visible > span:first-child { clip-path: inset(0 -2px 0 -2px); }
.js .sec-head.reveal > span:last-child { opacity: 0; transition: opacity .5s ease .28s; }
.js .sec-head.reveal.visible > span:last-child { opacity: 1; }

/* large display headings clip-wipe + rise */
.js .flag-copy.reveal h2 {
  clip-path: inset(0 100% 0 0); transform: translateY(14px);
  transition: clip-path .8s var(--ease), transform .8s var(--ease);
}
.js .flag-copy.reveal.visible h2 { clip-path: inset(0 0 0 0); transform: none; }

/* cascade the two credential cards instead of popping together */
.js .cred-grid .cert.reveal:nth-child(2) { transition-delay: .12s; }

/* ---------- one-time hero boot sequence (~950ms, once per session) ---------- */
html.booting .frame { animation: bootFrame .32s var(--ease) both; }
html.booting .dsr-photo > img { animation: bootWipe .4s var(--ease) .16s both; }
html.booting .hero .reveal { transition: none; }
html.booting .hero-copy > * { animation: bootIn .34s var(--ease) both; }
html.booting .hero-copy > :nth-child(1) { animation-delay: .42s; }
html.booting .hero-copy > :nth-child(2) { animation-delay: .50s; }
html.booting .hero-copy > :nth-child(3) { animation-delay: .58s; }
html.booting .hero-copy > :nth-child(4) { animation-delay: .66s; }
html.booting .hero-copy > :nth-child(5) { animation-delay: .74s; }
html.booting .hero-copy > :nth-child(6) { animation-delay: .82s; }
html.booting .hero-copy > :nth-child(7) { animation-delay: .90s; }
html.booting .idcard .dsr-body { animation: bootIn .34s var(--ease) .5s both; }

@keyframes bootFrame { from { transform: scale(0); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes bootWipe {
  from { clip-path: inset(0 0 100% 0); }
  to { clip-path: inset(0 0 0 0); }
}
@keyframes bootIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

/* ---------- hero ---------- */
/* pull the hero up under the sticky topbar so the drifting fog fills the
   top strip behind the nav; hero-grid padding compensates so nothing shifts */
.hero { position: relative; overflow: hidden; border-bottom: 1px solid var(--line); margin-top: -54px; }
.hero canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; pointer-events: none; }
/* atmospheric drifting fog — rendered low-res and softened so it reads as
   haze, not pixels; denser toward the hero's outer edges (see script.js) */
/* no CSS filter here: it forces a full-layer GPU pass every animation frame,
   which is what dropped desktop scroll below 60fps. The 2x buffer upscale
   already softens the dots. */
/* the buffer extends past the hero edges (clipped by .hero's overflow:hidden)
   so the drifting grid never exposes a black strip at the left/right borders
   when the wave shoves the outermost dots inward — see fOverX/fOverY in script.js */
.hero #herofog { opacity: .52; inset: -6% -7%; width: auto; height: auto; }
/* a faint fixed amber wash so the hero never reads as flat black */
.hero::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(80% 60% at 15% 20%, rgba(232, 177, 90, .06), transparent 60%),
    radial-gradient(80% 60% at 85% 30%, rgba(224, 150, 70, .05), transparent 60%),
    radial-gradient(90% 70% at 50% 95%, rgba(232, 177, 90, .05), transparent 65%);
}
.hero-grid {
  position: relative; z-index: 1;
  display: grid; grid-template-columns: auto 1fr; gap: clamp(34px, 4.5vw, 60px); align-items: center;
  padding-top: calc(54px + clamp(40px, 6vw, 66px)); padding-bottom: clamp(52px, 9vw, 88px);
}
/* the case-file card is desktop-only, so on a phone the portrait comes back
   here as a small medallion above the eyebrow */
.hero-avatar { display: none; }

.eyebrow { color: var(--faint); margin: 0 0 20px; }
h1 {
  font-family: "Roboto Flex", var(--display); font-weight: 700;
  font-size: clamp(34px, 5.6vw, 64px); line-height: 1.03; letter-spacing: -0.025em;
  text-wrap: balance; margin: 0 0 22px; max-width: 17ch;
}
h1 em { font-style: normal; color: var(--accent); }
/* pressure-type: per-letter spans that bulge toward the cursor (desktop, motion-safe) */
.hero-copy h1 { cursor: default; user-select: none; -webkit-user-select: none; }
h1 .tp-word { display: inline-block; white-space: nowrap; }
h1 .tp-ch {
  display: inline-block; will-change: font-variation-settings;
  font-variation-settings: "wght" 700, "wdth" 100;
}

/* birthdate stamp, upper-right of the hero — same pressure-type morph as the headline */
.birthdate {
  position: absolute; z-index: 2; top: 19%; right: clamp(14px, 4.5vw, 60px);
  font-family: var(--mono); font-weight: 500;
  font-size: 10.5px; letter-spacing: 0.16em; color: var(--faint);
  pointer-events: none; user-select: none; -webkit-user-select: none;
}
.birthdate .tp-word { display: inline-block; white-space: nowrap; }
.birthdate .tp-ch { display: inline-block; }
@media (max-width: 900px) { .birthdate { display: none; } }

.lead { color: var(--muted); max-width: 56ch; margin: 0 0 32px; font-size: 15.5px; }

.actions { display: flex; flex-wrap: wrap; gap: 14px 28px; }
.actions a, .actions button {
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--ink); background: none; border: 0; border-bottom: 1px solid var(--line);
  padding: 0 0 4px; cursor: pointer; transition: border-color .2s ease;
}
.actions a:hover, .actions button:hover { border-color: var(--accent); }
.actions .ar { color: var(--accent); display: inline-block; }

/* larger arrow glyph; alignment (the hover-slide lives after the component rules below).
   line-height 1 clips the ↗ head on some faces, so give the glyph its own room. */
.idlinks a .ar, .ov-social a .ar, .actions .ar, .case-links a .ar {
  font-size: 15px; line-height: 1.25; align-self: center; overflow: visible;
}
.idlinks a, .ov-social a { align-items: center; }
.actions a, .actions button { display: inline-flex; align-items: center; gap: 7px; }
/* arrow trails the label, so every link's text starts at the same left edge */
.idlinks a .ar, .ov-social a .ar, .actions a .ar, .actions button .ar, .case-links a .ar {
  order: 9; margin: 0;
}

.stackline { color: var(--faint); margin: 34px 0 0; font-size: 11px; }

/* hero "how I work" method row */
.method {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px 28px;
  margin: 10px 0 30px; max-width: 860px;
}
.method > div { display: flex; flex-direction: column; gap: 8px; }
.method > div:nth-child(2) { transition-delay: .07s; }
.method > div:nth-child(3) { transition-delay: .14s; }
.method span.mono { font-size: 11px; color: var(--accent); letter-spacing: 0.16em; }
.method p { margin: 0; color: var(--muted); font-size: 12.5px; line-height: 1.55; }

/* ---------- hero case-file card ----------
   one proportional system: every dimension below is in `em`, and the single
   font-size knob on .idcard scales the whole card as one unit. */
.idcard {
  position: relative;
  /* the two knobs that set the card's proportions: a bigger type scale keeps
     the copy legible, a shorter photo keeps the card the height of the text
     column beside it */
  --photo-h: 23em;
  --seam: calc(var(--photo-h) - 3.2em);
  width: 35em;
  margin-inline: auto;
  margin-top: 24px;
  font-size: clamp(8px, 0.36vw + 6.6px, 11.6px);
}
.casecard {
  position: relative; width: 100%; overflow: hidden;
  background: linear-gradient(180deg, var(--surface), var(--surface-2));
  border: 1px solid color-mix(in srgb, var(--accent) 55%, var(--line));
  border-radius: 0 1.6em 1.6em 1.6em;   /* square top-left so the tab's edges continue the card's as one line */
  box-shadow: 0 1.6em 3.6em rgba(0, 0, 0, .3);
}

/* one L-bracket only: a registration mark mirroring the photo's top-right
   corner mark (.dsr-photo::after) across the diagonal — same 1em inset, opposite
   (bottom-left) corner, opening up-right so the two read as a facing pair */
.dsr-frame { position: absolute; inset: 0; pointer-events: none; z-index: 6; }
.dsr-frame::before {
  content: ""; position: absolute; width: 1.15em; height: 1.15em;
  border: 0 solid var(--accent); opacity: .7;
  left: 1em; top: calc(var(--seam) - 2.15em);
  border-left-width: 1px; border-bottom-width: 1px;
}

/* folder tab — sealed flush onto the card's top edge: the tab's bottom sits
   exactly on the card's top border (no overlap, no gap), so the two borders
   meet in one clean line instead of a stray corner past the seam */
.dsr-tab {
  position: absolute; top: -2.95em; left: 0; z-index: 5;
  display: flex; align-items: center; gap: 0.7em;
  height: 2.95em; padding: 0 1.5em 0 1.35em;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--accent) 55%, var(--line));
  border-bottom: 0;
  border-radius: 0;                     /* square top: the file reads as sealed */
  font-size: 0.92em; letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--accent); white-space: nowrap;
}
.dsr-tab b { color: var(--faint); font-weight: 500; margin: 0 0.15em; }
.dsr-tab svg { flex: none; width: 1.55em; height: 1.3em; color: var(--accent); }

/* vertical caption up the right edge */
.dsr-side {
  position: absolute; top: 5.5em; right: 1.7em; z-index: 4;
  writing-mode: vertical-rl; text-orientation: mixed;
  display: flex; align-items: center; gap: 0.9em;
  font-size: 0.8em; letter-spacing: 0.34em; text-transform: uppercase; color: var(--faint);
}
.dsr-side::before { content: "\2022"; color: var(--accent); font-size: 1.6em; line-height: 1; }
.dsr-side::after {
  content: ""; width: 1px; height: 7em;
  background: color-mix(in srgb, var(--accent) 45%, transparent);
}

/* understated gold dot texture */
.dsr-dots {
  position: absolute; z-index: 3; pointer-events: none;
  background-image: radial-gradient(color-mix(in srgb, var(--accent) 40%, transparent) 0.6px, transparent 1.1px);
  background-size: 0.8em 0.8em;
}
.dsr-dots-a { top: 3em; left: 1.3em; width: 4.6em; height: 7em; opacity: .32; }
.dsr-dots-b { right: 1.9em; bottom: 7em; width: 4em; height: 5em; opacity: .28; }

/* portrait — fills the frame, warm glow behind the subject */
.dsr-photo {
  position: relative; height: var(--photo-h); overflow: hidden;
  border-radius: 0 1.5em 0 0; background: var(--surface-2);
}
.dsr-photo::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(44% 38% at 50% 60%, color-mix(in srgb, var(--accent) 26%, transparent), transparent 70%),
    radial-gradient(82% 66% at 50% 50%, color-mix(in srgb, var(--accent-2) 16%, transparent), transparent 80%);
}
.dsr-photo img {
  /* anchored to the bottom, so shrinking the width is what opens headroom at
     the top — at 65% the hair was clipped flush against the card's border */
  position: absolute; z-index: 1; bottom: 0; left: 50%;
  width: 58%; height: auto; transform: translateX(-50%);
  object-fit: contain; object-position: 50% 100%;
  filter: grayscale(1) contrast(1.06) brightness(.97);
  pointer-events: none; user-select: none; -webkit-user-drag: none;
}
.dsr-photo::after {
  content: ""; position: absolute; z-index: 2; right: 1em; top: 1em;
  width: 0.9em; height: 0.9em;
  border-right: 1px solid var(--accent); border-top: 1px solid var(--accent); opacity: .65;
}

/* level seam across the panel's top edge */
.dsr-seam {
  position: absolute; z-index: 4; left: 0; top: var(--seam); width: 100%; height: 0;
  border-top: 1.5px solid color-mix(in srgb, var(--accent) 55%, transparent);
  pointer-events: none;
}

/* information panel — flat top edge picks up the seam */
.dsr-body {
  position: relative; z-index: 2;
  margin-top: -3.2em; padding: 2.6em 2.3em 2.1em;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
  background: var(--surface);
}
.dsr-name {
  font-family: var(--display); font-weight: 800; font-size: 2.5em; line-height: 1;
  letter-spacing: 0.055em; text-transform: uppercase; color: var(--ink);
  margin: 0; max-width: none; white-space: nowrap;
}
.dsr-role  { color: var(--accent); font-size: 1em; letter-spacing: 0.16em; text-transform: uppercase; margin: 0.8em 0 0; }
.dsr-role2 { color: var(--ink); font-size: 1em; letter-spacing: 0.34em; text-transform: uppercase; margin: 0.32em 0 0; opacity: .9; }

.dsr-rule {
  display: block; position: relative; width: 60%; height: 1px; margin: 1.5em 0 1.5em;
  background: color-mix(in srgb, var(--accent) 22%, transparent);
}
.dsr-rule::before {
  content: ""; position: absolute; left: 0; top: -1.5px; width: 3.4em; height: 4px; background: var(--accent);
}

/* metadata — icon · label · leader · value */
.dsr-meta { display: grid; gap: 1.6em; margin: 0.2em 0 0; }
.dsr-meta > div {
  display: flex; align-items: center; gap: 0.9em;
  font-size: 1em; letter-spacing: 0.12em; text-transform: uppercase;
}
.dsr-ic { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 1.7em; height: 1.7em; color: var(--accent); line-height: 1; }
.dsr-ic svg { display: block; width: 100%; height: 100%; }
.dsr-meta dt { flex: none; color: var(--muted); margin: 0; }
.dsr-meta dt::after { content: "\00a0\00a0:"; color: var(--faint); }
.dsr-led { flex: 1; height: 0; border-bottom: 1px dotted color-mix(in srgb, var(--accent) 40%, transparent); }
.dsr-meta dd { flex: none; color: var(--ink); margin: 0; }
.dsr-meta dd.ok { color: var(--accent); }

/* footer links — icon · label · arrow, evenly split */
.dsr-links {
  display: flex; align-items: stretch; margin: 1.9em 0 0; padding: 1.4em 0 0;
  border-top: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
}
.dsr-links a {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 0.55em;
  font-size: 1em; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted);
  transition: color .2s ease;
}
.dsr-links a + a { border-left: 1px solid color-mix(in srgb, var(--accent) 20%, transparent); }
.dsr-links a:hover { color: var(--ink); }
.dsr-links svg { flex: none; width: 1.5em; height: 1.5em; color: var(--faint); transition: color .2s ease; }
.dsr-links a:hover svg { color: var(--accent); }

/* ---------- skills marquee ---------- */
.skillstrip {
  border-block: 1px dashed color-mix(in srgb, var(--accent) 42%, transparent);
  padding: 20px 0;
  display: grid; gap: 10px;
  overflow: hidden;
}
.marquee {
  display: flex; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}
.mq-track {
  flex: 0 0 auto; min-width: 100%;
  display: flex; justify-content: space-around; align-items: center;
  margin: 0; padding: 0; list-style: none;
  animation: mq-scroll 44s linear infinite;
}
.marquee.rev .mq-track { animation-direction: reverse; animation-duration: 54s; }
.marquee:hover .mq-track { animation-play-state: paused; }
.mq-track li {
  position: relative; white-space: nowrap; padding: 4px 30px;
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--muted);
  transition: color .25s ease;
}
.mq-track li::after {
  content: "/"; position: absolute; right: -2px;
  color: color-mix(in srgb, var(--accent) 55%, transparent);
}
.marquee:hover .mq-track li:hover { color: var(--accent); }
@keyframes mq-scroll { to { transform: translateX(-100%); } }

/* ---------- sections ---------- */
.section { padding-block: clamp(66px, 10vw, 108px); }
/* consecutive sections stack two large paddings — tighten the seam both sides */
.section + .section { padding-top: clamp(34px, 5vw, 54px); }
.section:has(+ .section) { padding-bottom: clamp(34px, 5vw, 54px); }
/* the dossier wraps flagship/credentials/experience, so the two rules above
   can't see across it and that one seam kept both full paddings — halve it too */
.section:has(+ .dossier) { padding-bottom: clamp(34px, 5vw, 54px); }
.dossier-body > .section:first-child { padding-top: clamp(34px, 5vw, 54px); }
.sec-head {
  position: relative;
  display: flex; justify-content: space-between; align-items: baseline;
  color: var(--muted); padding-bottom: 16px; margin-bottom: 26px;
}
.sec-head::after {
  content: ""; position: absolute; left: 0; bottom: 0; width: 100%; height: 1px;
  background: var(--line); transform: scaleX(1); transform-origin: left;
  transition: transform .6s var(--ease);
}
/* draw the divider in with the reveal, but only when JS can also un-hide it */
.js .sec-head.reveal:not(.visible)::after { transform: scaleX(0); }
.sec-head span:first-child { color: var(--accent); }
/* phone-only chrome: the metric row and the drawer front */
.sec-metrics { display: none; }
.drawer-front { display: none; }
/* section label doubles as the a11y/SEO heading — keep it visually a label */
.sec-head h2.sk {
  font: inherit; margin: 0; color: var(--accent); font-weight: 400;
  letter-spacing: inherit; text-transform: inherit;
}

h2 {
  font-family: var(--display); font-weight: 700;
  font-size: clamp(23px, 3.1vw, 32px); line-height: 1.1; letter-spacing: -0.02em;
  text-wrap: balance; margin: 0 0 16px; max-width: 26ch;
}

/* ---------- work rows ---------- */
#work { --case-rise: 52px; --case-tilt: 7deg; }
#work .shell { position: relative; }

/* scroll rail down the left of the list; fill tracks progress through the section */
.work-rail {
  position: absolute; left: -2px; top: 128px; bottom: 56px; width: 2px;
  background: none; pointer-events: none;
}
.work-rail span {
  position: absolute; left: 0; top: 0; width: 2px; height: var(--rail, 0%);
  background: var(--accent);
  box-shadow: 0 0 12px color-mix(in srgb, var(--accent) 55%, transparent);
  transition: height .12s linear;
}

.work-intro {
  color: var(--muted); font-size: 14px; line-height: 1.7;
  max-width: 70ch; margin: 2px 0 6px;
}

.case-item { position: relative; max-width: 1080px; border-bottom: 1px solid var(--line); }

/* scroll-scrubbed entrance: each case tilts up out of depth and settles as it
   scrolls into view. Native scroll-timeline only — GPU-composited, no JS. Browsers
   without it (Firefox / older Safari) keep the IntersectionObserver .reveal fade. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .js #work .shell { perspective: 1200px; }
    .js #work .case-item.reveal { opacity: 1; transform: none; transition: none; }
    .js #work .case-item {
      transform-origin: 50% 100%;
      animation: caseScrub linear both;
      animation-timeline: view();
      animation-range: entry 4% cover 22%;
    }
  }
}
@keyframes caseScrub {
  from { opacity: 0; transform: translateY(var(--case-rise)) rotateX(var(--case-tilt)) scale(.985); }
  to   { opacity: 1; transform: none; }
}

/* flagship case — marked only by the label, not a permanent highlight */
.case-item.flagship::before {
  content: "[ flagship ]";
  position: absolute; top: 18px; left: 54px; z-index: 2;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.22em;
  text-transform: uppercase; color: var(--accent);
}
.case-item.flagship .row { padding-top: 60px; }
.result {
  margin: 0 0 20px; font-size: 12px; line-height: 1.6;
  letter-spacing: 0.02em; color: var(--muted); max-width: 74ch;
}
.result b { color: var(--accent); font-weight: 600; }

.row {
  position: relative; width: 100%;
  display: grid; grid-template-columns: 168px 1fr 178px; column-gap: 40px; align-items: center;
  padding: 46px 6px 46px 54px;
  font: inherit; color: inherit; text-align: left;
  background: none; border: 0; cursor: pointer; -webkit-appearance: none; appearance: none;
  transition: background .3s var(--ease);
}
/* hover: a faded amber wash, no frame — fades out to the right */
.row:hover {
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--accent) 7%, transparent),
    color-mix(in srgb, var(--accent) 2%, transparent) 60%,
    transparent);
}

/* expandable case detail */
.js .case { overflow: hidden; height: 0; transition: height .38s var(--ease); }
.case-inner { padding: 0 6px 44px 262px; }
.js .case-inner { opacity: 0; transition: opacity .3s ease; }
.js .case.open > .case-inner { opacity: 1; }
/* case detail: one section at a time behind bracket tabs — the panel used to
   stack Situation / Built / Showed as three paragraphs, which nobody read */
.case-tabs { display: none; }
.js .case-tabs {
  display: flex; flex-wrap: wrap; gap: 26px;
  margin: 0 0 20px; padding-bottom: 12px; border-bottom: 1px solid var(--line);
}
.ct-tab {
  position: relative; padding: 0; background: none; border: 0; cursor: pointer;
  font: inherit; font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--faint); transition: color .22s ease;
}
.ct-tab::before,
.ct-tab::after { content: ""; opacity: 0; transition: opacity .22s ease; }
.ct-tab::before { content: "[ "; }
.ct-tab::after { content: " ]"; }
.ct-tab:hover { color: var(--ink); }
.ct-tab.on { color: var(--accent); }
.ct-tab.on::before, .ct-tab.on::after { opacity: 1; }
/* the seam under the active tab */
.ct-tab.on { box-shadow: 0 13px 0 -12px var(--accent); }

.ct-panels { margin: 0 0 22px; max-width: 74ch; }
.ct-panel { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.7; }
/* stack every panel in one grid cell so the container is sized by the tallest
   one — switching tabs then never reflows the case height */
.js .ct-panels { display: grid; }
.js .ct-panel {
  grid-area: 1 / 1; opacity: 0; visibility: hidden; transform: translateY(6px);
  transition: opacity .28s var(--ease), transform .28s var(--ease), visibility .28s;
}
.js .ct-panel.on { opacity: 1; visibility: visible; transform: none; }
/* no-JS: panels stack and read as plain paragraphs */
.ct-panel + .ct-panel { margin-top: 14px; }
.js .ct-panel + .ct-panel { margin-top: 0; }
.case-links { display: flex; flex-wrap: wrap; gap: 22px; font-size: 12px; }
.case-links a { color: var(--accent); display: inline-flex; align-items: center; gap: 7px; border-bottom: 1px solid transparent; padding-bottom: 2px; }
.row .chev {
  display: inline-block; width: 1em; text-align: center;
  font-size: 16px; line-height: 1; color: var(--accent);
  transition: transform .3s var(--ease);
}
.row[aria-expanded="true"] .chev { transform: rotate(45deg); }
.row[aria-expanded="true"] .go { opacity: 1; transform: none; }
.row[aria-expanded="true"] h3 { color: var(--accent); }

/* node on the rail — lights amber when this row is the one you're reading */
.row .node {
  position: absolute; left: -7px; top: 50%; width: 10px; height: 10px; margin-top: -5px;
  border-radius: 50%; background: var(--bg); border: 1.5px solid var(--faint); pointer-events: none;
  transition: border-color .3s ease, background .3s ease, box-shadow .3s ease, transform .3s var(--ease);
}
.row.rail-lit .node {
  border-color: var(--accent); background: var(--accent);
  box-shadow: 0 0 12px var(--accent); transform: scale(1.2);
}
.row.is-active .idx { color: var(--accent); }

.row .idx { color: var(--faint); display: block; margin-bottom: 14px; font-size: 13px; transition: color .3s ease; }
.row h3 {
  font-family: var(--display); font-weight: 600;
  font-size: clamp(20px, 2.6vw, 27px); letter-spacing: -0.015em; margin: 0 0 14px;
  transition: color .2s ease;
}
.row:hover h3 { color: var(--accent); }
.row .tags {
  font-size: 11px; letter-spacing: 0.1em; color: var(--muted); display: block; margin-bottom: 12px;
}
.row .tags b { color: var(--accent-2); font-weight: 500; }
/* separators live on the tag, not in the markup, so hiding a tag on a phone
   takes its dot with it */
.row .tags .t + .t::before { content: " · "; color: var(--faint); }
.case-dek {
  color: var(--muted); font-size: 13.5px; line-height: 1.65; margin: 0 0 16px; max-width: 74ch;
}
.case-inner .outcome {
  color: var(--ink); font-size: 13px; line-height: 1.6; margin: 0 0 22px; max-width: 74ch;
  padding-left: 12px; border-left: 2px solid var(--accent);
}
.case-inner .outcome .mono {
  color: var(--accent); font-size: 10px; letter-spacing: 0.16em; margin-right: 8px;
}

/* per-row staggered entrance */
.js .row.reveal h3 { opacity: 0; transform: translateY(18px); transition: opacity .5s var(--ease), transform .5s var(--ease); }
.js .row.reveal.visible h3 { opacity: 1; transform: none; }
.js .row.reveal .idx,
.js .row.reveal .tags,
.js .row.reveal .tags {
  opacity: 0; transform: translateY(8px);
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.js .row.reveal .tags { transition-delay: .08s; }
.js .row.reveal.visible .idx,
.js .row.reveal.visible .tags { opacity: 1; transform: none; }

.row .go {
  justify-self: start; align-self: center;
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
  color: var(--accent); font-size: 14px;
  opacity: 0; transform: translateX(-6px);
  transition: opacity .24s ease, transform .28s var(--ease);
}
.row:hover .go, .row:focus-visible .go { opacity: 1; transform: none; }
.row .go b {
  font-family: var(--mono); font-size: 11px; font-weight: 500;
  letter-spacing: 0.12em; text-transform: uppercase;
}
.row .go .ar { display: inline-block; }

.spark {
  display: block; width: 156px; height: 82px; color: var(--accent);
  transform-origin: left center;
  transition: transform .3s var(--ease), color .25s ease;
}
.row:hover .spark { transform: scale(1.05); color: #f3c274; }
.spark svg { width: 100%; height: 100%; overflow: visible; }
.spark polygon { fill: color-mix(in srgb, var(--accent) 15%, transparent); }
.spark polyline {
  fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round;
  stroke-dasharray: 320; stroke-dashoffset: 320; transition: stroke-dashoffset 1.1s var(--ease) .1s;
}
.reveal.visible .spark polyline { stroke-dashoffset: 0; }
.spark.bars rect {
  fill: currentColor; opacity: .5; transform-origin: bottom; transform: scaleY(0);
  transition: transform .5s var(--ease); transition-delay: .1s;
}
.spark.bars rect:nth-child(2) { transition-delay: .16s; }
.spark.bars rect:nth-child(3) { transition-delay: .22s; }
.spark.bars rect:nth-child(4) { transition-delay: .28s; }
.spark.bars rect:nth-child(5) { transition-delay: .34s; opacity: .85; }
.reveal.visible .spark.bars rect { transform: scaleY(1); }
.spark.gauge svg { overflow: visible; }
.spark.gauge circle { fill: none; stroke-width: 6; stroke-linecap: round; transform: rotate(-90deg); transform-origin: 64px 34px; }
.spark.gauge circle.track { stroke: var(--line); }
.spark.gauge circle.val {
  stroke: currentColor; stroke-dasharray: 76 100; stroke-dashoffset: 100;
  transition: stroke-dashoffset .9s var(--ease) .15s;
}
.reveal.visible .spark.gauge circle.val { stroke-dashoffset: 0; }
.spark.dots circle { fill: currentColor; opacity: .85; }
.spark.dots circle.hollow { fill: none; stroke: currentColor; stroke-width: 1.6; opacity: .5; }

/* desktop: Selected work as a 2×2 grid (01 02 / 03 04). Cards are set apart
   by whitespace, not rules. Each case opens inside its own cell so the detail
   appears right where it was clicked. Mobile keeps the single stack. */
@media (min-width: 900px) {
  .cases .case-item { max-width: none; }
  .cases .row {
    grid-template-columns: 92px minmax(0, 1fr) 132px;
    column-gap: 34px; align-items: center;
    padding: 24px 10px 24px 34px;
  }
  .cases .case-item.flagship .row { padding-top: 40px; }
  .cases .case-item.flagship::before { left: 34px; top: 12px; }
  .cases .spark { width: 84px; height: 34px; }
  .cases .row-body {
    display: grid; align-items: baseline;
    grid-template-columns: 40px minmax(0, 1fr) minmax(0, 40%);
    column-gap: 24px;
  }
  .cases .row .idx { margin: 0; }
  .cases .row h3 { margin: 0; font-size: clamp(17px, 1.65vw, 21px); }
  .cases .row .tags { margin: 0; justify-self: end; text-align: right; }
  .cases .case-inner { padding: 2px 10px 34px 224px; }
  .cases .case dl > div { grid-template-columns: 116px 1fr; gap: 16px; }
}

/* ---------- flagship ---------- */
.flag-grid { display: grid; grid-template-columns: .9fr 1.1fr; gap: 40px; align-items: start; margin-top: 8px; }
.flag-copy p { color: var(--muted); }
.flag-copy .actions { margin-top: 20px; flex-direction: column; align-items: flex-start; gap: 12px; }
.fineprint { color: var(--faint); font-size: 11px; margin-top: 20px; line-height: 1.6; }

.dashboard-window {
  border: 1px solid var(--line); border-radius: 12px; overflow: hidden;
  background: var(--surface-2); min-height: 460px; display: flex; flex-direction: column;
}
.window-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 11px 14px; border-bottom: 1px solid var(--line); color: var(--muted); font-size: 11px;
}
.window-bar span:first-child { color: var(--accent-2); letter-spacing: .2em; }
.window-bar a { color: var(--accent); }

.dash-stage { position: relative; flex: 1; display: flex; min-height: 420px; }
.dash-stage iframe {
  flex: 1; width: 100%; border: 0; background: var(--surface-2);
  opacity: 1; transition: opacity .4s ease, filter .4s ease;
}
.is-gated .dash-stage iframe { opacity: 0; }

/* blurred skeleton teaser shown until the visitor opts in */
.dash-skeleton {
  position: absolute; inset: 0; z-index: 1; padding: 26px;
  display: flex; flex-direction: column; gap: 18px;
  background: var(--surface-2);
  filter: blur(7px); opacity: .9;
  transition: opacity .35s ease;
}
.dash-skeleton > * , .dash-skeleton span { border-radius: 8px; background: linear-gradient(120deg, var(--surface), var(--line) 60%, var(--surface)); }
.dash-skeleton .sk-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; background: none; }
.dash-skeleton .sk-kpis span { height: 74px; }
.dash-skeleton .sk-kpis span:nth-child(2) { background: linear-gradient(120deg, color-mix(in srgb, var(--accent) 22%, var(--surface)), var(--line)); }
.dash-skeleton .sk-chart { flex: 1; min-height: 150px; }
.dash-skeleton .sk-split { display: grid; grid-template-columns: 1.4fr 1fr; gap: 14px; background: none; }
.dash-skeleton .sk-split span { height: 96px; }
.dashboard-window:not(.is-gated) .dash-skeleton { opacity: 0; pointer-events: none; }

/* the opt-in gate */
.dash-gate {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  background: color-mix(in srgb, var(--bg) 45%, transparent);
  border: 0; cursor: pointer; color: var(--ink);
  font-family: var(--mono); text-transform: uppercase;
  transition: opacity .3s ease;
}
.dash-gate .play {
  width: 60px; height: 60px; border-radius: 50%;
  border: 1.5px solid var(--accent); color: var(--accent);
  display: grid; place-items: center;
  transition: transform .25s var(--ease), background .25s ease;
}
.dash-gate:hover .play, .dash-gate:focus-visible .play {
  transform: scale(1.08); background: color-mix(in srgb, var(--accent) 14%, transparent);
}
.dash-gate .gate-label { font-size: 12px; letter-spacing: 0.16em; }
.dashboard-window:not(.is-gated) .dash-gate { opacity: 0; pointer-events: none; visibility: hidden; }

/* ---------- credentials ---------- */
.cred-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 10px; }
.cert {
  display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: 12px;
  overflow: hidden; background: var(--surface); transition: border-color .25s ease, transform .25s ease;
}
.cert:hover { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); transform: translateY(-3px); }
.cert-img { padding: 16px; background: var(--surface-2); border-bottom: 1px solid var(--line); }
.cert-img img { display: block; width: 100%; height: auto; border: 1px solid var(--line); }
.cert-copy { padding: 20px; }
.cert-copy > span { color: var(--accent); font-size: 11px; letter-spacing: .13em; }
.cert-copy h3 {
  font-family: var(--display); font-weight: 600; font-size: 17px; letter-spacing: -0.01em;
  margin: 10px 0 8px;
}
.cert-copy p { color: var(--muted); font-size: 13.5px; margin: 0 0 14px; }
.cert-copy .go { color: var(--accent); font-size: 11px; }
.edu {
  display: flex; gap: 18px; align-items: baseline; margin-top: 20px;
  padding: 16px 0 0; border-top: 1px solid var(--line); color: var(--muted); font-size: 11px;
}
.edu span { color: var(--faint); flex-shrink: 0; }
.edu p { margin: 0; text-transform: none; letter-spacing: 0; font-size: 13px; font-family: var(--body); }
.edu p b { color: var(--ink); font-weight: 600; }

/* ---------- experience ---------- */
.xrow {
  display: grid; grid-template-columns: 190px 1fr; gap: 26px;
  padding: 22px 0; border-bottom: 1px solid var(--line);
}
/* the last row's rule has nothing under it but the section's own edge */
.xrow:last-child { border-bottom: 0; }
.xr-when time { display: block; color: var(--muted); font-size: 11px; margin-bottom: 10px; }
.xr-when .bar { display: block; height: 3px; background: var(--line); position: relative; }
.xr-when .bar::after {
  content: ""; position: absolute; inset: 0 auto 0 0; width: var(--fill, 0%);
  background: var(--accent); transition: width .9s var(--ease) .1s;
}
.reveal .xr-when .bar::after { width: 0; }
.reveal.visible .xr-when .bar::after { width: var(--fill, 0%); }
.xr-body h3 {
  font-family: var(--display); font-weight: 600; font-size: 18px; letter-spacing: -0.01em;
  margin: 0 0 6px; display: flex; flex-wrap: wrap; gap: 10px; align-items: baseline;
}
.xr-body h3 .co { color: var(--accent-2); font-size: 11px; font-weight: 400; }
.xr-body p { color: var(--muted); font-size: 13.5px; margin: 0; max-width: 58ch; }

/* ---------- contact ---------- */
#contact { padding-top: clamp(44px, 6vw, 68px); padding-bottom: clamp(52px, 7vw, 78px); }
#experience { padding-bottom: clamp(40px, 6vw, 60px); }
/* closing block: headline left, the four routes out as borderless rows beside it */
.contact-clean {
  display: grid; grid-template-columns: minmax(260px, 0.85fr) minmax(420px, 1.15fr);
  gap: clamp(28px, 5vw, 64px); align-items: center; margin-top: 24px;
}
.contact-clean h2 { margin: 0; }

/* no borders here — the icon chip is the only frame, so the rows stay quiet */
.channels { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 28px; }
.ch {
  display: flex; align-items: center; gap: 14px; width: 100%;
  padding: 4px 0; text-align: left; cursor: pointer;
  border: 0; background: none;
}
.ch-ic {
  flex: none; display: grid; place-items: center; width: 38px; height: 38px;
  color: var(--accent); border: 1px solid var(--line); background: var(--surface);
  transition: border-color .22s ease, background-color .22s ease;
}
.ch:hover .ch-ic { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); background: var(--surface-2); }
.ch-ic svg { width: 17px; height: 17px; display: block; }
.ch-body { display: flex; flex-direction: column; justify-content: center; gap: 3px; min-width: 0; }
.ch-k { color: var(--ink); font-size: 12px; letter-spacing: 0.07em; text-transform: uppercase; transition: color .22s ease; }
.ch:hover .ch-k { color: var(--accent); }
/* the handle is the proof the route is real — never let it wrap the row open */
.ch-v { color: var(--faint); font-size: 11px; letter-spacing: 0.02em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ch-go {
  margin-left: auto; flex: none; color: var(--accent); font-size: 15px; line-height: 1;
  transition: transform .28s var(--ease);
}
.ch-go.mono { font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; }
.ch:hover .ch-go:not(.mono) { transform: translate(2px, -2px); }

/* heading types itself out, then the CTAs/socials fade up after */
.type-cursor {
  display: inline-block; width: 0.55em; height: 1em; margin-left: 4px; vertical-align: -0.12em;
  background: var(--accent); animation: blink 1.1s steps(1, end) infinite;
}
@keyframes blink { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }
/* rows land one after another once the heading has finished typing */
.js .contact-reveal .ch {
  opacity: 0; transform: translateY(10px);
  transition: opacity .45s ease, transform .45s var(--ease);
}
.js .contact-reveal.visible .ch { opacity: 1; transform: none; }
.js .contact-reveal.visible .ch:nth-child(2) { transition-delay: .08s; }
.js .contact-reveal.visible .ch:nth-child(3) { transition-delay: .16s; }
.js .contact-reveal.visible .ch:nth-child(4) { transition-delay: .24s; }
@media (prefers-reduced-motion: reduce) {
  .type-cursor { animation: none; }
  .js .contact-reveal .ch { transition: none; }
}

@media (max-width: 980px) {
  .contact-clean { grid-template-columns: 1fr; gap: 26px; align-items: start; }
}

/* on a phone the rows are dead weight: keep the four logos only, in one row
   under a centred heading, each a 56px tap target */
/* phone: three logo chips as the secondary row, CV promoted to a full-width
   amber slab so the block has one obvious action instead of four equal ones */
@media (max-width: 700px) {
  .contact.section { padding-block: clamp(80px, 16vw, 120px); }
  .contact-clean { text-align: center; gap: 28px; }
  /* grid, not flex-wrap: lets the CV row size to its own text instead of
     stretching the full width, so its rule sits only under the label */
  .channels { display: grid; grid-template-columns: repeat(3, 54px); justify-content: center; gap: 14px; }
  .ch { width: 54px; height: 54px; padding: 0; display: grid; place-items: center; gap: 0; }
  .ch-body, .ch-go { display: none; }
  .ch-ic { width: 100%; height: 100%; border: 1px solid var(--line); background: var(--surface); }
  .ch-ic svg { width: 21px; height: 21px; }

  .channels .ch:last-child {
    grid-column: 1 / -1; justify-self: center; width: fit-content; height: auto; margin-top: 10px;
    display: flex; flex-direction: row; align-items: center; justify-content: center; gap: 9px;
    padding: 0 0 9px; background: none; color: var(--accent);
    border-bottom: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  }
  .channels .ch:last-child .ch-ic { width: auto; height: auto; border: 0; background: none; color: inherit; }
  .channels .ch:last-child .ch-ic svg { width: 15px; height: 15px; }
  .channels .ch:last-child .ch-body { display: flex; }
  .channels .ch:last-child .ch-k { color: inherit; font-size: 12px; letter-spacing: 0.12em; }

  /* the mark alone carries the footer on a phone */
  .stamp span:not(.fmark) { display: none; }
}

/* ---------- footer ---------- */
footer { border-top: 1px solid var(--line); padding: 42px 0 48px; }

/* arrow stays put; the label slides right on hover (defined late so it wins source order) */
.idlinks a, .ov-social a, .actions a, .actions button, .case-links a {
  transition: transform .28s var(--ease), color .2s ease, border-color .2s ease;
}
.idlinks a .ar, .ov-social a .ar, .actions .ar, .case-links a .ar { transition: transform .28s var(--ease); }
.idlinks a:hover, .ov-social a:hover,
.actions a:hover, .actions button:hover, .case-links a:hover { transform: translateX(5px); color: var(--accent); }
.case-links a:hover { border-color: var(--accent); }
.idlinks a:hover .ar, .ov-social a:hover .ar,
.actions a:hover .ar, .actions button:hover .ar, .case-links a:hover .ar { transform: translateX(4px); }

/* The ↗ marks a link. Buttons are not links, so they stay bare. */
.actions button .ar { display: none; }

.stamp {
  display: flex; align-items: center; gap: 9px;
  color: var(--faint); font-size: 11px; letter-spacing: 0.12em;
}
.stamp .fmark {
  width: 16px; height: 16px;
  background: var(--accent); opacity: 1;
  -webkit-mask: url("assets/logo-x.png") center / contain no-repeat;
  mask: url("assets/logo-x.png") center / contain no-repeat;
}

/* ---------- toast ---------- */
.toast {
  position: fixed; left: 50%; bottom: calc(26px + env(safe-area-inset-bottom, 0px));
  z-index: 500;
  transform: translate(-50%, calc(100% + 40px));
  opacity: 0; visibility: hidden;
  max-width: min(90vw, 420px); text-align: center;
  padding: 11px 18px; background: var(--accent); color: #1a1204; border-radius: 8px;
  font-size: 11px; letter-spacing: 0.1em; word-break: break-all;
  transition: transform .3s var(--ease), opacity .3s ease, visibility .3s;
}
.toast.show { transform: translate(-50%, 0); opacity: 1; visibility: visible; }

/* ---------- back-to-top ---------- */
.to-top {
  position: fixed; right: 20px; bottom: 20px; z-index: 300;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 13px; background: color-mix(in srgb, var(--surface) 92%, transparent);
  border: 1px solid var(--line); border-radius: 999px; color: var(--muted);
  font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; cursor: pointer;
  backdrop-filter: blur(8px);
  opacity: 0; transform: translateY(14px); pointer-events: none;
  transition: opacity .3s var(--ease), transform .3s var(--ease), color .2s ease, border-color .2s ease;
}
.to-top.show { opacity: 1; transform: none; pointer-events: auto; }
.to-top:hover { color: var(--accent); border-color: var(--accent); }
.to-top span:first-child { color: var(--accent); font-size: 13px; line-height: 1; }

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width: 960px) {
  .topbar .topnav { display: none; }
  .ov-inner { grid-template-columns: 1fr; gap: 22px; align-content: start; padding: 74px 0 26px; }
  .ov-nav a { padding: 9px 12px; }
  /* readout left, social links right, so the whole menu fits one screen
     instead of pushing the links below the fold */
  .ov-side {
    align-self: start;
    display: grid; grid-template-columns: 1fr auto;
    column-gap: 20px; row-gap: 12px; align-items: start;
  }
  .ov-side > div:not(.ov-social) { grid-column: 1; }
  .ov-social { grid-column: 2; grid-row: 1 / span 4; margin-top: 0; justify-self: end; }
  .ov-social a { justify-content: flex-end; }
  .ov-stamp { grid-column: 1 / -1; }
}

@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; gap: 30px; }
  /* case-file card is a desktop-only element */
  .idcard { display: none; }
  .hero-avatar {
    display: block; position: relative; overflow: hidden;
    width: 148px; height: 148px; margin: 0 0 24px;
    border-radius: 50%;
    border: 1px solid color-mix(in srgb, var(--accent) 55%, var(--line));
    background:
      radial-gradient(60% 55% at 50% 62%, color-mix(in srgb, var(--accent) 26%, transparent), transparent 72%),
      var(--surface-2);
    box-shadow: 0 8px 20px rgba(0, 0, 0, .38);
  }
  /* the source is a head-to-waist cut-out: the face sits in its top third, the
     torso fills the rest. Zoom is independent of the circle's size (percent
     scales both axes together), so widening the circle alone would still crop
     tight on the face — pull the zoom back to 130% to bring more of the
     jacket and shoulders into frame with it. */
  .hero-avatar img {
    position: absolute; left: 50%; top: 1%;
    width: 130%; max-width: none; height: auto; transform: translateX(-50%);
    filter: grayscale(1) contrast(1.06) brightness(.97);
    pointer-events: none; user-select: none; -webkit-user-drag: none;
  }
  h1 { max-width: 20ch; }
  .flag-grid { grid-template-columns: 1fr; }
  .flag-copy .actions { flex-direction: row; flex-wrap: wrap; }
  .cred-grid { grid-template-columns: 1fr; }
}

@media (max-width: 720px) {
  :root { --shell: calc(100% - 28px); }

  /* let the heading use the full centred width and breathe a little smaller */
  h1 { font-size: clamp(27px, 8vw, 34px); max-width: none; }

  /* thumb targets: these are all 11–12px text links, so pad them out to a
     comfortable tap height without letting the padding change the layout */
  .idlinks a, .ov-social a, .case-links a, .actions a, .actions button {
    padding-block: 11px;
  }
  .idlinks { gap: 0; margin-top: 0; }
  .ov-social { gap: 0 !important; }
  .case-links { gap: 0 22px; }
  .actions { gap: 0 24px; }
  .topbar .id { padding-block: 12px; }

  /* A phone browser's bottom toolbar sits over the bottom of the layout
     viewport, so a toast anchored there is painted underneath it and never
     seen. Drop it in from the top instead, clear of the 54px topbar. */
  .toast {
    top: calc(64px + env(safe-area-inset-top, 0px)); bottom: auto;
    transform: translate(-50%, calc(-100% - 80px));
  }
  .toast.show { transform: translate(-50%, 0); }
  /* the phone hero is small enough that the dots sit right on the headline —
     keep the brighter wash for desktop only */
  .hero #herofog { opacity: .34; }
  .window-bar { align-items: center; }
  .window-bar a { display: flex; align-items: center; padding-left: 14px; min-height: 42px; }

  /* --- section strip: slides in under the header once past the hero --- */
  .secnav {
    display: flex; gap: 6px;
    position: sticky; top: 54px; z-index: 90;
    margin: 0; padding: 8px 14px;
    overflow-x: auto; scrollbar-width: none;
    background: color-mix(in srgb, var(--bg) 90%, transparent);
    backdrop-filter: blur(9px);
    border-bottom: 1px solid var(--line);
    transform: translateY(-115%); opacity: 0;
    transition: transform .32s var(--ease), opacity .32s var(--ease);
  }
  .secnav::-webkit-scrollbar { display: none; }
  .secnav.show { transform: none; opacity: 1; }
  .secnav a {
    flex: 0 0 auto; padding: 10px 13px;
    border: 1px solid var(--line); border-radius: 999px;
    font-size: 12px; color: var(--muted); white-space: nowrap;
    transition: color .2s ease, background .2s ease, border-color .2s ease;
  }
  .secnav a.active {
    color: #1a1204; background: var(--accent); border-color: var(--accent);
  }
  main section[id] { scroll-margin-top: 98px; }

  /* === the drawer: three folders whose files pull open === */
  .dossier {
    /* no bottom padding: the next section's own padding-top already matches the
       --tab-band headroom above the stack, so the drawer sits evenly spaced */
    padding: 0;
    /* scroll anchoring stays ON here: with it suppressed the browser had to
       anchor to #contact below the drawer, so opening a folder while another
       was open above scrolled the viewport down by the new folder's height.
       Letting nodes inside the drawer anchor keeps the tapped head put.
       "File all back" adds .filing for the length of the fold: while the
       stack is shrinking, anchoring would instead chase the viewport down. */
    /* same charcoal as the rest of the site; amber only on the accents */
    --kraft-hi: #121010; --kraft-lo: #0a0908;
    /* clear space an index tab (22.8px) drops into, plus room to breathe */
    --tab-band: 44px;
  }
  .dossier.filing { overflow-anchor: none; }
  .dossier + .section { padding-top: 34px; }
  /* the drawer hangs off the box above it, so that box drops its bottom padding */
  .section:has(+ .dossier) { padding-bottom: 0; }

  /* headroom for the first folder's index tab, so it clears the box above */
  .js .dossier-body { display: block; height: auto; padding-top: var(--tab-band); }

  /* closed, the folders butt into one stack — adjacent 1px borders overlap into a
     single shared rule and each index tab rides on the front above it */
  .dossier-body > .section.collapsible {
    position: relative; margin: -1px 0 0; padding: 0;
  }
  .dossier-body > .section.collapsible:first-child { margin-top: 0; }
  /* a drawn-out file ends its card, so the folder below drops by one tab band
     rather than landing its tab on the open file */
  .dossier-body > .section.collapsible.open + .section.collapsible { margin-top: var(--tab-band); }
  /* #experience carries an id-level padding-bottom off the base sheet — null it
     here so the last folder butts flush against the drawer front */
  .dossier-body > #experience.section.collapsible { padding-bottom: 0; }

  /* .sec-head is the folder front — the whole bar is the tap target */
  .section.collapsible .sec-head {
    position: relative; display: flex; align-items: center; gap: 10px;
    margin: 0; padding: 10px 13px 9px; min-height: 38px;
    cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent;
    background: linear-gradient(180deg, var(--kraft-hi), var(--kraft-lo));
    border: 1px solid var(--line); border-radius: 0;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
    transition: border-color .35s var(--ease), background .35s var(--ease), box-shadow .4s var(--ease);
  }
  /* a front rounds its top only where a card starts: at the head of the stack, or
     under the gap an open file above it opened up */
  .dossier-body > .section.collapsible:first-child .sec-head,
  .dossier-body > .section.collapsible.open + .section.collapsible .sec-head {
    border-radius: 8px 8px 0 0;
  }
  .section.collapsible .sec-head::after { display: none; }
  /* the index tab riding above the front, one step further left each time */
  .section.collapsible .sec-head > :first-child {
    position: absolute; bottom: 100%; margin-bottom: -1px;
    display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
    padding: 4px 9px 5px;
    background: linear-gradient(180deg, #131010, #0a0808);
    border: 1px solid var(--line); border-bottom: 0; border-radius: 7px 7px 0 0;
    font-size: 8px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--faint);
    transition: color .3s var(--ease), border-color .3s var(--ease);
  }
  .dossier-body > .section.collapsible:nth-child(1) .sec-head > :first-child { left: auto; right: 2%; }
  .dossier-body > .section.collapsible:nth-child(2) .sec-head > :first-child { left: 27%; }
  .dossier-body > .section.collapsible:nth-child(3) .sec-head > :first-child { left: 2%; }
  .section.collapsible .sec-head > :first-child::before {
    content: attr(data-file) "\00a0\00a0"; color: var(--accent);
  }
  /* no caption text on the front — just an open/close chevron */
  .section.collapsible .sec-head > :last-child {
    display: inline-flex; align-items: center; margin-left: auto;
    font-size: 0; letter-spacing: 0; color: var(--faint);
  }
  .section.collapsible .sec-head > :last-child::after {
    content: "\25B8"; font-size: 13px; color: var(--faint);
    display: inline-block; transition: transform .4s var(--ease), color .3s var(--ease);
  }
  .section.collapsible.open .sec-head {
    border-color: color-mix(in srgb, var(--accent) 30%, var(--line));
    background: linear-gradient(180deg, #16120c, #0c0a07);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05);
  }
  .section.collapsible.open .sec-head > :first-child {
    color: var(--ink); border-color: color-mix(in srgb, var(--accent) 30%, var(--line));
  }
  .section.collapsible.open .sec-head > :last-child::after {
    transform: rotate(90deg); color: var(--accent);
  }

  /* the file inside the folder: hidden at rest, drawn out when pressed */
  .section.collapsible .sec-metrics {
    display: grid; grid-template-columns: repeat(4, 1fr);
    gap: 1px; padding: 1px; margin: -1px 0 0;
    list-style: none; cursor: pointer;
    background: var(--line);
    border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--line));
    border-radius: 0; overflow: hidden;
  }
  .js .section.collapsible:not(.open) .sec-metrics { display: none; }
  .section.collapsible .sec-metrics li {
    position: relative; overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    min-height: 44px; padding: 10px 4px; text-align: center;
    background: var(--file, #050403);
    font: 500 11px/1.25 var(--mono); letter-spacing: 0.04em; color: var(--ink);
    text-transform: uppercase;
  }
  /* classified-doc redaction bar: covers the cell until the file opens, then
     wipes off left-to-right (staggered) in step with the body expanding */
  .section.collapsible .sec-metrics li::before {
    content: ""; position: absolute; inset: 0; z-index: 1;
    background: #000;
    transform-origin: right;
    transition: transform .42s var(--ease) calc(var(--i, 0) * 70ms);
  }
  .section.collapsible.open .sec-metrics li::before { transform: scaleX(0); }

  /* padding rides the same curve as height: the box is border-box, so padding
     appearing all at once made the file pop open before it slid open */
  .js .section.collapsible .sec-body {
    position: relative; overflow: hidden; margin: 0;
    transition: height .38s var(--ease), padding .38s var(--ease);
  }
  .js .section.collapsible.open .sec-body {
    padding: 16px 13px 18px;
    background: #050403;
    border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--line)); border-top: 0;
    border-radius: 0 0 8px 8px;
    box-shadow: 0 26px 46px -22px rgba(0, 0, 0, .92);
    animation: fileDraw .5s var(--ease);
  }
  /* experience has no metric strip to cap the file: it takes its own top edge and
     pulls up 1px so that edge sits on the folder front's border, not beside it */
  .js #experience.section.collapsible.open .sec-body {
    margin-top: -1px;
    border-top: 1px solid color-mix(in srgb, var(--accent) 30%, var(--line));
    border-radius: 0 0 8px 8px;
  }
  /* an amber light sweeps down the file as it draws open */
  .js .section.collapsible.open .sec-body::after {
    content: ""; position: absolute; left: 0; right: 0; top: 0; height: 42%;
    pointer-events: none;
    background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 20%, transparent), transparent);
    animation: fileScan .62s var(--ease) forwards;
  }
  @keyframes fileDraw {
    from { opacity: .25; transform: translateY(-8px); }
    to   { opacity: 1; transform: translateY(0); }
  }
  @keyframes fileScan {
    0%   { transform: translateY(-100%); opacity: 0; }
    35%  { opacity: 1; }
    100% { transform: translateY(320%); opacity: 0; }
  }
  /* resting collapsed state is CSS-only, so a resize back to desktop always reveals */
  .js .section.collapsible:not(.open) .sec-body { height: 0; padding: 0; }

  /* the drawer front, butting directly under the last folder to close the stack.
     With files drawn out it becomes the control that files them all back in. */
  .drawer-front {
    position: relative; width: calc(100% - 28px); margin: -1px auto 0; height: 44px;
    display: flex; align-items: center; justify-content: center; gap: 12px;
    appearance: none; -webkit-appearance: none; cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    background: linear-gradient(180deg,
      color-mix(in srgb, var(--accent) 92%, #fff),
      var(--accent));
    border: 1px solid color-mix(in srgb, var(--accent) 70%, #000);
    border-radius: 0 0 8px 8px;
    box-shadow: 0 16px 26px -20px rgba(0, 0, 0, .7);
    font: 600 10.5px/1 var(--mono); letter-spacing: 0.22em; text-transform: uppercase;
    color: #0b0906;
  }
  .drawer-front b { color: #0b0906; font-weight: 700; }
  .drawer-front:disabled { cursor: default; }
  /* once a folder is open the bar's whole job is to file it back, so it swaps
     the "Case file / 03 files" label out for a single centred prompt */
  .df-shut { display: none; color: #0b0906; font-weight: 700; align-items: center; }
  .dossier:has(.section.collapsible.open) .drawer-front > span:first-child { display: none; }
  .dossier:has(.section.collapsible.open) .df-shut { display: inline-flex; }
  .df-shut .ar { color: #0b0906; margin-right: 5px; }
  /* the front knocks shut once the last file has slid back in */
  .drawer-front.shutting { animation: drawerShut .46s var(--ease); }
  @keyframes drawerShut {
    0%   { transform: translateY(0); }
    40%  { transform: translateY(5px); box-shadow: 0 -12px 20px -16px rgba(0, 0, 0, .9); }
    100% { transform: translateY(0); }
  }
  /* the closed stack is short, so landing on its top shows the whole drawer */
  .dossier { scroll-margin-top: 78px; }
  /* the last file drawn out ends the stack, so the front becomes its own bar */
  #dossier-body:has(> .section.collapsible:last-child.open) + .drawer-front {
    margin-top: var(--tab-band); border-radius: 8px;
  }

  /* contents fade up once the cells have finished filling */
  .js .section.collapsible .sec-body > * {
    opacity: 0; transform: translateY(14px);
    transition: opacity .3s var(--ease), transform .3s var(--ease);
  }
  .js .section.collapsible.open .sec-body > * { opacity: 1; transform: none; transition-delay: .24s; }
  .js .section.collapsible.open .sec-body > :nth-child(2) { transition-delay: .29s; }
  .js .section.collapsible.open .sec-body > :nth-child(3) { transition-delay: .34s; }
  .js .section.collapsible.open .sec-body > :nth-child(4) { transition-delay: .39s; }
  .js .section.collapsible.open .sec-body > :nth-child(5) { transition-delay: .44s; }

  /* --- fewer words on a phone: keep collapsed rows to title + tags --- */
  .hero-copy .stackline { display: none; }
  .flag-copy .fineprint { display: none; }
  /* Experience is behind a folder the visitor chose to open, so the roles read
     in full — a 3-line clamp was cutting them mid-sentence. */

  /* keep the live preview, just shorter — it only mounts once Flagship is opened */
  .dashboard-window { min-height: 0; }
  .dash-stage { min-height: 300px; }
  .dash-skeleton .sk-kpis { grid-template-columns: repeat(2, 1fr); }
  .dash-gate .play { width: 48px; height: 48px; }
  .dash-gate .play svg { width: 18px; height: 18px; }
  /* a blur filter inside the height-animating, overflow-hidden section body makes
     iOS Safari composite a layer it then fails to repaint (content renders half
     painted). Fake the softness with opacity instead — no filter, no layer. */
  .dash-skeleton { filter: none; opacity: .5; }

  /* calmer hero: centred, drop the 3-beat method list */
  .hero-copy { text-align: center; }
  .hero-copy .actions { justify-content: center; }
  .hero-copy .lead { margin-inline: auto; }
  .hero-avatar { margin-inline: auto; }
  .method { display: none; }

  .case-item { max-width: none; }
  #work { --case-rise: 26px; --case-tilt: 0deg; }
  #work .sec-head { margin-bottom: 6px; }
  /* the index sits top-left and the +/× top-right on one line, with the title
     and a trimmed tag strip beneath — three lines a row instead of four */
  .row {
    max-width: none; grid-template-columns: 1fr auto; gap: 4px 14px;
    align-items: start; padding: 18px 2px 18px 22px;
    scroll-margin-top: 96px;
  }
  .row .row-body { grid-column: 1; }
  .row .go {
    grid-column: 2; grid-row: 1; align-self: start;
    opacity: 1; transform: none; margin-top: 0;
  }
  /* the glyph alone carries the affordance — the words cost a whole line */
  .row .go b { display: none; }
  .row .go .chev { font-size: 20px; }
  .row .idx { display: inline-block; margin: 0 0 4px; }
  .row h3 { margin: 0; }
  .row .tags { margin-top: 2px; line-height: 1.8; }
  /* three skills is what a phone can show without wrapping to a block of text */
  .row .tags .t:nth-child(n+4) { display: none; }
  .case-item.flagship::before { left: 22px; top: 2px; }
  .case-item.flagship .row { padding-top: 26px; }
  .case-inner { padding-left: 22px; padding-right: 2px; }
  .case dl > div { grid-template-columns: 1fr; gap: 4px; }

  /* the rail stays — it is the section's spine and the only scroll feedback
     on a phone — but slimmed and moved inside the shell. The sparks go: they
     are decoration, and they cost real height. */
  .work-rail { left: 3px; width: 1px; }
  .work-rail span { width: 1px; }
  .row .node { left: 0; width: 7px; height: 7px; margin-top: -3.5px; border-width: 1px; }
  .row.rail-lit .node { box-shadow: 0 0 8px var(--accent); }
  .row .spark { display: none; }

  /* the fixed corner frames crowd content on small screens */
  .frame { display: none; }

  .xrow { grid-template-columns: 1fr; gap: 10px; }
  .xr-when { display: flex; align-items: center; gap: 12px; }
  .xr-when time { margin: 0; }
  .xr-when .bar { flex: 1; }

  .skillstrip { padding: 15px 0; gap: 8px; }
  .mq-track li { padding: 3px 17px; letter-spacing: 0.12em; font-size: 11px; }

}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .js .sec-head.reveal .sk, .js .sec-head.reveal > span,
  .js .flag-copy.reveal h2, .js .contact .shell.reveal h2 {
    clip-path: none; transform: none; opacity: 1; transition: none;
  }
  .secnav { transition: none; }
  .to-top { transition: opacity .15s ease; transform: none; }
  .mq-track { animation: none; flex-wrap: wrap; min-width: 0; justify-content: center; row-gap: 2px; }
  .marquee { -webkit-mask-image: none; mask-image: none; }
  .marquee > .mq-track:nth-child(2) { display: none; }
  .mq-track li:last-child::after { content: none; }
  .section.collapsible .sec-head,
  .section.collapsible .sec-head > :first-child,
  .section.collapsible .sec-head > :last-child::after { transition: none; }
  .section.collapsible .sec-body { transition: none; animation: none; }
  .section.collapsible .sec-body::after { animation: none; display: none; }
  .section.collapsible .sec-body > * { opacity: 1; transform: none; transition: none; }
  .section.collapsible .sec-metrics li { animation: none; }
  .drawer-front.shutting { animation: none; }
  .section.collapsible .sec-metrics li span { opacity: 1; transition: none; }
  .section.collapsible .sec-metrics li::before { transition: none; transform: scaleX(0); }
  .section.collapsible .sec-head > :last-child::after { transition: none; }
  .section.collapsible .sec-head:hover > :last-child::after { letter-spacing: 0.14em; }
  .section.collapsible .sec-head::after { animation: none; }
  .spark polyline, .spark.gauge circle.val { stroke-dashoffset: 0; transition: none; }
  .spark.bars rect { transform: scaleY(1); transition: none; }
  .xr-when .bar::after { transition: none; }
  .ov-nav a::before, .ov-nav a::after { transition: opacity .15s ease; transform: none; }
  .row:hover { transition: none; }
  .row:hover .spark { transform: none; }
  .row .go { transition: opacity .15s ease; transform: none; }
  .sec-head::after { transition: none; transform: scaleX(1); }
  .js .row.reveal h3, .js .row.reveal .idx, .js .row.reveal .tags,
  .js .row.reveal .tags { opacity: 1; transform: none; transition: none; }
  .work-rail span, .row .node { transition: none; }
  .case, .case-inner, .row .chev { transition: none; }
  .js .ct-panel { transition: none; transform: none; }
  .ct-tab, .ct-tab::before, .ct-tab::after { transition: none; }
  .idlinks a:hover, .ov-social a:hover,
  .actions a:hover, .actions button:hover,
  .idlinks a:hover .ar, .ov-social a:hover .ar,
  .actions a:hover .ar, .actions button:hover .ar { transform: none; }
  html.booting .frame,
  html.booting .dsr-photo > img,
  html.booting .hero-copy > *,
  html.booting .idcard .dsr-body { animation: none !important; }
  .scroll-progress { box-shadow: none; }
  .overlay { transition: opacity .12s ease, visibility .12s; transform: none; }
  .overlay.open { transform: none; }
  .overlay .ov-nav a { transition: color .2s ease; }
  .overlay.open .ov-nav a { opacity: 1; transform: none; transition-delay: 0s; }
  .overlay .ov-side { transition: none; }
}
