/* danbianchi.com — 2026 refresh. All values from tokens/ (see styles.css). */

* { box-sizing: border-box; }
html, body { margin: 0; }
/* The hero pattern deliberately bleeds past the content column. Clip that
   overhang at the root so narrow viewports never scroll sideways. Must be on
   html, not body: overflow on body propagates to the viewport instead of
   clipping. `clip` rather than `hidden` so the sticky nav keeps working. */
html { overflow-x: clip; }
body {
  background: var(--bg-page);
  color: var(--text-primary);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  transition: background var(--dur-base, 200ms) var(--ease-out, ease-out);
}
a { color: var(--link); }
img { max-width: 100%; display: block; }
button { font-family: var(--font-body); }

:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--accent-ring); border-radius: 4px; }

/* Two widths, not one. The shell is wide so work and imagery can breathe;
   prose is capped to a reading measure. A single 840px column was over the
   80-character accessibility ceiling for body text and still cramped the
   screenshots. */
:root {
  --w-page: 1200px;  /* nav, work grid, media, footer */
  /* Deliberately px, not ch: ch resolves against each element's own font size,
     so one shared ch token yields a different measure at 16px than at 24px.
     These are calibrated from measured characters per line. */
  --w-prose: 640px;  /* 18px body copy  → ~68 characters */
  --w-lede: 740px;   /* 24px intro text → ~62 characters */
  /* Long-form case-study prose sits larger and looser than UI text. 16px at
     1.4 was fine for labels but cramped for reading at this page length. */
  --fs-prose: 18px;
  --lh-prose: 1.6;
}
.container { max-width: calc(var(--w-page) + 64px); margin: 0 auto; padding: 0 32px; }
@media (max-width: 760px) { .container { padding: 0 24px; } }

@keyframes fadeUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.view { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
  .view { animation: fadeUp 360ms cubic-bezier(0.22, 1, 0.36, 1); }
}

/* ---- Nav ---- */
.navbar {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--bg-page) 72%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.nav { position: relative; display: flex; align-items: center; gap: 25px; padding: 24px 0; }

/* Menu button — only shown below the nav breakpoint (see the media query). */
.nav-toggle {
  display: none;
  align-items: center; justify-content: center;
  margin-left: auto; flex: none;
  width: 44px; height: 44px;
  background: transparent; color: var(--text-primary);
  border: 1px solid var(--border-default); border-radius: var(--radius-md, 10px);
  cursor: pointer;
  transition: border-color 120ms var(--ease-out, ease-out), color 120ms var(--ease-out, ease-out);
}
.nav-toggle:hover { border-color: var(--accent); color: var(--accent); }
.nav-toggle .nav-toggle-icon { display: inline-flex; }
.nav-toggle .lucide, .nav-toggle svg { width: 20px; height: 20px; }
.nav-logo { height: 30px; width: auto; color: var(--text-primary); cursor: pointer; flex: none; }
.nav-logo svg { height: 100%; width: auto; display: block; fill: currentColor; }
.nav-menu { display: flex; justify-content: flex-end; align-items: center; gap: 33px; flex: 1; }
.nav-link {
  background: none; border: none; padding: 0; cursor: pointer;
  font-family: var(--font-body); font-weight: var(--fw-medium); font-size: 16px; line-height: 22px;
  color: var(--text-primary); text-decoration: none;
  display: inline-flex; align-items: center; gap: 2px;
  transition: color 120ms var(--ease-out, ease-out);
}
.nav-link.active { color: var(--accent); }

/* Text roll on hover (see RollLabel in Nav.jsx). The window is exactly one
   line tall and clips the second copy until the stack slides up. */
.nav-link { --roll-line: 22px; }
.roll { display: inline-block; height: var(--roll-line); overflow: hidden; vertical-align: bottom; }
.roll-stack {
  display: flex; flex-direction: column;
  /* 250ms on the soft curve. The house --ease-out is too front-loaded for a
     full line of travel and reads as a snap. */
  transition: transform 250ms var(--ease-out-soft, cubic-bezier(0.33, 1, 0.68, 1));
}
.roll-copy { display: block; line-height: var(--roll-line); }
/* The incoming copy carries the hover colour, so the roll and the colour
   change land together. */
.roll-copy + .roll-copy { color: var(--accent); }
.nav-link:hover .roll-stack,
.nav-link:focus-visible .roll-stack { transform: translateY(-50%); }

@media (prefers-reduced-motion: reduce) {
  .roll-stack { transition: none; }
  /* No movement: fall back to a plain colour change. */
  .nav-link:hover .roll-stack, .nav-link:focus-visible .roll-stack { transform: none; }
  .nav-link:hover, .nav-link:focus-visible { color: var(--accent); }
}
.nav-link .lucide { width: 16px; height: 16px; }

.theme-toggle {
  display: flex; align-items: center; gap: 4px; padding: 3px;
  width: 46px; height: 24px; border: none; cursor: pointer;
  background: var(--bg-raised); border-radius: 12px; flex: none;
}
.theme-toggle .knob {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 999px; color: var(--text-primary);
  transition: background 200ms var(--ease-out, ease-out);
}
.theme-toggle .knob.active { background: var(--accent); color: #FFFFFF; }
.theme-toggle .knob .lucide, .theme-toggle .knob svg { width: 12px; height: 12px; }

/* ---- Home hero ---- */
.hero { position: relative; padding: 48px 0; min-height: 480px; }
.hero::before {
  content: ''; position: absolute; inset: -80px -48px 0;
  background-image: radial-gradient(circle, color-mix(in srgb, var(--accent) 35%, transparent) 0.5px, transparent 1px);
  background-size: 8px 8px;
  -webkit-mask-image: radial-gradient(ellipse 54% 78% at 46% 48%, #000 17%, transparent 100%);
          mask-image: radial-gradient(ellipse 54% 78% at 46% 48%, #000 17%, transparent 100%);
  pointer-events: none;
}
/* Cursor wake over the dot grid, painted to a canvas (see Hero.jsx). Lighter
   than the base dots on dark, darker on light — either way the dots the
   pointer passes over read as lit, then burn off oldest-first. */
.hero { --dot-trail: var(--lavender); }
[data-theme="light"] .hero { --dot-trail: color-mix(in srgb, var(--accent) 55%, #000000); }
/* A wrapper carries the inset: canvas is a replaced element, so `width: auto`
   resolves to its intrinsic 300x150 instead of stretching to the insets. */
.hero-trail { position: absolute; inset: -80px -48px 0; pointer-events: none; }
.hero-trail canvas { display: block; width: 100%; height: 100%; }
@media (prefers-reduced-motion: reduce) { .hero-trail { display: none; } }

.hero > *:not(.hero-trail) { position: relative; }
.hero h1 {
  position: relative; z-index: 0;
  /* Wide enough for three balanced lines; `balance` then does the breaking so
     no word is orphaned and "meaningful experiences" stays together. */
  margin: 0 0 24px; max-width: 860px; text-wrap: balance;
  font-family: var(--font-display); font-weight: var(--fw-hero);
  font-size: clamp(40px, 6vw, var(--size-hero)); line-height: var(--lh-hero); letter-spacing: var(--ls-hero);
  color: var(--text-display);
}
/* 1px outside gradient stroke (Figma: diamond gradient iris-bright → iris-dusk).
   A duplicate glyph layer carries a 2px transparent stroke clipped to the
   gradient; the solid fill above covers the inner half, leaving 1px outside. */
.hero h1::before {
  content: attr(data-text);
  position: absolute; inset: 0; z-index: -1;
  -webkit-text-stroke: 2px transparent;
  background: linear-gradient(135deg, var(--iris-bright) 0%, var(--iris-dusk) 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.hero .lede {
  margin: 0; max-width: var(--w-lede);
  font-family: var(--font-body); font-weight: var(--fw-light);
  font-size: clamp(20px, 3vw, 24px); line-height: 1.375;
  color: var(--text-secondary);
}

/* ---- Project cards (home) — bento-thumb treatment ----
   Stripe-style mechanics: the white face and its border layer are painted
   --grow larger than the card slot and clipped back with clip-path inset();
   hover animates the clip to inset(0), so the card "grows" with no raster
   scaling and no layout shift. The border's gradient glow is a blob that
   chases the cursor via --mouse-x/--mouse-y with a lazy 1s transform. */
.work { display: flex; flex-direction: column; gap: 64px; padding: 32px 0 0; }
.project-card {
  position: relative; z-index: 0; cursor: pointer;
  --grow: 10px;
  --radius: 16px;
  --pad-x: 40px;
  --mouse-x: 50%;
  --mouse-y: 50%;
  --bento-ease: cubic-bezier(0.165, 0.84, 0.44, 1);
  --bento-dur: 800ms;
  /* Card palette. The default is the brand's white card; a project can
     theme its tile (data.js `theme`), which WorkGrid sets inline. */
  --card-bg: #FFFFFF;
  --card-ink: var(--iris-deep);
  --card-sub: var(--iris);
  --card-border: var(--wisteria);
  --card-glow: var(--lavender);
  --card-glow-mid: var(--iris);
}
/* Themed tiles derive the ring and glow from the project's own ink and
   accent so the hover state stays in the project's palette. */
.project-card.themed {
  --card-sub: var(--card-ink);
  --card-border: color-mix(in srgb, var(--card-ink) 18%, var(--card-bg));
  --card-glow: var(--card-accent);
  --card-glow-mid: var(--card-ink);
}
.bento-border {
  position: absolute; inset: calc(-1 * var(--grow) - 1px); z-index: 0;
  border-radius: calc(var(--radius) + 1px);
  background: var(--card-border);
  clip-path: inset(var(--grow) round calc(var(--radius) + 1px));
  transition: clip-path var(--bento-dur) var(--bento-ease);
  overflow: hidden;
}
.bento-glow {
  position: absolute; left: 0; top: 0;
  width: 520px; height: 520px; margin: -260px 0 0 -260px; border-radius: 50%;
  background: radial-gradient(circle, var(--card-glow), var(--card-glow-mid) 33%, var(--card-border) 66%);
  opacity: 0;
  transform: translate3d(var(--mouse-x), var(--mouse-y), 0);
  transition: opacity 250ms ease, transform 1s var(--bento-ease);
  pointer-events: none;
}
.bento-face {
  position: absolute; inset: calc(-1 * var(--grow)); z-index: 1;
  /* The veil is --card-bg laid over the image at (1 - bgImageOpacity), which
     renders the same as the image at that opacity on the tile colour. */
  background:
    linear-gradient(var(--card-bg-veil, transparent), var(--card-bg-veil, transparent)),
    var(--card-bg-image, none) left top / cover no-repeat,
    var(--card-bg);
  border-radius: var(--radius);
  clip-path: inset(var(--grow) round var(--radius));
  transition: clip-path var(--bento-dur) var(--bento-ease);
}
.bento-content {
  position: relative; z-index: 2;
  padding: 40px var(--pad-x) 0; border-radius: var(--radius); overflow: hidden;
}
.project-card.no-media .bento-content { padding-bottom: 40px; }
.project-card-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; flex-wrap: wrap;
  transition: transform var(--bento-dur) var(--bento-ease);
}
/* Let the title block shrink so the button stays on the title row whatever the
   summary length; it only wraps below once the card gets genuinely narrow. */
.project-card-head > div { flex: 1 1 320px; min-width: 0; }
@media (hover: hover) and (pointer: fine) {
  .project-card:hover .bento-face { clip-path: inset(0 round var(--radius)); }
  .project-card:hover .bento-border { clip-path: inset(0 round calc(var(--radius) + 1px)); }
  .project-card:hover .bento-glow { opacity: 0.5; }
  .project-card:hover .project-card-head { transform: translate(-4px, -4px); }
}
@media (prefers-reduced-motion: reduce) {
  .bento-face, .bento-border, .bento-glow, .project-card-head,
  .project-card-media.bleed { transition: none; }
}
.project-card h2 {
  margin: 0 0 6px;
  font-family: var(--font-display); font-weight: var(--fw-bold);
  font-size: 32px; line-height: 1.25; letter-spacing: var(--ls-display);
  color: var(--card-ink);
}
.project-card .sub {
  margin: 0; max-width: var(--w-lede);
  font-family: var(--font-body); font-weight: var(--fw-regular);
  font-size: 20px; line-height: 1.35; color: var(--card-sub);
}
.btn-outline {
  flex: none; padding: 10px 18px; cursor: pointer;
  background: #FFFFFF; color: var(--iris-deep);
  border: 1px solid var(--periwinkle); border-radius: 8px;
  font-family: var(--font-body); font-weight: var(--fw-semibold); font-size: 15px;
  transition: background 120ms var(--ease-out, ease-out), border-color 120ms var(--ease-out, ease-out);
}
.btn-outline:hover { background: var(--petal); border-color: var(--iris); }
.btn-outline:active { transform: scale(0.99) translateY(1px); }
/* On a themed tile the CTA becomes a solid button in the project's accent. */
.project-card.themed .btn-outline {
  background: var(--card-accent); color: var(--card-on-accent, #FFFFFF);
  border-color: var(--card-accent);
}
.project-card.themed .btn-outline:hover {
  background: var(--card-accent-hover, color-mix(in srgb, var(--card-accent) 86%, #000));
  border-color: var(--card-accent-hover, color-mix(in srgb, var(--card-accent) 86%, #000));
}
.project-card-media {
  display: flex; gap: 24px; align-items: flex-start;
  /* Cap scales with the wider shell so covers keep roughly the same crop. */
  margin-top: 40px; max-height: 620px; overflow: hidden;
}
.project-card-media img { border-radius: 8px 8px 0 0; box-shadow: 0 8px 28px rgba(7, 9, 31, 0.18); }
.project-card-media .thumb-side { width: 29%; }
.project-card-media .thumb-main { width: 68%; }
/* Cards with a single cover shot let it span the full card width. */
.project-card-media.single .thumb-main { width: 100%; }

/* Full-bleed cover (media.bleed): the art runs to the card's left, right and
   bottom edges. Like the face, it is painted --grow larger than the slot and
   clipped back, so on hover it grows with the card instead of exposing a white
   frame. flow-root keeps the negative bottom margin from collapsing through
   the parent, so the card's height stays the slot height. */
.project-card.bleed .bento-content { overflow: visible; display: flow-root; }
.project-card-media.bleed {
  --cap: 620px;
  margin: 40px calc(-1 * (var(--pad-x) + var(--grow))) calc(-1 * var(--grow));
  max-height: calc(var(--cap) + var(--grow));
  clip-path: inset(0 var(--grow) var(--grow) round 0 0 var(--radius) var(--radius));
  transition: clip-path var(--bento-dur) var(--bento-ease);
}
.project-card-media.bleed img { border-radius: 0; box-shadow: none; }
@media (hover: hover) and (pointer: fine) {
  .project-card:hover .project-card-media.bleed { clip-path: inset(0 round 0 0 var(--radius) var(--radius)); }
}

/* ---- Ghost buttons on dark surfaces (detail page) ---- */
.btn-ghost {
  padding: 10px 18px; cursor: pointer;
  background: transparent; color: var(--text-primary);
  border: 1px solid var(--border-default); border-radius: 8px;
  font-family: var(--font-body); font-weight: var(--fw-semibold); font-size: 15px;
  display: inline-flex; align-items: center; gap: 6px;
  transition: border-color 120ms var(--ease-out, ease-out), color 120ms var(--ease-out, ease-out);
}
.btn-ghost:hover { border-color: var(--accent); color: var(--accent); }
.btn-ghost:active { transform: scale(0.99) translateY(1px); }
.btn-ghost .lucide { width: 16px; height: 16px; }

/* ---- Shared section pattern (About + case studies) ---- */
.page { display: flex; flex-direction: column; gap: 48px; padding: 64px 0 0; }
.section h2 {
  margin: 0 0 8px;
  font-family: var(--font-display); font-weight: var(--fw-h3);
  font-size: var(--size-h3); line-height: var(--lh-h3);
  color: var(--accent);
}
.section p {
  margin: 0 0 16px; max-width: var(--w-prose);
  font-family: var(--font-body); font-weight: var(--fw-regular);
  font-size: var(--fs-prose); line-height: var(--lh-prose); color: var(--text-primary);
  text-wrap: pretty;
}
.section p:last-child { margin-bottom: 0; }
.section h3 {
  margin: 28px 0 8px;
  font-family: var(--font-body); font-weight: var(--fw-bold);
  font-size: var(--fs-prose); line-height: var(--lh-prose); color: var(--text-primary);
}
.section h2 + h3 { margin-top: 0; }
.section ul, .section ol {
  margin: 0 0 16px; padding-left: 1.25em; max-width: var(--w-prose);
  font-family: var(--font-body); font-weight: var(--fw-regular);
  font-size: var(--fs-prose); line-height: var(--lh-prose); color: var(--text-primary);
}
.section ol { padding-left: 1.5em; }
.section li { margin-bottom: 8px; text-wrap: pretty; }
.section li::marker { color: var(--accent); }
.section ol li::marker { font-weight: var(--fw-semibold); }
.section ul:last-child, .section ol:last-child { margin-bottom: 0; }
.section .section-figure + .section-figure { margin-top: 24px; }

/* Charts ship as one file per theme; show the one matching [data-theme].
   Hidden lazy images are never fetched, so each visitor loads one set. */
.theme-light-only { display: none; }
[data-theme="light"] .theme-light-only { display: block; }
[data-theme="light"] .theme-dark-only { display: none; }

.section-charts {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px;
}
.section-chart {
  margin: 0;
  display: flex; flex-direction: column; gap: 16px;
}
/* One box shape for both charts, so the captions line up across the row
   even though the line chart is wider than the donut. */
.chart-media { position: relative; width: 50%; aspect-ratio: 560 / 470; }
.chart-media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.section-chart figcaption,
.section-figure figcaption {
  font-family: var(--font-body); font-size: 16px; line-height: 1.5;
  color: var(--text-secondary); text-wrap: pretty;
}
/* Figure captions sit under the frame, not inside it. */
.section-figure figcaption { margin-top: 12px; max-width: var(--w-prose); }
@media (max-width: 760px) {
  .section-charts { grid-template-columns: minmax(0, 1fr); }
  .chart-media { width: 80%; }
}

.section-embed iframe { display: block; width: 100%; border: 0; background: transparent; }
.section-embed:not(.plain) iframe { border: 1px solid var(--border-default); border-radius: var(--radius-lg, 16px); }

.section-figure video {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--border-default); border-radius: var(--radius-lg, 16px);
  background: var(--bg-surface-2);
}
/* Looping clips stand in for images, so they match the image treatment. */
.section-figure video.loop { border: 0; background: none; }

/* Label rail: section heading in a sticky left column beside its content.
   Same 200px + 64px grid as the case-study index, so About and the case
   studies share one structure. */
.section--railed { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: 64px; align-items: start; }
.section--railed > h2 { margin: 0; position: sticky; top: 104px; }
.section--railed > .section-content { min-width: 0; }
@media (max-width: 1000px) {
  .section--railed { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .section--railed > h2 { position: static; }
}

/* ---- About ---- */
.about-intro { display: flex; gap: 24px; align-items: flex-start; }
.photo-frame { width: 432px; height: 370px; border-radius: 16px; overflow: hidden; flex: none; }
.photo-frame img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 18%;
  transform: scale(1.85); transform-origin: 47% 34%;
}
.about-intro .intro-text { flex: 1; max-width: var(--w-lede); display: flex; flex-direction: column; gap: 16px; }
.about-intro h1 {
  margin: 0;
  font-family: var(--font-display); font-weight: var(--fw-display);
  font-size: var(--size-display); line-height: var(--lh-display); letter-spacing: var(--ls-display);
  color: var(--accent);
}
.about-intro .lede {
  margin: 0;
  font-family: var(--font-body); font-weight: var(--fw-regular);
  font-size: 24px; line-height: 1.375; color: var(--text-secondary);
}
.about-intro .lede p { margin: 0 0 16px; }
.about-intro .lede p:last-child { margin: 0; }

/* Experience timeline */
.timeline { position: relative; margin-top: 8px; padding-left: 23px; }
.timeline::before {
  content: ''; position: absolute; left: 7px; top: 8px; bottom: 0; width: 1px;
  background: linear-gradient(180deg, var(--text-primary) 0%, var(--text-primary) 60%, transparent 100%);
}
.timeline-entry { position: relative; margin-bottom: 36px; }
.timeline-entry:last-child { margin-bottom: 0; }
.timeline-entry::before {
  content: ''; position: absolute; left: -23px; top: 4px;
  width: 15px; height: 15px; border-radius: 999px; background: var(--accent);
}
.timeline-entry .company { font-weight: var(--fw-bold); font-size: 16px; line-height: 22px; color: var(--text-primary); }
.timeline-entry .dates {
  font-weight: var(--fw-semibold); font-size: 12px; line-height: 16px;
  text-transform: uppercase; letter-spacing: 0.04em; color: var(--accent);
}
.timeline-entry .desc { margin-top: 8px; max-width: var(--w-prose); font-size: var(--fs-prose); line-height: var(--lh-prose); color: var(--text-primary); }

/* Testimonials */
.quote-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-top: 8px; }
.quote-card {
  display: flex; flex-direction: column; gap: 16px; padding: 24px;
  background: var(--bg-surface-2); border: 1px solid var(--border-default); border-radius: 16px;
}
.quote-card blockquote {
  margin: 0; flex: 1;
  font-family: var(--font-body); font-weight: var(--fw-light);
  font-size: 20px; line-height: 1.35; color: var(--text-primary);
}
.quote-card .name { font-weight: var(--fw-bold); font-size: 16px; line-height: 22px; color: var(--text-primary); }
.quote-card .role { font-weight: var(--fw-medium); font-size: 14px; line-height: 19px; color: var(--accent); }

/* ---- Case study detail ---- */
.detail-eyebrow {
  font-weight: var(--fw-semibold); font-size: 12px; line-height: 16px;
  text-transform: uppercase; letter-spacing: 0.08em; color: var(--accent); margin-bottom: 12px;
}
.detail h1 {
  margin: 0 0 12px; max-width: 20ch; text-wrap: balance;
  font-family: var(--font-display); font-weight: var(--fw-display);
  font-size: clamp(34px, 5vw, var(--size-display)); line-height: var(--lh-display); letter-spacing: var(--ls-display);
  color: var(--accent);
}
.detail .lede {
  margin: 0; max-width: var(--w-lede);
  font-family: var(--font-body); font-weight: var(--fw-regular);
  font-size: 24px; line-height: 1.375; color: var(--text-secondary);
}
/* "At a glance": the case study's summary, role and key metrics in one panel
   between the header and the body. */
.glance {
  padding: 32px; scroll-margin-top: 104px;
  background: var(--bg-surface-2);
  border: 1px solid var(--border-default); border-radius: var(--radius-lg, 16px);
}
.glance h2 {
  margin: 0 0 24px;
  font-family: var(--font-display); font-weight: var(--fw-h3);
  font-size: var(--size-h3); line-height: var(--lh-h3);
  color: var(--accent);
}
.glance-grid { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 32px 48px; }
.glance-label {
  margin-bottom: 8px;
  font-weight: var(--fw-semibold); font-size: 12px; line-height: 16px;
  text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted);
}
.glance-text {
  margin: 0;
  font-family: var(--font-body); font-weight: var(--fw-regular);
  font-size: var(--fs-prose); line-height: var(--lh-prose); color: var(--text-primary);
  text-wrap: pretty;
}
.glance-metrics { margin-top: 28px; padding-top: 24px; border-top: 1px solid var(--border-default); }
.glance-stats {
  /* flex-start so the numbers share a top line even when labels wrap to
     different heights */
  display: flex; gap: 48px; flex-wrap: wrap; align-items: flex-start;
}
.glance-stats .stat { max-width: 200px; }
.glance-stats .stat .value { font-family: var(--font-display); font-weight: var(--fw-semibold); font-size: 28px; line-height: 1.2; color: var(--accent); }
.glance-stats .stat .value.year { font-size: 20px; line-height: 34px; }
.glance-stats .stat .label { margin-top: 4px; font-size: 12px; line-height: 16px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); }

/* Inline section imagery (charts, diagrams). The exports carry their own dark
   ground and baked-in titles, so they get a frame but no caption. */
/* Visuals get 32px above and below. A paragraph's own 16px bottom margin
   collapses into the 32px, and back-to-back visuals close up to 24px. */
.section-figure, .section-charts { margin: 32px 0; }
.section .section-figure:has(+ .section-figure) { margin-bottom: 24px; }
.section .section-figure:last-child, .section .section-charts:last-child { margin-bottom: 0; }
.section-figure img { width: 100%; border: 0; border-radius: var(--radius-lg, 16px); background: none; }
.glance-stats .timeline-slot { margin-left: auto; text-align: right; }
/* Case-study body: sticky section index beside the content. The index occupies
   the space the reading measure would otherwise leave empty, so the page reads
   as a composed two-column spread rather than a left-hugging column. */
.detail-body { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: 64px; align-items: start; }
.detail-main { min-width: 0; display: flex; flex-direction: column; gap: 48px; }
/* Clears the sticky nav when jumping to a section from the index. */
.detail-main .section { scroll-margin-top: 104px; }

.detail-toc { position: sticky; top: 104px; }
.detail-toc ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.detail-toc a {
  display: block; padding: 7px 12px; border-radius: var(--radius-md, 10px);
  font-size: 14px; line-height: 1.35; font-weight: var(--fw-medium);
  color: var(--text-muted); text-decoration: none;
  border-left: 2px solid transparent;
  transition: color 120ms var(--ease-out, ease-out), background 120ms var(--ease-out, ease-out);
}
.detail-toc a:hover { color: var(--text-primary); background: var(--bg-surface-2); }
.detail-toc a.active { color: var(--accent); border-left-color: var(--accent); background: var(--accent-soft); }

@media (max-width: 1000px) {
  .detail-body { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .detail-toc { display: none; }
}


/* ---- Footer ---- */
.footer { display: flex; align-items: center; gap: 4px; padding: 128px 10px 24px; }
.footer span { font-weight: var(--fw-medium); font-size: 14px; line-height: 19px; color: var(--text-primary); }

/* ---- Responsive ---- */
@media (max-width: 760px) {
  /* Collapse the nav into a menu button plus a flyover panel. This keeps the
     bar within a 320px viewport, which the inline row could not do. */
  .nav { gap: 12px; }
  .nav-toggle { display: inline-flex; }
  .nav-menu {
    display: none;
    position: absolute; top: calc(100% - 4px); right: 0;
    flex-direction: column; align-items: stretch; justify-content: flex-start;
    gap: 2px; flex: none;
    min-width: 220px; max-width: calc(100vw - 48px); padding: 8px;
    background: var(--bg-surface-2);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg, 16px);
    box-shadow: 0 18px 40px rgba(7, 9, 31, 0.45);
    z-index: 30;
  }
  .nav-menu.open { display: flex; }
  .nav-menu .nav-link {
    min-height: 44px; padding: 0 14px;
    justify-content: flex-start; border-radius: var(--radius-md, 10px);
  }
  .nav-menu .nav-link:hover { background: var(--bg-raised); }
  .nav-menu .theme-toggle {
    margin: 6px 0 2px 14px;
    /* keep the pill's own hit area clear of the link above it */
  }
  @media (prefers-reduced-motion: no-preference) {
    .nav-menu.open { animation: fadeUp 200ms var(--ease-out, cubic-bezier(0.22, 1, 0.36, 1)); }
  }

  .about-intro { flex-direction: column; }
  .photo-frame { width: 100%; height: auto; aspect-ratio: 432 / 370; }
  .quote-grid { grid-template-columns: 1fr; }
  .project-card { --pad-x: 24px; }
  .bento-content { padding: 28px var(--pad-x) 0; }
  .project-card.no-media .bento-content { padding-bottom: 28px; }
  .project-card h2 { font-size: 26px; }
  .project-card-media { flex-direction: column; max-height: 420px; }
  .project-card-media.bleed { --cap: 420px; }
  .project-card-media .thumb-side { display: none; }
  .project-card-media .thumb-main { width: 100%; }
  .glance { padding: 24px; }
  .glance-grid { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  .glance-stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px 20px; }
  .glance-stats .timeline-slot { margin-left: 0; text-align: left; }
  .footer { padding-top: 80px; }
}
