/* ---------- Design tokens ---------- */
:root {
  --bg: #ffffff;
  --surface: #ffffff;
  --ink: #0d0d0d;
  --muted: #5c5c58;
  --line: #0d0d0d;
  --accent: #ff4a1c;      /* signal red-orange */
  --accent-2: #2b2bff;    /* electric blue */

  --font-display: "Host Grotesk", "Helvetica Neue", Arial, sans-serif; /* Suisse-like neo-grotesk for headings */
  --font: "Inter", "Helvetica Neue", Arial, sans-serif;                   /* text face */
  --mono: ui-monospace, "SF Mono", Menlo, monospace;

  --fs-xs: 0.75rem;
  --fs-sm: 0.875rem;
  --fs-md: 1.125rem;
  --fs-lg: clamp(1.5rem, 2.4vw, 2rem);
  --fs-xl: clamp(2.25rem, 5vw, 4rem);
  --fs-display: clamp(3.5rem, 12vw, 11rem);

  --s1: 0.5rem; --s2: 1rem; --s3: 1.5rem; --s4: 2.5rem; --s5: 4rem; --s6: 7rem;
  --gutter: clamp(1rem, 4vw, 3rem);
  --radius: 0;
  --ease: cubic-bezier(.2, .7, .2, 1);
  --t: .5s var(--ease);

  /* Added in Step 2A */
  --tint: #f4f4f2;                                        /* stage behind screens, placeholders */
  --hair: color-mix(in srgb, var(--ink) 14%, transparent); /* light hairline between sub-sections */
  --topbar-h: 4rem;
  --content: 78rem;                                       /* max content width on project pages */
  --measure: 62ch;                                        /* max line length for body text */
  --frame: color-mix(in srgb, var(--ink) 28%, transparent); /* outline around sketch and storyboard panels */
  --frame-radius: 12px;                                   /* corner radius of those outlines */

  /* Text around and inside visuals: always use these, never ad-hoc styles */
  --type-caption: 400 0.8125rem/1.5 var(--font);          /* image caption: muted, left, max 60ch */
  --type-fig-label: 500 0.6875rem/1.4 var(--mono);        /* figure label "Fig. 03 · Flow": ink, uppercase, .08em */
  --type-panel: var(--type-caption);                     /* storyboard panel text: same as captions, muted */
  --type-callout: 500 0.75rem/1.2 var(--font);            /* annotation pin: white on ink pill, accent dot */
  --type-meta: 500 0.6875rem/1.4 var(--mono);             /* small metadata: muted, uppercase, .06em */
  --type-dg: 500 12px/1 var(--font);                      /* diagram label (SVG units): ink, Title Case, centered */

  /* Diagram language */
  --dg-stroke: 1.25px;       /* every line and node outline */
  --dg-line: var(--ink);     /* primary path, node outline */
  --dg-soft: #c4c4bf;        /* secondary node outline, inactive lines */
  --dg-fill: #ffffff;        /* default node fill */
  --dg-hi: var(--accent);    /* one highlighted node/result per diagram */
  --dg-alt: var(--muted);    /* alternative path, dashed 4 4 */
  --dg-grid: #dededa;        /* dot grid behind diagrams */
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: 5rem; }
body { margin: 0; overflow-x: clip; background: var(--bg); color: var(--ink); font: 400 var(--fs-md)/1.5 var(--font); -webkit-font-smoothing: antialiased; }
img { max-width: 100%; display: block; }
a { color: inherit; }
h1, h2, h3 { margin: 0; font-family: var(--font-display); font-weight: 600; letter-spacing: -0.035em; line-height: .92; }
p { margin: 0 0 var(--s2); max-width: 62ch; }
:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 3px; }
.wrap { padding-inline: var(--gutter); }
.skip { position: absolute; left: -999px; top: 0; background: var(--ink); color: var(--bg); padding: var(--s1) var(--s2); z-index: 99; }
.skip:focus { left: var(--s2); }
.eyebrow, .num, .tag, dt, .footer, .btn, .topbar nav a { font: 500 var(--fs-xs)/1.3 var(--mono); text-transform: uppercase; letter-spacing: .06em; }
.num { color: var(--muted); }
.display { font-size: var(--fs-display); }
.section { padding-block: var(--s6) var(--s5); }
#work { padding-top: var(--s4); transition: opacity .9s var(--ease), transform .9s var(--ease); } /* peeks above the fold so the hero invites a scroll */
.intro #work { opacity: 0; transform: translateY(20px); } /* appears once the intro text is in focus and scrolling unlocks */
.scroll-cue { display: inline-block; animation: bob 1.6s ease-in-out infinite; }
@keyframes bob { 50% { transform: translateY(4px); } }
/* no rule under the label: the accent dot and the space below do the separating */
.section-head { display: flex; justify-content: space-between; align-items: center; gap: var(--s2); margin-bottom: var(--s4); }
.section-head h2 { display: inline-flex; align-items: center; gap: .6em; }
.section-head h2::before, .contact > .eyebrow::before { content: ""; width: .55rem; height: .55rem; border-radius: 50%; background: var(--accent); }
.section-head h2 { font: 500 var(--fs-xs)/1.3 var(--mono); text-transform: uppercase; letter-spacing: .06em; }   /* small label, like the "Connect" eyebrow */
.box { border: 1px solid var(--line); background: var(--surface); padding: var(--s3); }

/* Buttons */
.btn { display: inline-flex; gap: .5em; align-items: center; padding: .9em 1.4em; border: 1px solid var(--ink); text-decoration: none; transition: background var(--t), color var(--t); }
.btn:hover { background: var(--ink); color: var(--bg); }
.btn.solid { background: var(--ink); color: var(--bg); }
.btn.solid:hover { background: var(--accent); border-color: var(--accent); color: var(--ink); }
.link { text-decoration: none; background: linear-gradient(currentColor 0 0) 0 100% / 0 1px no-repeat; transition: background-size var(--t); }
.link:hover { background-size: 100% 1px; }

/* ---------- Top bar (translucent, blurred) ---------- */
.topbar { position: sticky; top: 0; z-index: 50; height: var(--topbar-h); display: flex; justify-content: space-between; align-items: center; padding: var(--s2) var(--gutter); background: color-mix(in srgb, var(--bg) 70%, transparent); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); }
.wordmark { font-family: var(--font-display); font-weight: 600; font-size: 1.25rem; letter-spacing: -0.03em; text-decoration: none; }
.topbar nav { display: flex; gap: var(--s4); }
.topbar nav a { text-decoration: none; position: relative; padding-block: .3em; }
.topbar nav a::after { content: ""; position: absolute; left: 0; bottom: 0; width: 100%; height: 1px; background: currentColor; transform: scaleX(0); transform-origin: left; transition: transform var(--t); }
.topbar nav a:hover::after, .topbar nav a.active::after, .topbar nav a[aria-current]::after { transform: scaleX(1); }
.topbar nav a.active, .topbar nav a[aria-current] { color: var(--accent); }
.menu-btn { display: none; background: none; border: 1px solid var(--ink); padding: .5em 1em; font: 500 var(--fs-xs) var(--mono); text-transform: uppercase; cursor: pointer; color: var(--ink); }

@media (max-width: 720px) {
  .menu-btn { display: block; }
  .topbar nav { position: fixed; inset: var(--topbar-h) 0 auto 0; flex-direction: column; gap: 0; padding: var(--s2) var(--gutter) var(--s4); background: color-mix(in srgb, var(--bg) 82%, transparent); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); transform: translateY(-120%); visibility: hidden; transition: transform var(--t), visibility var(--t); }
  .topbar nav a { font: 600 2.5rem/1.2 var(--font-display); text-transform: none; letter-spacing: -0.03em; }
  .menu-open .topbar nav { transform: none; visibility: visible; }
}

/* ---------- Hero ---------- */
.hero { min-height: calc(78svh - 4rem); display: flex; flex-direction: column; justify-content: flex-end; gap: var(--s5); padding-bottom: var(--s5); }
.hero h1 { font-size: clamp(2.25rem, 5.4vw, 5.25rem); font-weight: 500; line-height: 1.02; letter-spacing: -0.035em; max-width: 20ch; }
.hero-name { color: var(--ink); }
.hero-intro { color: var(--muted); }
/* Light field: grainy soft glows that wander and change shape. The pointer pulls them like liquid (spring
   physics in main.js): fast moves stretch them, stopping lets them settle home.
   Each glow is a solid colour plus grain, faded out by a radial mask. No blend modes and no CSS blur:
   Safari draws those as grey or black boxes on moving layers.
   Full-bleed behind the text; fades out at the bottom so Selected Work starts on plain white. */
.hero { position: relative; isolation: isolate; }
.hero h1 { position: relative; }
.hero-light { position: absolute; z-index: -1; top: calc(-1 * var(--topbar-h)); bottom: calc(-1 * (var(--s4) + 3.5rem)); /* reaches down behind the Selected Work row */ left: 50%; width: 100vw; transform: translateX(-50%); overflow: hidden; pointer-events: none;
  -webkit-mask-image: linear-gradient(#000 70%, transparent); mask-image: linear-gradient(#000 70%, transparent); }
.hero-light .glow { position: absolute; aspect-ratio: 1; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .35 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"), var(--c);
  -webkit-mask-image: radial-gradient(closest-side, #000, rgb(0 0 0 / .55) 30%, rgb(0 0 0 / .22) 60%, rgb(0 0 0 / .06) 85%, transparent); mask-image: radial-gradient(closest-side, #000, rgb(0 0 0 / .55) 30%, rgb(0 0 0 / .22) 60%, rgb(0 0 0 / .06) 85%, transparent); }
/* Both glows share one centre (--cx from the right, --cy from the top) and only drift a little around it,
   so they always overlap and read as one soft light, never two separate circles. */
.hero-light { --cx: calc(4vw + max(24vw, 10rem)); --cy: max(18vw, 9rem); }
.hero-light .glow { right: calc(var(--cx) - var(--w) / 2); top: calc(var(--cy) - var(--w) / 2); width: var(--w); }
.hero-light .g1 { --c: var(--accent); --w: max(64vw, 30rem); opacity: .3; animation: wander1 19s ease-in-out infinite alternate, morph 11s ease-in-out infinite alternate, grain 1s steps(5) infinite; }
.hero-light .g2 { --c: #ffb59c; --w: max(44vw, 22rem); opacity: .38; animation: wander2 23s ease-in-out infinite alternate, morph 13s ease-in-out infinite alternate-reverse, grain 1s steps(5) infinite; }
@keyframes wander1 { 50% { translate: -3vw 2vh; } 100% { translate: 2vw -2vh; } }
@keyframes wander2 { 50% { translate: 3vw -2vh; } 100% { translate: -3vw 3vh; } }
@keyframes morph { 50% { scale: 1.12 .94; } 100% { scale: .92 1.06; } }
@keyframes grain { 20% { background-position: -37px 51px; } 40% { background-position: 83px -19px; } 60% { background-position: -101px -67px; } 80% { background-position: 59px 97px; } }
/* Text comes into focus, like the posters' blur-to-sharp play. */
.hero-name, .hero-intro { display: inline; animation: focus 1.4s var(--ease) both; }
.hero-intro { animation-duration: 2s; animation-delay: .5s; }
@keyframes focus { from { filter: blur(14px); opacity: 0; } }

/* ---------- Covers & cards ---------- */
.cover { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; transition: transform .8s var(--ease), filter .8s var(--ease); }
.ph { display: grid; place-items: center; background: radial-gradient(circle at 30% 35%, var(--c) 0 22%, transparent 55%), radial-gradient(circle at 75% 70%, color-mix(in srgb, var(--c) 40%, #fff) 0 18%, transparent 50%), #dcdcd8; }
.ph span { font: 500 var(--fs-xs) var(--mono); color: var(--ink); background: #fff; padding: .3em .6em; border: 1px solid var(--ink); }
.cards { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s4) var(--s3); }
.card { text-decoration: none; display: block; }
.card-media { position: relative; overflow: hidden; }
.card-hover { position: absolute; inset: auto 0 0 0; padding: var(--s2); font: 500 var(--fs-xs) var(--mono); text-transform: uppercase; background: color-mix(in srgb, #fff 45%, transparent); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); transform: translateY(100%); transition: transform var(--t); }
.card:hover .cover, .card:focus-visible .cover { transform: scale(1.04); filter: saturate(1.2); }
.card:hover .card-hover, .card:focus-visible .card-hover { transform: none; }
.card-meta { display: grid; grid-template-columns: auto 1fr; gap: .2rem var(--s2); padding-top: var(--s2); border-top: 1px solid var(--line); margin-top: var(--s2); }
.card-meta h3 { font-size: var(--fs-lg); letter-spacing: -0.03em; }
.card-meta .tag { grid-column: 2; color: var(--muted); }
@media (max-width: 960px) { .cards { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .cards { grid-template-columns: 1fr; } }

/* ---------- About + CV ---------- */
/* About: photo and short bio stacked on the left, experience and education on the right */
.about-grid { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: var(--s5); align-items: start; }
.about-top { display: grid; gap: var(--s3); align-content: start; position: sticky; top: calc(var(--topbar-h) + var(--s3)); }
.photo { display: block; width: 100%; height: auto; }   /* as wide as the bio text, at its own proportions */
.about-top .lead { font-size: var(--fs-md); font-weight: 500; line-height: 1.35; letter-spacing: -0.01em; max-width: 44ch; margin-bottom: var(--s2); }
.about-top p { font-size: var(--fs-sm); max-width: 56ch; }
.cv h3 { font: 500 var(--fs-xs) var(--mono); text-transform: uppercase; letter-spacing: .06em; color: var(--muted); padding-bottom: var(--s1); border-bottom: 1px solid var(--line); }
.cv h3:not(:first-child) { margin-top: var(--s5); }
.cv ol { list-style: none; margin: 0; padding: 0; }
.cv li { display: grid; grid-template-columns: 1fr auto; column-gap: var(--s3); align-items: baseline; padding: var(--s2) 0; border-bottom: 1px solid color-mix(in srgb, var(--ink) 18%, transparent); }
.cv .when { font: 400 var(--fs-sm)/1.6 var(--mono); color: var(--muted); white-space: nowrap; }
.cv .org { display: block; font: 600 var(--fs-md)/1.3 var(--font-display); letter-spacing: -0.01em; }
.cv .role { display: block; margin-top: .15rem; font-size: var(--fs-sm); color: var(--muted); }
@media (max-width: 820px) { .about-grid { grid-template-columns: 1fr; } .about-top { position: static; } }


/* ---------- Contact ---------- */
/* heading on the left, links on the right, sharing the heading's bottom line */
.contact { display: grid; grid-template-columns: 1fr; column-gap: var(--s4); align-items: end; }
/* side by side only when "in touch" and the links both fit on one line; stacked below that */
@media (min-width: 1440px) { .contact { grid-template-columns: minmax(0, 1fr) auto; } .contact h2 { margin-bottom: 0 !important; } .contact-links { justify-content: flex-end !important; padding-bottom: .6rem !important; } }
.contact > .eyebrow { grid-column: 1 / -1; display: inline-flex; align-items: center; gap: .6em; }
.contact h2 { font-size: var(--fs-display); margin-bottom: var(--s4); white-space: nowrap; } /* keeps "Let's get" / "in touch" as two lines */
.contact-links { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center; justify-content: flex-start; }
.contact-links .big { font-size: var(--fs-lg); letter-spacing: -0.02em; margin-right: var(--s3); }
.footer-links { display: flex; gap: var(--s3); }
.footer-links a { text-transform: none; }
.footer { display: flex; justify-content: space-between; padding-block: var(--s3); border-top: 1px solid var(--line); margin-top: var(--s5); }

/* ---------- Work page ---------- */
.work-list { padding: 0; }
.work-list.grid { padding-top: var(--s5); }
/* Pages | Grid switch: fixed just under the menu, in the gap above the first project */
.view-switch { position: fixed; z-index: 40; top: calc(var(--topbar-h) + .25rem); right: var(--gutter); display: flex; gap: .35rem; }
main:has(.work-list.grid) .view-switch { position: absolute; } /* in the grid it scrolls away with the page */
.view-switch a { display: grid; place-items: center; width: 2rem; height: 2rem; color: var(--muted); transition: color var(--t); }
.view-switch svg { width: 1.15rem; height: 1.15rem; fill: none; stroke: currentColor; stroke-width: 1.4; }
.view-switch a:hover { color: var(--ink); }
.view-switch a[aria-current] { color: var(--accent); }
.view-switch a[aria-current] svg { fill: color-mix(in srgb, var(--accent) 18%, transparent); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } /* heading for screen readers, not shown */

/* Spread: cover with a vellum page over it. All spreads sit on one sticky, screen-high stage and are placed
   from the scroll position in main.js (page turns while a spread holds still, then the next one moves up). */
html:has(.work-track) { scroll-snap-type: y proximity; }
.work-track { position: relative; }
.snap { position: absolute; left: 0; width: 1px; height: 1px; scroll-snap-align: start; }
.work-view { position: sticky; top: var(--topbar-h); height: calc(100svh - var(--topbar-h)); overflow: hidden; }
.spread { position: absolute; top: 0; left: 0; right: 0; will-change: transform; }
.spread.waiting { pointer-events: none; }
.spread-card { position: relative; display: block; height: max(26rem, min(64vh, 56.25vw)); overflow-x: visible; overflow-y: clip; /* the peeled flap may reach out sideways, never over the menu or the next project */ color: var(--ink); text-decoration: none; }
.spread-media { position: absolute; inset: 0; overflow: hidden; background: var(--edge, #0d0d10); container-type: size; }
.spread-cover, .spread-haze { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* The cover is scaled to fill the frame, but never so far that the central object (the middle 1900 x 900 of the
   2400 x 1800 cover) comes closer than a margin to the frame's edges; any leftover band is filled with the cover's own edge colour, and the image's
   sides fade into it so there is no seam. */
.spread-cover { inset: auto; left: 50%; top: 50%; translate: -50% -50%; width: min(max(100cqw, 133.34cqh), 108.6cqw, 208cqh); /* object box at most 86% of the width and 78% of the height */ height: auto; aspect-ratio: 4 / 3; object-fit: fill; transition: transform .8s var(--ease);
  -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent), linear-gradient(transparent, #000 6%, #000 94%, transparent); -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent), linear-gradient(transparent, #000 6%, #000 94%, transparent); mask-composite: intersect; }
.spread.flipped .spread-card:hover .spread-cover { transform: scale(1.03); }
/* the cover seen through the vellum: a pre-blurred copy (no CSS blur, which Safari mangles) that clears as the page turns */

/* The page: translucent paper, whiter where the text sits (top and bottom) so the cover's object glows through the middle.
   Its turn is set from scroll in main.js only (no hover effect, which fought the scroll-driven turn). */
.leaf { position: absolute; inset: 0; display: grid; grid-template-rows: auto 1fr auto; padding: clamp(1.25rem, 3vw, 2.75rem);
  background: linear-gradient(to bottom, rgb(255 255 255 / .9), rgb(255 255 255 / .62) 38%, rgb(255 255 255 / .58) 58%, rgb(255 255 255 / .9)); }
.leaf::before { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: .35; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .35 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); } /* paper grain */
.leaf::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: var(--shade, none); } /* shading while it bends */
.leaf > * { position: relative; }
/* the folded-over flap: the same page seen from the back, a touch whiter, only shown while peeling */
.leaf-back { visibility: hidden; transform-origin: 0 0; background: linear-gradient(to bottom, rgb(255 255 255 / .9), rgb(255 255 255 / .74)); }
.spread.peeling .leaf-back { visibility: visible; }

.leaf-top { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--s3); }
.leaf-no { font: 600 clamp(2.5rem, 5vw, 4.5rem)/.85 var(--font-display); letter-spacing: -0.04em; color: var(--accent); }
.leaf-top .meta { color: var(--ink); padding-top: .3rem; text-align: right; }
.leaf-bottom { grid-row: 3; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 24rem); gap: var(--s4); align-items: end; }
.leaf h2 { font-size: clamp(2.75rem, 7vw, 6.5rem); line-height: .9; margin: 0; }
.leaf-text { display: flex; flex-direction: column; align-items: flex-start; }
.leaf-sum { margin: 0; font-size: var(--fs-sm); line-height: 1.5; }
.leaf .tags { margin: var(--s2) 0 0; gap: .35rem; }
.spread-cap { display: flex; justify-content: space-between; gap: var(--s2); margin: var(--s2) 0 0; max-width: none; font: 500 var(--fs-xs) var(--mono); text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
@media (max-width: 720px) {
  .spread-card { height: max(31rem, 68vh); }
  .leaf-bottom { grid-template-columns: 1fr; gap: var(--s2); }
}
dl { margin: 0 0 var(--s3); display: grid; grid-template-columns: repeat(3, auto); gap: var(--s2); }
dd { margin: .2rem 0 0; font-size: var(--fs-sm); }
dt { color: var(--muted); }

/* Project tags: printed look, accent hairline outline with small mono caps (Work page and project pages alike) */
.tags { list-style: none; margin: var(--s3) 0; padding: 0; display: flex; flex-wrap: wrap; gap: .35rem; }
.tags li { display: inline-flex; align-items: center; padding: .35em .75em; border-radius: 99px; border: 1px solid var(--accent); color: var(--accent); font: 500 .66rem/1.2 var(--mono); text-transform: uppercase; letter-spacing: .06em; white-space: nowrap; }
.p-hero-row .tags { margin: var(--s3) 0 0; }

/* ---------- Project page ---------- */
html:has(.p-nav) { scroll-padding-top: calc(var(--topbar-h) + 3.25rem); }
.meta { font: var(--type-meta); text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.p-hero { padding-block: var(--s5) var(--s4); }
.back { display: inline-block; margin-bottom: var(--s5); }
.p-title { font-size: clamp(3rem, 9vw, 8.5rem); max-width: 14ch; }
.p-hero-row { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--s4); margin-top: var(--s5); padding-top: var(--s2); border-top: 1px solid var(--line); animation-delay: .1s; }
.p-lede { font-size: var(--fs-lg); line-height: 1.25; letter-spacing: -0.02em; margin: 0; max-width: 32ch; }
.p-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s3) var(--s2); margin: 0; }
.p-cover { margin: 0; overflow: hidden; }
.p-cover .cover { aspect-ratio: 21 / 9; }
/* Layered cover (background + screens as separate images, same composition as the flat cover). The 4:3 stage is
   centred in the frame like object-fit: cover. On load the side screens glide in from further out and the centre
   one settles forward; then they breathe very slowly. Scrolling past moves each layer by its own amount (project.js). */
.p-cover.layered { position: relative; aspect-ratio: 21 / 9; }
.cv-stage { position: absolute; left: 0; top: 50%; width: 100%; aspect-ratio: 4 / 3; translate: 0 -50%; container-type: inline-size; }
.cv-stage img { position: absolute; display: block; }
.cv-bg { inset: 0; width: 100%; height: 100%; }
.cv-layer { left: var(--x); top: var(--y); width: var(--w); height: auto; will-change: transform; }
.cv-layer[data-role="left"] { animation: cv-in-left 1.9s cubic-bezier(.2, .7, .2, 1) .15s both, cv-breathe 9s ease-in-out 2.1s infinite alternate; }
.cv-layer[data-role="right"] { animation: cv-in-right 1.9s cubic-bezier(.2, .7, .2, 1) .15s both, cv-breathe 10.5s ease-in-out 2.1s infinite alternate; }
.cv-layer[data-role="center"] { animation: cv-in-center 1.6s cubic-bezier(.2, .7, .2, 1) both, cv-breathe 12s ease-in-out 1.6s infinite alternate; }
/* nothing shows (or starts moving) until every piece has loaded, so a half-hidden card never appears on its own */
.p-cover.layered:not(.ready) .cv-stage { visibility: hidden; }
.p-cover.layered:not(.ready) .cv-layer, .p-cover.layered:not(.inview) .cv-layer { animation-play-state: paused; } /* waits at its first frame until loaded and scrolled into view */
@keyframes cv-in-left { from { translate: -4.5cqw 0; opacity: 0; } }
@keyframes cv-in-right { from { translate: 4.5cqw 0; opacity: 0; } }
@keyframes cv-in-center { from { translate: 0 5%; scale: .95; } } /* no fade: the front screen is always solid, so the ones behind never show through it */
@keyframes cv-breathe { to { scale: 1.018; } }
/* Interactive Long Table: the middle of the long "o" grows from its left end while the right cap and "ng" ride
   along, starting from a round "o" (middle 20 of 458 px; the cap travels the other 438 px = 18.25% of the cover). */
.cv-layer[data-role="stretch"] { transform-origin: left center; animation: cv-stretch 2s cubic-bezier(.65, 0, .25, 1) .5s both; }
.cv-layer[data-role="follow"] { animation: cv-follow 2s cubic-bezier(.65, 0, .25, 1) .5s both; }
@keyframes cv-stretch { from { scale: .0437 1; } }
@keyframes cv-follow { from { translate: -18.25cqw 0; } }

/* Section navigator: docked under the top bar, scroll-spy marks the current section */
.p-nav { position: sticky; top: var(--topbar-h); z-index: 40; display: flex; align-items: center; justify-content: space-between; gap: var(--s3); height: 3.25rem; padding-inline: var(--gutter); background: color-mix(in srgb, var(--bg) 80%, transparent); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); border-block: 1px solid var(--hair); }
.p-nav-title { font: 600 1rem/1 var(--font-display); letter-spacing: -0.02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.p-nav ol { list-style: none; margin: 0; padding: 0; display: flex; gap: var(--s3); overflow-x: auto; scrollbar-width: none; }
.p-nav a { display: inline-flex; align-items: center; gap: .5em; padding-block: .6em; white-space: nowrap; font: 500 var(--fs-xs)/1 var(--mono); text-transform: uppercase; letter-spacing: .06em; text-decoration: none; color: var(--muted); transition: color var(--t); }
.p-nav a::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); transform: scale(0); transition: transform var(--t); }
.p-nav a:hover, .p-nav a[aria-current] { color: var(--ink); }
.p-nav a[aria-current]::before { transform: none; }
@supports (animation-timeline: scroll()) {
  .p-nav::after { content: ""; position: absolute; left: 0; bottom: -1px; width: 100%; height: 1px; background: var(--ink); transform-origin: left; animation: progress linear both; animation-timeline: scroll(root); }
  @keyframes progress { from { transform: scaleX(0); } }
}

/* Section flow: content column with optional full-bleed rows */
.p-flow { display: grid; grid-template-columns: [full-start] minmax(var(--gutter), 1fr) [content-start] minmax(0, var(--content)) [content-end] minmax(var(--gutter), 1fr) [full-end]; row-gap: var(--s5); padding-block: var(--s6) var(--s4); }
.p-flow > * { grid-column: content; min-width: 0; }
.p-flow > .bleed { grid-column: full; }
.bleed figcaption { padding-inline: var(--gutter); }

/* Section opener */
.p-open { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--s2) var(--s4); align-items: end; padding-top: var(--s2); border-top: 1px solid var(--line); }
.p-open::before { content: ""; grid-column: 1 / -1; width: .75rem; height: .75rem; border-radius: 50%; background: var(--accent); margin-bottom: var(--s3); }
.p-open h2 { font-size: clamp(3rem, 8.5vw, 8rem); overflow: hidden; padding-bottom: .08em; }
.p-open h2 span { display: inline-block; transform: translateY(105%); transition: transform .9s var(--ease); }
.p-open.in h2 span { transform: none; }
.p-open.reveal { opacity: 1; transform: none; }
.p-open p { font-size: clamp(1.35rem, 2.15vw, 1.8rem); line-height: 1.25; letter-spacing: -0.02em; color: var(--muted); margin: 0; max-width: 30ch; }

/* Sub-section row: text on the left third (sticky), content on the right two thirds */
.p-row { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: var(--s5); padding-top: var(--s2); border-top: 1px solid var(--hair); }
.p-side { position: sticky; top: calc(var(--topbar-h) + 3.25rem + var(--s3)); align-self: start; }
.p-side .meta { display: block; margin-bottom: var(--s1); }
.p-side h3 { font-size: var(--fs-lg); line-height: 1.1; letter-spacing: -0.025em; }
.p-side h3 + * { margin-top: var(--s2); }
.p-side p { max-width: 36ch; }
.p-side > :last-child { margin-bottom: 0; }
.p-content { min-width: 0; }
.p-side .m-list { margin-top: var(--s3); grid-template-columns: 1fr; gap: var(--s3); }
.m-list .li-icon { display: block; height: var(--icon, 2.25rem); width: auto; margin-bottom: var(--s2); }
.m-list li:has(.li-icon) { border-top: 0; padding-top: 0; }
.m-list span.li-icon, .m-timeline span.li-icon { display: block; width: 2.5rem; height: 2.5rem; margin-bottom: var(--s2); }
.ico { width: 100%; height: 100%; fill: none; stroke: var(--ink); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.ico .acc { stroke: var(--accent); }
.ico .accf { fill: var(--accent); stroke: none; }
.m-timeline .li-icon { margin-top: var(--s1); }
/* inside a row the row divider is already above: no second line over the numbers or the quote */
.p-content .m-list li { border-top: 0; padding-top: 0; }
.p-content > .m-quote { border: 0; padding-block: var(--s1) 0; }
.m-list li::before { margin-bottom: var(--s1); }
.p-side .m-list li:first-child { border-top: 0; padding-top: 0; }
/* list items paired with their own image row */
.p-row.pair { border-top: 0; padding-top: 0; margin-top: calc(var(--s3) - var(--s5)); }
.pair .p-side { position: static; }
.pair .m-list { margin-top: 0; }
.pair .m-list li:first-child { border-top: 1px solid var(--line); padding-top: var(--s2); }
/* the first item already sits under the row divider */
.p-row:not(.pair) + .pair .m-list li:first-child { border-top: 0; padding-top: 0; }

/* Live text placed on an image (`labels`), in the shared caption / figure-label styles */
.img-label { position: absolute; margin: 0; }
.img-label.caption { font: var(--type-caption); color: var(--muted); }
.img-label.label { font: var(--type-fig-label); text-transform: uppercase; letter-spacing: .08em; color: var(--ink); }
.img-label.center { transform: translateX(-50%); text-align: center; white-space: nowrap; }
@media (max-width: 560px) {
  /* each centred caption wraps within its own panel width, in a smaller size, so it stays in the gap under it */
  .img-label.caption { font-size: .45rem; line-height: 1.05; margin-top: -.15rem; }
  .img-label.center { white-space: normal; width: var(--lw, 22%); }
}
.beside { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: var(--s4); align-items: start; }
.p-row.wide .p-side:empty { display: none; }
.p-row.wide { grid-template-columns: 1fr; gap: var(--s3); }
.p-row.joined { border-top: 0; padding-top: 0; }
.p-row.wide .p-side { position: static; max-width: calc((100% - var(--s5)) / 3); }
.m-body { max-width: var(--measure); }
.m-body > :last-child { margin-bottom: 0; }

/* Figures, captions, annotations */
.m-fig { margin: 0; min-width: 0; }
/* Images are shown whole, on the page background: no frame fill, no cropping, no zoom */
.m-frame { position: relative; }
.m-frame > :first-child { display: block; width: 100%; height: auto; object-fit: contain; border: 0; }
.ph-m { display: grid; place-items: center; width: 100%; background: var(--tint); }
.ph-m span { font: var(--type-fig-label); text-transform: uppercase; letter-spacing: .08em; color: var(--muted); padding: 0 1em; text-align: center; }
figcaption { display: flex; flex-wrap: wrap; gap: .25rem var(--s2); align-items: baseline; margin-top: var(--s1); }
.fig-label { font: var(--type-fig-label); text-transform: uppercase; letter-spacing: .08em; color: var(--ink); white-space: nowrap; }
.caption { font: var(--type-caption); color: var(--muted); max-width: 60ch; }
.anno { position: absolute; display: inline-flex; align-items: center; gap: .45em; padding: .45em .8em .45em .55em; border-radius: 99px; font: var(--type-callout); color: #fff; background: var(--ink); white-space: nowrap; }
.anno::before { content: ""; width: .5em; height: .5em; border-radius: 50%; background: var(--accent); }
.chip { position: absolute; top: var(--s2); left: var(--s2); padding: .4em .7em; font: var(--type-fig-label); text-transform: uppercase; letter-spacing: .08em; background: #fff; border: 1px solid var(--ink); }

.embed-poster { position: relative; display: block; width: 100%; padding: 0; border: 0; background: none; cursor: pointer; }
.embed-poster img { width: 100%; height: 100%; object-fit: cover; }
.embed-poster .play { position: absolute; left: 50%; top: 50%; width: 4.5rem; height: 4.5rem; margin: -2.25rem 0 0 -2.25rem; border-radius: 50%; background: var(--accent); transition: transform var(--t); }
.embed-poster .play::after { content: ""; position: absolute; left: 1.8rem; top: 1.45rem; border-style: solid; border-width: .8rem 0 .8rem 1.3rem; border-color: transparent transparent transparent #fff; }
.embed-poster:hover .play, .embed-poster:focus-visible .play { transform: scale(1.08); }

/* Views of spatial concepts float with one shared shadow; `rounded` gives photos the frame radius */
.floating .m-frame > img, .m-seq.floating .seq-stage { filter: drop-shadow(0 18px 28px color-mix(in srgb, var(--ink) 22%, transparent)); }
/* same corner as the view panels (64px on a 2166px-wide view = 2.95% of the width), at any size */
.rounded .m-frame { container-type: inline-size; }
.rounded .m-frame > img { border-radius: 2.95cqw; }

/* Module: marquee (edge-to-edge sliding strip) */
.m-marquee { position: relative; overflow: hidden; padding-block: 0 var(--s4); }
.mq-track { display: flex; gap: var(--s3); width: max-content; padding-right: var(--s3); animation: mq var(--dur) linear infinite; }
.mq-track img { flex: none; height: clamp(11rem, 24vw, 21rem); width: auto; }
.m-marquee:hover .mq-track, .m-marquee.paused .mq-track { animation-play-state: paused; }
.mq-toggle { left: auto; right: var(--gutter); bottom: var(--s2); }
@keyframes mq { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .m-marquee { overflow-x: auto; } }

/* Stepped diagram: groups fade in turn; rows on the left dim when not the current one */
.dg-steps { position: relative; }
.dg-steps .seq-toggle { top: 0; bottom: auto; left: 0; }
.dg-steps [class*="k-"] { transition: opacity .9s cubic-bezier(.45, 0, .2, 1); will-change: opacity; }
.p-side .rows > div { transition: opacity .9s cubic-bezier(.45, 0, .2, 1); }
.p-side .rows > div.dim { opacity: .3; }

/* Highlighted phrases in body text (key statements), in the accent colour */
.m-body em.hl { font-style: normal; color: var(--accent); }

/* Interaction demo (sequence): frames crossfade in place */
.m-seq { margin: 0; }
.seq-stage { position: relative; }
.seq-stage img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; opacity: 0; z-index: 0; }
.seq-stage img.prev { opacity: 1; z-index: 1; }
.seq-stage img.on { opacity: 1; z-index: 2; animation: seq-in .5s ease-in-out both; }
@keyframes seq-in { from { opacity: 0; } to { opacity: 1; } }
.seq-toggle { z-index: 3; position: absolute; left: var(--s2); bottom: var(--s2); width: 2.5rem; height: 2.5rem; border: 0; border-radius: 50%; background: color-mix(in srgb, var(--ink) 75%, transparent); cursor: pointer; }
.seq-toggle::before, .seq-toggle::after { content: ""; position: absolute; top: .8rem; width: .25rem; height: .9rem; background: #fff; border-radius: 1px; }
.seq-toggle::before { left: .9rem; }
.seq-toggle::after { left: 1.35rem; }
.seq-toggle[aria-pressed="true"]::before { left: 1rem; width: 0; height: 0; border-radius: 0; background: none; border-style: solid; border-width: .45rem 0 .45rem .75rem; border-color: transparent transparent transparent #fff; }
.seq-toggle[aria-pressed="true"]::after { display: none; }

/* Module: columns (side-by-side comparison) */
.m-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); gap: var(--s3); }
.m-cols .col { padding: var(--s3); border-radius: var(--frame-radius); background: var(--tint); }
.m-cols .col.accent { background: color-mix(in srgb, var(--accent) 10%, #fff); }
.m-cols .col .meta { display: block; margin-bottom: var(--s1); }
.m-cols .col.accent .meta { color: var(--accent); }
.m-cols h4 { margin: 0 0 var(--s2); font: 600 1.25rem/1.2 var(--font-display); letter-spacing: -0.02em; }
.m-cols p { margin: 0; font-size: var(--fs-sm); }
.m-cols ul { list-style: none; margin: 0; padding: 0; }
.m-cols li { position: relative; padding: .55rem 0 .55rem 1.25rem; border-top: 1px solid var(--hair); font-size: var(--fs-sm); }
.m-cols li:first-child { border-top: 0; }
.m-cols li::before { content: ""; position: absolute; left: 0; top: 1rem; width: .5rem; height: .5rem; border-radius: 50%; background: var(--ink); }
.m-cols .col.accent li::before { background: var(--accent); }

/* Horizontal scroller shared by carousel, storyboard, timeline */
.scroller { display: grid; grid-auto-flow: column; grid-auto-columns: var(--col, minmax(16rem, 1fr)); grid-template-columns: none; gap: var(--s3); overflow-x: auto; scroll-snap-type: x mandatory; overscroll-behavior-x: contain; padding-bottom: var(--s2); scrollbar-width: thin; }
.scroller > * { scroll-snap-align: start; }

/* Module: gallery / carousel */
.m-gallery { display: grid; grid-template-columns: repeat(var(--cols), minmax(0, 1fr)); gap: var(--s3); align-items: start; }
.m-gallery .wide { grid-column: span 2; }
.m-gallery.scroller { --col: min(85%, 34rem); grid-template-columns: none; }

/* Shared iPhone mockup: generic modern phone (titanium edge, black bezel, island, side buttons). Screens keep their proportions. */
:root { --phone-w: clamp(10rem, 15vw, 13.5rem); --shadow-phone: 0 22px 36px color-mix(in srgb, var(--ink) 24%, transparent); }
.phone-frame, .iphone .device, .m-seq.iphone .seq-stage {
  --b: calc(var(--phone-w) * .038); --r: calc(var(--phone-w) * .17);
  position: relative; width: var(--phone-w); padding: var(--b); box-sizing: content-box; border-radius: var(--r);
  background: #0b0b0c;
  box-shadow: 0 0 0 calc(var(--phone-w) * .012) #3a3a3d, 0 0 0 calc(var(--phone-w) * .018) #1e1e20, var(--shadow-phone);
}
.phone-frame img, .iphone .device img, .m-seq.iphone .seq-stage img { display: block; width: 100%; height: auto; border-radius: calc(var(--r) - var(--b)); }
.phone-frame::after, .iphone .device::after, .m-seq.iphone .seq-stage::after { content: ""; position: absolute; z-index: 3; top: calc(var(--b) + var(--phone-w) * .022); left: 50%; width: 30%; height: calc(var(--phone-w) * .085); transform: translateX(-50%); border-radius: 99px; background: #0b0b0c; }
.phone-frame::before, .iphone .device::before, .m-seq.iphone .seq-stage::before { content: ""; position: absolute; left: calc(var(--phone-w) * -.03); top: 22%; width: calc(var(--phone-w) * .016); height: 9%; border-radius: 2px; background: #2c2c2e; box-shadow: 0 calc(var(--phone-w) * .24) 0 #2c2c2e, calc(var(--phone-w) * 1.1) calc(var(--phone-w) * .16) 0 #2c2c2e; }
.m-seq.iphone .seq-stage { aspect-ratio: auto !important; margin-inline: auto; }
.m-seq.iphone .seq-stage img { position: absolute; inset: var(--b); width: calc(100% - 2 * var(--b)); height: calc(100% - 2 * var(--b)); }
.m-seq.iphone .seq-stage img:first-child { position: relative; inset: auto; width: 100%; height: auto; }
.m-seq.iphone { --phone-w: clamp(11rem, 18vw, 15rem); }
.m-seq.iphone figcaption { justify-content: center; margin-top: var(--s4); }
.m-seq.iphone .seq-toggle { left: calc(100% + var(--s3)); bottom: 0; }
.iphone .row { gap: var(--s4); padding: var(--s2) var(--s2) var(--s3); }
.iphone .shot { width: calc(var(--phone-w) + 2 * var(--phone-w) * .038); }
.iphone .shot figcaption { justify-self: start; margin-top: 0; }

/* Module: phone slider */
.m-pslider { position: relative; }
@media (max-width: 560px) { .m-pslider .ps-track { padding-inline: var(--gutter); margin-inline: calc(-1 * var(--gutter)); scroll-padding-inline: var(--gutter); } }
.ps-track { display: flex; gap: var(--s4); overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: var(--s5); scrollbar-width: none;
  /* room around the phones so frames, side buttons and shadows are never clipped; edges fade instead of cutting */
  padding: var(--s4) var(--s5) var(--s5); margin: calc(-1 * var(--s4)) calc(-1 * var(--s5)) calc(-1 * var(--s3));
  -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--s4), #000 calc(100% - var(--s4)), transparent);
          mask-image: linear-gradient(to right, transparent, #000 var(--s4), #000 calc(100% - var(--s4)), transparent); }
.ps-track::-webkit-scrollbar { display: none; }
.ps-slide { flex: none; margin: 0; display: grid; gap: var(--s2); scroll-snap-align: start; }
.ps-slide figcaption { display: grid; gap: .15rem; margin: 0; }
.ps-nav { display: flex; gap: var(--s1); justify-content: flex-end; padding-right: var(--s2); }
.ps-btn { width: 2.75rem; height: 2.75rem; border-radius: 50%; border: 1px solid var(--line); background: var(--bg); cursor: pointer; position: relative; transition: background var(--t); }
.ps-btn:hover { background: var(--ink); }
.ps-btn::after { content: ""; position: absolute; left: 50%; top: 50%; width: .55rem; height: .55rem; border: solid var(--ink); border-width: 1.5px 1.5px 0 0; transform: translate(-65%, -50%) rotate(45deg); }
.ps-prev::after { transform: translate(-35%, -50%) rotate(-135deg); }
.ps-btn:hover::after { border-color: var(--bg); }
.ps-feats { margin-top: var(--s3); grid-template-columns: 1fr; gap: var(--s2); }
.ps-feats li { padding-top: var(--s2); border-top: 1px solid var(--hair); }
.ps-feats li:first-child { border-top: 0; padding-top: 0; }
.ps-feat { all: unset; cursor: pointer; }
.ps-feat h4 { transition: color var(--t); }
.ps-feat:hover h4, .ps-feat.on h4 { color: var(--accent); }
.ps-feat:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 3px; }

/* Storyboard extras: touchpoint and opportunity under a panel */
.m-story.journey { grid-template-rows: auto auto auto auto; row-gap: 0; }
.m-story.journey > li:not(.opp-cell) { grid-row: 1 / span 3; display: grid; grid-template-rows: subgrid; gap: var(--s1); }
.m-story.journey > li.opp-cell { grid-row: 4; }
/* narrow screens: one column, each opportunity right after the panel(s) it belongs to (--o set in project.js) */
@media (max-width: 820px) { .m-story.journey { grid-template-columns: minmax(0, 28rem); grid-template-rows: none; row-gap: var(--s3); } .m-story.journey > li { grid-column: auto !important; grid-row: auto !important; order: var(--o); } .m-story.journey > li:not(.opp-cell) { grid-template-rows: none; } }
.m-story .meta { display: block; margin-top: var(--s1); color: var(--accent); }
.m-story .panel-text.opp { margin-top: var(--s1); padding-top: var(--s1); border-top: 1px solid var(--hair); }
.m-story .panel-text.opp .meta { color: var(--muted); margin: 0 0 .2rem; }

/* Module: key insight / quote */
.m-quote { margin: 0; padding-block: var(--s5); border-block: 1px solid var(--line); display: grid; gap: var(--s3); }
.m-quote p { font: 500 clamp(1.75rem, 3.6vw, 3.25rem)/1.08 var(--font-display); letter-spacing: -0.03em; max-width: 24ch; margin: 0; }
.m-quote cite { font-style: normal; }
.dot { display: inline-block; width: .6em; height: .6em; border-radius: 50%; background: var(--accent); margin-right: .6em; }

/* Module: findings / goals list */
.m-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); gap: var(--s4) var(--s3); counter-reset: item; }
.m-list li { counter-increment: item; padding-top: var(--s2); border-top: 1px solid var(--line); }
.m-list li::before { content: counter(item, decimal-leading-zero); display: block; margin-bottom: var(--s3); font: var(--type-meta); letter-spacing: .06em; color: var(--accent); }
.m-list h4, .persona h4, .m-timeline h4 { margin: 0 0 var(--s1); font: 600 1.25rem/1.15 var(--font-display); letter-spacing: -0.02em; }
.m-list p, .m-timeline p { margin: 0; font-size: var(--fs-sm); color: var(--muted); }
.m-list.cards li { border: 1px solid var(--line); padding: var(--s3); transition: background var(--t); }
.m-list.cards li:hover { background: var(--tint); }

/* Module: stats */
.m-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: var(--s3); margin: 0; }
.m-stats div { display: flex; flex-direction: column-reverse; justify-content: flex-end; gap: var(--s1); padding-top: var(--s2); border-top: 1px solid var(--line); }
.m-stats dd { margin: 0; font: 600 var(--fs-xl)/1 var(--font-display); letter-spacing: -0.04em; }
.m-stats dt { font: var(--type-caption); text-transform: none; letter-spacing: 0; }

/* Module: personas (portrait slot + name + quote + trait rows) */
.m-personas { display: grid; gap: var(--s5); }
.persona { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: var(--s5); align-items: start; }
.persona-visual > * { width: 100%; object-fit: cover; }
.persona-body .meta { display: block; margin-bottom: var(--s2); }
.persona-name { margin: 0; font: 600 clamp(2.5rem, 5vw, 4rem)/.95 var(--font-display); letter-spacing: -0.035em; }
.persona-role { margin: var(--s1) 0 var(--s4); font-size: var(--fs-md); color: var(--muted); }
.persona-quote { margin: 0 0 var(--s4); font: 500 var(--fs-lg)/1.2 var(--font-display); letter-spacing: -0.02em; max-width: 30ch; }

/* Label/value rows (persona traits, target group) */
.rows { display: block; margin: var(--s3) 0 0; }
.rows div:last-child { border-bottom: 0; }
.rows div { display: grid; grid-template-columns: 10rem 1fr; gap: var(--s2); padding: var(--s1) 0; border-bottom: 1px solid var(--hair); }
.rows dt { padding-top: .2em; }
.rows dd { margin: 0; font-size: var(--fs-md); }

/* No bullets in body text: lists read as hairline rows */
.m-body ul { list-style: none; margin: 0 0 var(--s2); padding: 0; border-top: 1px solid var(--hair); }
.m-body ul li { padding: var(--s1) 0; border-bottom: 1px solid var(--hair); }

/* Module: diagram container + diagram language (inline SVG uses these classes) */
.m-diagram { margin: 0; }
.dg-scroll { overflow-x: auto; }
.dg { margin-inline: auto; }
.dg svg, .dg img { display: block; width: 100%; height: auto; overflow: visible; color: var(--dg-line); }
.dg text { font: var(--type-dg); fill: var(--ink); }
.dg .note { font: var(--type-caption); letter-spacing: 0; fill: var(--muted); }
.dg .node { fill: var(--dg-fill); stroke: var(--dg-line); stroke-width: var(--dg-stroke); vector-effect: non-scaling-stroke; }
.dg .node.soft { fill: var(--tint); stroke: var(--dg-soft); }
.dg .node.hi, .dg .node.start { fill: var(--dg-hi); stroke: var(--dg-hi); }
.dg .node.choice { fill: var(--tint); stroke: var(--dg-line); }
.dg .fa { fill: color-mix(in srgb, var(--accent) 22%, #fff); }   /* diagrams converted from vector sources */
.dg .fi { fill: var(--ink); }
.dg .fb { fill: var(--accent); }
.dg .fg { fill: var(--tint); }
.dg .fw { fill: #fff; }
.dg .fn { fill: #fff; stroke: var(--dg-line); stroke-width: 2.5; }
.dg .fh { fill: var(--dg-hi); }
.dg text.on-dark { fill: #fff; }
.dg .edge { fill: none; stroke: var(--dg-line); stroke-width: var(--dg-stroke); vector-effect: non-scaling-stroke; }
.dg .edge.alt { stroke: var(--dg-alt); stroke-dasharray: 4 4; }
.dg .edge.soft { stroke: var(--dg-soft); }

/* Module: storyboard */
.m-story { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr)); gap: var(--s4) var(--s3); }
.m-story li { display: grid; gap: var(--s1); align-content: start; }
.m-story .ph-m { border: 1px solid var(--hair); }
.m-story img, .outlined .m-frame > img { border: 1px solid var(--frame); border-radius: var(--frame-radius); }
.m-story .fig-label { margin-top: var(--s1); }
.panel-text { margin: 0; font: var(--type-panel); color: var(--muted); }

/* Module: screens (phone, desktop or unframed) */
.m-screens { margin: 0; }
.m-screens .row { display: flex; gap: var(--s3); overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: var(--s1); }
.m-screens .row > :first-child { margin-left: auto; }
.m-screens .row > :last-child { margin-right: auto; }
.shot { flex: none; display: grid; gap: var(--s2); justify-items: center; align-content: start; scroll-snap-align: center; }
.shot figcaption { justify-self: start; margin-top: 0; }
.device { overflow: hidden; background: #fff; }
/* frame: "mockup" — the image already contains the device, shown at one shared height */
.mockup .device { background: none; }
.mockup .device img { height: clamp(12rem, 17vw, 17rem); width: auto; max-width: none; }
.phone .device { width: clamp(11rem, 20vw, 16rem); border: 8px solid var(--ink); border-radius: 2rem; }
.desktop .shot, .none .shot { width: min(56rem, 100%); }
.desktop .device, .none .device { width: 100%; border: 1px solid var(--line); }
.desktop .device { position: relative; border-top: 1.75rem solid #fff; box-shadow: inset 0 1px 0 var(--hair); }
.desktop .device::before { content: ""; position: absolute; top: -1.15rem; left: .75rem; width: 2.6rem; height: .55rem; background: radial-gradient(circle, var(--dg-soft) .27rem, transparent .3rem) 0 0 / .9rem .55rem repeat-x; }

/* Module: information architecture tree (same structure as the source, site type and hairlines) */
.m-ia { margin: 0; display: grid; gap: var(--s5); }
.ia-tree { display: grid; gap: var(--s2); }
.iat { --ia-line: var(--accent); --bh: 2.5rem; --g: 1.75rem; --t: 1rem; --drop: 1.5rem; --ng: 1.25rem; display: grid; grid-template-columns: repeat(var(--n), minmax(9.5rem, 1fr)); column-gap: var(--g); min-width: calc(var(--n) * 10.5rem); padding-bottom: var(--s1); }
.iat-box { height: var(--bh); display: flex; align-items: center; padding: 0 .8rem; border: 1px solid var(--line); background: var(--bg); font: 600 .95rem/1 var(--font-display); letter-spacing: -0.01em; white-space: nowrap; }
.iat-items { list-style: none; margin: .6rem 0 0; padding: 0 0 0 .8rem; font-size: var(--fs-sm); line-height: 1.35; }
.iat-items li { padding: .15rem 0; }
.iat-items li span { display: block; font: var(--type-caption); color: var(--muted); }
.iat-col, .iat-node { position: relative; }
/* bus: root on the left, children hang from one horizontal line */
.bus .branch { display: grid; align-content: start; gap: var(--ng); padding: calc(var(--bh) / 2 + var(--drop)) 0 0 var(--t); }
.bus .branch::before { content: ""; position: absolute; top: calc(var(--bh) / 2); left: calc(-1 * var(--g)); width: var(--g); border-top: 1px solid var(--ia-line); }
.bus .branch + .branch::before { left: calc(-100% - var(--g)); width: calc(100% + var(--g)); }
.branch .iat-node::before { content: ""; position: absolute; left: calc(-1 * var(--t)); top: calc(-1 * var(--ng)); width: var(--t); height: calc(var(--ng) + var(--bh) / 2); border: solid var(--ia-line); border-width: 0 0 1px 1px; }
.branch .iat-node:first-child::before { top: calc(-1 * var(--drop)); height: calc(var(--drop) + var(--bh) / 2); }
.branch .iat-node:not(:last-child)::after { content: ""; position: absolute; left: calc(-1 * var(--t)); top: calc(var(--bh) / 2); bottom: 0; border-left: 1px solid var(--ia-line); }
/* chain: top-level pages in sequence, child pages hang below their parent */
.chain .iat-col + .iat-col::before { content: ""; position: absolute; top: calc(var(--bh) / 2); left: calc(-1 * var(--g) + 4px); width: calc(var(--g) - 8px); border-top: 1px solid var(--ia-line); }
.chain .iat-col + .iat-col::after { content: ""; position: absolute; top: calc(var(--bh) / 2 - 3.5px); left: -11px; width: 6px; height: 6px; border: solid var(--ia-line); border-width: 1px 1px 0 0; transform: rotate(45deg); }
.under { position: relative; margin-left: .9rem; padding-left: var(--t); }
.under .iat-items { padding-left: 0; }
.under.has-kids { display: grid; gap: var(--ng); border-left: 1px solid var(--ia-line); }
.under.has-kids > .iat-node::before { content: ""; position: absolute; left: calc(-1 * var(--t)); top: calc(var(--bh) / 2); width: var(--t); border-top: 1px solid var(--ia-line); }
.under.has-kids > .iat-node:last-child::after { content: ""; position: absolute; left: calc(-1 * var(--t) - 2px); top: calc(var(--bh) / 2 + 1px); bottom: 0; width: 3px; background: var(--bg); }

.bus > .iat-col:first-child .iat-box, .chain > .iat-col > .iat-box { background: var(--accent); border-color: var(--accent); }

/* Module: color palette */
.m-swatches { display: grid; gap: var(--s4); }
.sw-group { display: grid; gap: var(--s2); }
.sw-row { display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); gap: var(--s3); }
.sw { display: grid; gap: .5rem; align-content: start; }
.sw-chip { aspect-ratio: 16 / 9; border-radius: var(--frame-radius); background: var(--c); }
.sw-tints { display: flex; gap: 4px; margin-top: -2px; }
.sw-tints i { flex: 1; height: 1.25rem; border-radius: 6px; background: color-mix(in srgb, var(--c) 75%, #fff); }
.sw-tints i:nth-child(2) { background: color-mix(in srgb, var(--c) 50%, #fff); }
.sw-tints i:nth-child(3) { background: color-mix(in srgb, var(--c) 28%, #fff); }
.sw code { font: var(--type-meta); letter-spacing: .06em; color: var(--muted); }

/* Module: type scale */
.m-type { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr)); gap: var(--s4); }
.tf-head { display: flex; gap: var(--s2); align-items: center; padding-bottom: var(--s2); }
.tf-aa { font-size: 3rem; line-height: 1; font-weight: 700; color: var(--accent); }
.tf-head b { display: block; font: 600 1.25rem/1.2 var(--font-display); }
.tf table { width: 100%; border-collapse: collapse; }
.tf th, .tf td { text-align: left; padding: .6rem .5rem .6rem 0; border-bottom: 1px solid var(--hair); vertical-align: middle; font-weight: 400; }
.tf thead th { border-bottom-color: var(--line); }
.tf td span { line-height: 1; }

/* Module: layout grid (zones) */
.m-zones { margin: 0; }
.zones { position: relative; max-width: 20rem; border: 8px solid var(--ink); border-radius: 20px; box-sizing: content-box; }
.zone { position: absolute; display: grid; place-items: center; text-align: center; border: 1.5px dashed var(--ink); font: 600 .8rem/1.15 var(--font-display); color: var(--ink); padding: .2rem; }
.zone.fill { border: 0; background: var(--ink); color: #fff; }
.zone.label { border: 0; }
.zone.big span { font-size: 1.1rem; }

/* Module: before / after */
.m-compare { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); }

/* Module: process timeline */
.m-timeline { list-style: none; margin: 0; padding: 6px 0 var(--s2); gap: 0; --col: minmax(13rem, 40%); }
/* hint that it scrolls: the next phase peeks in and the right edge fades out (until the end is reached) */
.m-timeline:not(.at-end) { -webkit-mask-image: linear-gradient(to right, #000 80%, transparent); mask-image: linear-gradient(to right, #000 80%, transparent); }
.m-timeline li { position: relative; padding: var(--s3) var(--s3) 0 0; border-top: 1px solid var(--line); }
.m-timeline li::before { content: ""; position: absolute; top: -5px; left: 0; width: 9px; height: 9px; border-radius: 50%; background: var(--bg); border: 1px solid var(--ink); }
.m-timeline .meta { display: block; margin-bottom: var(--s1); }

/* Previous / next */
.p-pager { display: grid; grid-template-columns: 1fr 1fr; border-top: 1px solid var(--line); margin-top: var(--s5); }
.p-pager a { text-decoration: none; padding: var(--s4) 0; font: 600 var(--fs-xl)/1 var(--font-display); letter-spacing: -0.035em; transition: color var(--t); }
.p-pager a:last-child { text-align: right; border-left: 1px solid var(--line); }
.p-pager a:hover { color: var(--accent); }
.p-pager span { display: block; font: 500 var(--fs-xs) var(--mono); text-transform: uppercase; letter-spacing: .06em; margin-bottom: var(--s2); color: var(--muted); }

/* Subtle parallax on cover and full-bleed visuals (scroll-driven, no JS) */
@supports (animation-timeline: view()) {
  .p-cover .cover, .bleed .m-frame > :first-child { animation: drift linear both; animation-timeline: view(); }
  @keyframes drift { from { transform: translateY(-4%) scale(1.08); } to { transform: translateY(4%) scale(1.08); } }
}

@media (max-width: 960px) {
  .m-gallery:not(.scroller) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 820px) {
  /* diagrams: title and intro, then the figure, then the notes on each part (the side column splits around it) */
  .p-row:has(.p-side-more) { display: flex; flex-direction: column; gap: 0; }
  .p-row:has(.p-side-more) > .p-side { display: contents; }
  .p-row:has(.p-side-more) > .p-content { margin-top: var(--s3); }
  .p-side-more { order: 2; margin-top: var(--s3); }
  .p-hero-row, .p-open { grid-template-columns: 1fr; }
  .p-cover .cover, .p-cover.layered { aspect-ratio: 4 / 3; }
  .p-flow { row-gap: var(--s4); padding-block: var(--s5) var(--s3); }
  .p-nav { justify-content: flex-start; }
  .p-nav-title { display: none; }
  .p-row { grid-template-columns: 1fr; gap: var(--s3); }
  .p-side { position: static; }
  .p-row.wide .p-side { max-width: none; }
  .m-story { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .persona, .beside { grid-template-columns: 1fr; gap: var(--s3); }
  .persona-visual { max-width: 16rem; }
  .rows div { grid-template-columns: 7rem 1fr; }
  .p-pager a { font-size: var(--fs-lg); }
}
@media (max-width: 560px) {
  .dg { min-width: 0 !important; --dg-stroke: .6px; } /* hairlines: diagrams shrink a lot on phones, outlines should too */
  /* key-feature screens wrap into rows that fit instead of a sideways scroll */
  .m-screens .row { flex-wrap: wrap; justify-content: center; align-items: flex-end; overflow: visible; scroll-snap-type: none; row-gap: var(--s3); }
  .m-screens .row > :first-child, .m-screens .row > :last-child { margin-inline: 0; }
  .mockup .device img { height: auto; width: auto; max-width: 100%; max-height: min(28rem, 62svh); } /* one per line, so each can be as big as the screen allows */
  .m-screens .shot { max-width: 100%; }
  .mockup .device { overflow: visible; translate: var(--shift, 0) 0; } /* the slot and caption stay centred; only the picture moves so the phone sits on the centre line */
  .m-screens .shot figcaption { justify-self: center; } /* caption centred under the phone, moving with it */ /* centre the device itself, not the cards that stick out of it (shift measured per image) */ /* phones: diagrams fit the screen (whole image at once) instead of a sideways swipe */
  .m-gallery:not(.scroller), .m-compare, .persona-cols { grid-template-columns: 1fr; }
  .m-gallery .wide { grid-column: auto; }
}

/* ---------- Motion ---------- */
.reveal { opacity: 0; transform: translateY(12px); transition: opacity .5s var(--ease), transform .5s var(--ease); }
.load { animation: rise .6s var(--ease) both; }
@keyframes rise { from { opacity: 0; transform: translateY(14px); } }
main { animation: fade .4s ease-out both; }
@keyframes fade { from { opacity: 0; } }

/* Cursor dot */
.cursor-dot { position: fixed; top: 0; left: 0; width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: 50%; background: var(--accent); pointer-events: none; z-index: 100; transition: opacity .3s; } /* no blend mode: over the flickering grain it made the dot flicker too */
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .reveal { opacity: 1; transform: none; }
  .p-open h2 span, .m-fig .m-frame > :first-child { transform: none !important; }
}
