/* Breakpoints (mobile-first, min-width):
   sm: 480px, md: 768px, lg: 1024px */

/* ============================================================
   HASAN YOUSSEF, Personal Portfolio Design System
   colors_and_type.css

   The DNA: deep navy on warm cream, with cream on navy as the
   inverse. Chunky condensed display in Anton, editorial italic
   in EB Garamond, body & UI in Inter. Architect-gold appears
   ONLY for cross-references to The Architect AI work.

   No em dashes. No emojis. No gradients. No glassmorphism.
   ============================================================ */

/* ---------- Self-hosted brand fonts ----------
   Anton and EB Garamond ship from /fonts (TTFs supplied by
   the brand). Inter loads from Google Fonts; if you need a
   fully offline build, drop the Inter TTFs into /fonts and
   add @font-face rules below. */

@font-face {
  font-family: 'Anton';
  src: url('/assets/fonts/Anton-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'EB Garamond';
  src: url('/assets/fonts/EBGaramond-Regular.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'EB Garamond';
  src: url('/assets/fonts/EBGaramond-Italic.woff2') format('woff2');
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'EB Garamond';
  src: url('/assets/fonts/EBGaramond-Medium.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'EB Garamond';
  src: url('/assets/fonts/EBGaramond-MediumItalic.woff2') format('woff2');
  font-weight: 500; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'EB Garamond';
  src: url('/assets/fonts/EBGaramond-SemiBold.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'EB Garamond';
  src: url('/assets/fonts/EBGaramond-SemiBoldItalic.woff2') format('woff2');
  font-weight: 600; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'EB Garamond';
  src: url('/assets/fonts/EBGaramond-Bold.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'EB Garamond';
  src: url('/assets/fonts/EBGaramond-BoldItalic.woff2') format('woff2');
  font-weight: 700; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'EB Garamond';
  src: url('/assets/fonts/EBGaramond-ExtraBold.woff2') format('woff2');
  font-weight: 800; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'EB Garamond';
  src: url('/assets/fonts/EBGaramond-ExtraBoldItalic.woff2') format('woff2');
  font-weight: 800; font-style: italic; font-display: swap;
}

/* Inter (self-hosted from /fonts, Inter_18pt set, the body/UI optical size).
   The brand also ships 24pt and 28pt sets; if you need them, add @font-face
   rules pointing to fonts/Inter_24pt-*.woff2 or fonts/Inter_28pt-*.woff2 under
   a distinct family name (e.g. 'Inter Display'). */
@font-face {
  font-family: 'Inter';
  src: url('/assets/fonts/Inter_18pt-Regular.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('/assets/fonts/Inter_18pt-Italic.woff2') format('woff2');
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('/assets/fonts/Inter_18pt-Medium.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('/assets/fonts/Inter_18pt-MediumItalic.woff2') format('woff2');
  font-weight: 500; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('/assets/fonts/Inter_18pt-SemiBold.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('/assets/fonts/Inter_18pt-SemiBoldItalic.woff2') format('woff2');
  font-weight: 600; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('/assets/fonts/Inter_18pt-Bold.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}

:root {
  /* ============================================================
     COLOR TOKENS  (locked, do not weaken)
     ============================================================ */

  /* Surfaces */
  --bg-primary:        #F4EEDF;  /* warm cream, default canvas */
  --bg-inverse:        #11253E;  /* deep navy, inverse canvas */

  /* Accents */
  --accent-secondary:  #BFA98F;  /* warm sand, borders & dividers on cream */
  --accent-signal:     #C9A84C;  /* architect gold, SPARINGLY, only for
                                    cross-refs to The Architect AI */

  /* Text on cream */
  --fg-on-cream:       #11253E;  /* primary, same as inverse bg */
  --fg-on-cream-dim:   #4A5566;  /* muted navy */
  --fg-on-cream-dimmer:#8A9098;  /* caption gray */

  /* Text on navy */
  --fg-on-navy:        #F4EEDF;  /* primary, same as primary bg */
  --fg-on-navy-dim:    #C9BFA8;  /* muted cream */

  /* Semantic aliases (use these in components) */
  --fg1: var(--fg-on-cream);
  --fg2: var(--fg-on-cream-dim);
  --fg3: var(--fg-on-cream-dimmer);
  --bg1: var(--bg-primary);
  --bg2: var(--bg-inverse);
  --rule: var(--accent-secondary);   /* hairlines, dividers */
  --signal: var(--accent-signal);    /* cross-ref highlight only */

  /* ============================================================
     TYPOGRAPHY TOKENS
     Max 3 fonts on any page.
     ============================================================ */
  --font-display: 'Anton', 'Bebas Neue', 'Oswald', Impact, sans-serif;
  --font-body:    'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-serif:   'EB Garamond', Georgia, 'Times New Roman', serif;

  /* Display sizes (Anton, single weight 400). Fluid clamp expressions:
     each token scales with viewport between its mobile floor and desktop ceiling. */
  --display-hero:   clamp(56px, 9vw, 128px);
  --display-xl:     clamp(48px, 8vw, 96px);
  --display-lg:     clamp(40px, 6vw, 72px);
  --display-md:     clamp(32px, 5vw, 56px);
  --display-sm:     clamp(24px, 3.5vw, 40px);
  --display-xs:     clamp(20px, 2.5vw, 32px);

  /* Body / UI sizes */
  --text-xs:   12px;        /* labels, eyebrow, captions */
  --text-sm:   14px;
  --text-md:   16px;        /* body */
  --text-lg:   18px;
  --text-xl:   20px;        /* sub-headlines */
  --text-2xl:  24px;
  --text-3xl:  32px;        /* small section openers */

  /* Editorial reading (EB Garamond) */
  --read-md:   18px;
  --read-lg:   19px;
  --read-xl:   22px;        /* pull-quotes */

  /* Line heights */
  --lh-tight:  1.05;        /* display */
  --lh-snug:   1.2;
  --lh-base:   1.5;         /* body */
  --lh-read:   1.6;         /* long-form serif */

  /* Tracking */
  --track-display: 0;  /* large display */
  --track-eyebrow: 3px;     /* uppercase pre-headlines */
  --track-base:    0px;

  /* ============================================================
     SPACING SCALE  (lock, lean toward larger for vertical rhythm)
     ============================================================ */
  --space-2:   8px;
  --space-3:  12px;
  --space-4:  16px;
  --space-5:  24px;
  --space-6:  32px;
  --space-7:  48px;
  --space-8:  64px;
  --space-9:  96px;
  --space-10:128px;   /* rare, hero only */

  /* Corner radius tokens. Cards: 14px. Buttons: 8px. */
  --radius-card:   14px;
  --radius-button: 8px;

  /* ============================================================
     LAYOUT
     ============================================================ */
  --max-content: 1200px;
  --read-column: 680px;     /* body text column 640–720px */
  --gutter: 24px;           /* 12-col grid */

  /* Shared edge padding for the nav's horizontal padding and the
     full-bleed footer-bottom's horizontal padding, so the nav wordmark
     and the footer wordmark always sit at the same X. Base value matches
     the .container gutter, so nav and footer align with page content on
     mobile and tablet. The @media override below switches to 48px at the
     viewport where the centered content edge first reaches 48px (derived
     from --max-content), so on desktop nav and footer sit further left
     than the centered content — the established desktop look. See
     section 5 "Nav and footer alignment rule" in CLAUDE.md. */
  --edge-pad-x: clamp(16px, 4vw, 32px);

  /* ============================================================
     BORDERS & SHADOWS
     ============================================================ */
  --border-hair: 1px solid var(--rule);
  --border-strong: 1px solid var(--fg1);
  --radius-0: 0;            /* photos, cards: NO rounded corners */
  --radius-pill: 999px;     /* never used on photos; reserved for nothing currently */
  /* No drop shadows on imagery. Subtle hover-lift only. */
  --lift: 0 0 0 1px var(--fg1);  /* 1px navy border on photo hover */

  /* ============================================================
     MOTION  (subtle only, no parallax, no bouncing)
     ============================================================ */
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
  --dur-fast: 140ms;
  --dur-base: 220ms;
  --dur-slow: 420ms;
}

/* --edge-pad-x switches to 48px at the viewport where the centered content
   edge first reaches 48px. Derivation: content_edge_when_centered =
   (viewport - --max-content) / 2 + container_gutter; with --max-content =
   1200 and container_gutter clamping to 32 at md+, content_edge = 48 when
   viewport = 1232. Using 1200 directly would create a [1200, 1232] band
   where the nav sits more indented than the content, opposite the desktop
   look; 1232 makes the transition land at exact nav-to-content alignment. */
@media (min-width: 1232px) {
  :root { --edge-pad-x: 48px; }
}

/* ============================================================
   BASE / RESETS
   ============================================================ */
html, body {
  background: var(--bg1);
  color: var(--fg1);
  font-family: var(--font-body);
  font-size: var(--text-md);
  line-height: var(--lh-base);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection {
  background: var(--fg1);
  color: var(--bg1);
}

/* ============================================================
   SEMANTIC TYPE, use these classes (or the matching tag styles)
   ============================================================ */

/* Eyebrow / pre-headline label */
.eyebrow,
.label-eyebrow {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-xs);
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--fg3);
}

/* Display headlines (Anton) */
h1, .h1 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(56px, 9vw, var(--display-hero));
  line-height: var(--lh-tight);
  letter-spacing: 0;
  font-kerning: normal;
  font-feature-settings: "kern" 1;
  text-rendering: optimizeLegibility;
  color: var(--fg1);
  margin: 0 0 var(--space-5) 0;
  text-wrap: balance;
}

h2, .h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(40px, 5.5vw, var(--display-lg));
  line-height: var(--lh-snug);
  letter-spacing: 0;
  font-kerning: normal;
  font-feature-settings: "kern" 1;
  text-rendering: optimizeLegibility;
  color: var(--fg1);
  margin: 0 0 var(--space-5) 0;
}

h3, .h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--display-sm);
  line-height: var(--lh-snug);
  letter-spacing: 0;
  font-kerning: normal;
  font-feature-settings: "kern" 1;
  text-rendering: optimizeLegibility;
  color: var(--fg1);
  margin: 0 0 var(--space-4) 0;
}

h4, .h4 {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--text-xl);
  line-height: var(--lh-snug);
  color: var(--fg1);
  margin: 0 0 var(--space-3) 0;
}

/* Sub-headline below display */
.subhead {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--text-xl);
  line-height: var(--lh-base);
  color: var(--fg2);
  max-width: var(--read-column);
}

/* Body copy */
p, .body {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--text-md);
  line-height: var(--lh-base);
  color: var(--fg1);
  text-wrap: pretty;
  hyphens: auto;
  overflow-wrap: break-word;
}

.body-lg {
  font-size: var(--text-lg);
  line-height: var(--lh-base);
}

/* Editorial reading, Aria, About long-form, pull quotes */
.serif {
  font-family: var(--font-serif);
  font-size: var(--read-lg);
  line-height: var(--lh-read);
  color: var(--fg1);
  max-width: var(--read-column);
}
.serif-italic {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--read-lg);
  line-height: var(--lh-read);
  color: var(--fg1);
}
.pullquote {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--read-xl);
  line-height: var(--lh-read);
  color: var(--fg1);
  max-width: var(--read-column);
  border-left: 1px solid var(--rule);
  padding-left: var(--space-5);
  margin: var(--space-7) 0;
}

/* Captions, meta */
.caption,
small {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--fg3);
  line-height: var(--lh-base);
}

/* Inline link, quiet, with hover underline */
a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  transition: opacity var(--dur-base) var(--ease-out);
}
a:hover { opacity: 0.6; }

/* ============================================================
   INVERSE SURFACE, apply .on-navy to a navy section to recolor
   text + dividers automatically.
   ============================================================ */
.on-navy {
  background: var(--bg2);
  color: var(--fg-on-navy);
  --fg1: var(--fg-on-navy);
  --fg2: var(--fg-on-navy-dim);
  --fg3: var(--fg-on-navy-dim);
  --rule: rgba(244, 238, 223, 0.18);
}

/* ============================================================
   UTILITY: container + horizontal rule used throughout
   ============================================================ */
.container {
  max-width: var(--max-content);
  margin: 0 auto;
  padding: 0 clamp(16px, 4vw, 32px);
}

.hairline {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: var(--space-7) 0;
}

/* Architect-gold cross-reference (sparingly) */
.signal,
.xref {
  color: var(--signal);
}

/* Breakpoints (mobile-first, min-width):
   sm: 480px, md: 768px, lg: 1024px */

/* UI Kit shared styles, builds on the root colors_and_type.css */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

body {
  background: var(--bg-primary);
  color: var(--fg-on-cream);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
}

#app { min-height: 100vh; }

.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 clamp(16px, 4vw, 32px);
}

/* ==========================================================================
   ANTON DISPLAY DEFAULTS
   Anton's narrow letters (I, l, t, i) collide at default tracking.
   These rules enable kerning and zero out negative letter-spacing.
   For the very largest displays, we open up to +0.5px so headlines breathe.
   ========================================================================== */
.display,
.hero h1,
.featured h3,
.featured-img,
.page-title,
.tl-finale,
.tl-year,
.intent-card h2,
.pcard-name,
.pcard-img,
.aria-hero h1,
.about-lang h3,
.phase .ptitle,
.stage .num,
.build-img,
.word,
.word-mini {
  letter-spacing: 0;
  font-kerning: normal;
  font-feature-settings: "kern" 1;
  text-rendering: optimizeLegibility;
}

/* Largest displays: open the tracking slightly so I, l, t breathe. */
.aria-hero h1,
.page-title {
  letter-spacing: 0.5px;
}

/* Eyebrow */
.eyebrow {
  font-family: var(--font-body);
  font-weight: 500;
  line-height: var(--lh-base);
  font-size: 12px;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--fg-on-cream-dimmer);
  display: block;
  margin: 0 0 24px;
}
.on-navy .eyebrow { color: var(--fg-on-navy-dim); }

/* Display utility */
.display {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 0.98;
  margin: 0;
  text-wrap: balance;
}

/* NAV */
/* Scroll-progress bar: thin architect-gold bar fixed at the very top that
   fills left to right with scroll (transform scaleX driven from App.jsx).
   left/right:0 (not width:100vw) so it never adds horizontal overflow from the
   scrollbar. z-index 51 sits one above .nav (50). No transition so it tracks
   scroll directly without lag. */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--accent-signal);
  transform: scaleX(0);
  transform-origin: left center;
  z-index: 51;
  pointer-events: none;
}
.nav {
  position: fixed; top: 0; left: 0; right: 0;
  display: flex; justify-content: space-between; align-items: center;
  /* Horizontal padding uses --edge-pad-x (shared with .footer-bottom) so
     the nav wordmark and the footer wordmark always sit at the same X.
     Vertical padding stays at 22px. */
  padding: 22px var(--edge-pad-x);
  z-index: 50;
  background: transparent;
  transition: background 220ms cubic-bezier(0.22,0.61,0.36,1), border-color 220ms;
  border-bottom: 1px solid transparent;
}
.nav.scrolled {
  background: rgba(17,37,62,0.92);
  border-bottom-color: rgba(244,238,223,0.12);
}
.nav.scrolled .word, .nav.scrolled .nav-link, .nav.scrolled .nav-burger { color: var(--fg-on-navy); }
.word {
  font-family: var(--font-display);
  font-size: 22px;
  color: var(--fg-on-cream);
  cursor: pointer;
}
.nav-links { display: none; gap: 32px; }
.nav-link {
  font-family: var(--font-body); font-size: 14px;
  color: var(--fg-on-cream); cursor: pointer;
  letter-spacing: 0.3px; padding: 4px 0;
  border: none; background: none;
  line-height: normal;
  transition: opacity 220ms;
}
.nav-link:hover { opacity: 0.6; }
.nav-link.active { font-weight: 600; }
.nav-burger {
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;
  background: transparent; border: none; cursor: pointer; padding: 0;
  color: var(--fg-on-cream);
}
@media (min-width: 768px) {
  /* md */
  .nav-links { display: flex; }
  .nav-burger { display: none; }
}
.nav-drawer {
  position: absolute; top: 100%; left: 0; right: 0;
  background: var(--bg-inverse);
  padding: var(--space-5) var(--space-6);
  display: flex; flex-direction: column; gap: var(--space-4);
  z-index: 100;
}
.nav-drawer button {
  width: 100%; min-height: 48px;
  background: transparent; border: none; cursor: pointer;
  color: var(--fg-on-navy);
  font: 500 18px/1.4 Inter, sans-serif;
  text-align: left; padding: var(--space-3) 0;
}

/* Buttons */
.btn {
  font-family: var(--font-body); font-weight: 500; font-size: 14px;
  padding: 16px 26px; border: 1.5px solid var(--fg-on-cream); cursor: pointer;
  display: inline-flex; align-items: center; gap: 12px;
  transition: all 220ms cubic-bezier(0.22,0.61,0.36,1);
  letter-spacing: 0.3px;
  background: transparent; color: var(--fg-on-cream);
  text-decoration: none;
  /* Surgical token, same approach as the card retrofits at b551cb8 / 9d6890f.
     Rounds both the filled .btn-primary background corners and the outlined
     .btn-secondary border corners; no overflow: hidden needed (no inner
     edge-bleeding panel). */
  border-radius: var(--radius-button);
}
.btn-primary { background: var(--fg-on-cream); color: var(--bg-primary); }
.btn-primary:hover { background: #1A3454; border-color: #1A3454; }
.btn-secondary:hover { background: var(--fg-on-cream); color: var(--bg-primary); }
.on-navy .btn { color: var(--fg-on-navy); border-color: var(--fg-on-navy); }
.on-navy .btn-primary { background: var(--fg-on-navy); color: var(--bg-inverse); }
.on-navy .btn-primary:hover { background: #E5DDC8; border-color: #E5DDC8; }
.on-navy .btn-secondary:hover { background: var(--fg-on-navy); color: var(--bg-inverse); }
.btn .arr { font-size: 18px; line-height: 1; }

/* Inline link, styled as an outlined CTA button */
.inline-link {
  font-family: var(--font-body); font-size: 14px; font-weight: 500;
  color: inherit; cursor: pointer;
  border: 1.5px solid currentColor;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: var(--space-4) var(--space-6);
  letter-spacing: 0.3px;
  background: none;
  text-align: center;
  line-height: normal;
  transition: opacity 220ms;
  /* Same outlined-CTA box family as .btn (rounded at eee5d9a). The .inline-link
     class is the section CTA + closing-strip variant used site-wide ("See all
     work", "Read my full story", "Read the case study", "Talk to me",
     "Back to Work", etc.). Underline-only links (.cta, .crumb-link,
     .campaign-watch, .val-url) deliberately stay unrounded by design. */
  border-radius: var(--radius-button);
}
.inline-link:hover { opacity: 0.6; }
.inline-link .arr { font-size: 16px; line-height: 1; }

/* Sections */
.section { padding: clamp(48px, 8vw, 96px) 0; }
.section-tight { padding: clamp(32px, 6vw, 64px) 0; }
.section--ruled { border-top: 1px solid var(--accent-secondary); }

.on-navy {
  background: var(--bg-inverse);
  color: var(--fg-on-navy);
}

/* Hero */
.hero {
  min-height: 100vh; display: flex; flex-direction: column; justify-content: center;
  padding-top: clamp(88px, 14vw, 140px); padding-bottom: 80px;
  position: relative;
}
.hero h1 {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(56px, 9vw, 112px);
  line-height: 1.15;
  margin: 0 0 36px 0; max-width: 1080px;
  color: var(--fg-on-cream);
  text-wrap: balance;
}
.hero .subhead {
  font-family: var(--font-body);
  font-size: 19px; line-height: 1.55;
  color: var(--fg-on-cream-dim);
  max-width: 640px;
  margin: 0 0 48px 0;
}
.hero-ctas { display: flex; gap: 16px; flex-wrap: wrap; }

/* Through-line */
.throughline-grid {
  display: grid; grid-template-columns: 1fr;
  gap: var(--space-7); margin-top: 40px;
}
@media (min-width: 768px) {
  /* md */
  .throughline-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-6);
  }
}
.tl-col { display: flex; flex-direction: column; gap: 16px; }
.tl-year {
  font-family: var(--font-display); font-size: 44px;
  line-height: 0.95;
  color: var(--fg-on-cream);
  text-align: center;
}
@media (min-width: 768px) {
  /* md */
  .tl-year { text-align: left; }
}
.tl-year .dim { color: var(--fg-on-cream-dimmer); }
.tl-text { font-size: 15px; line-height: 1.55; color: var(--fg-on-cream-dim); margin: 0; }
@media (min-width: 768px) {
  /* md */
  .tl-text { max-width: 320px; }
}
.tl-finale {
  /* Through-line divider removed; padding-top absorbs the dropped 1.5px border
     so the thesis text's vertical offset within the section is preserved. */
  margin-top: 80px; padding-top: 41.5px;
  text-align: center;
  font-family: var(--font-display); font-size: 36px;
  color: var(--fg-on-cream);
}

/* Featured strip */
.featured {
  display: grid; grid-template-columns: 1fr;
  gap: var(--space-6); align-items: center;
  border: 1.5px solid var(--accent-secondary);
  padding: 0;
  /* Surgical token, same approach as .pcard and .intent-card at b551cb8.
     overflow: hidden clips the flush navy .featured-img panel's outer
     corners to the card radius; the interior seam where the navy panel
     meets the cream text side stays square by design. One rule covers
     both the desktop side-by-side and stacked-mobile layouts. */
  border-radius: var(--radius-card);
  overflow: hidden;
  /* Hover-state transition (matches .pcard's base transition exactly). The
     .featured.is-revealing rule already redeclares the full 4-entry list
     for the reveal animation; this base entry ensures hover stays smooth
     when .is-revealing is absent (e.g. under prefers-reduced-motion when
     the hook short-circuits). */
  transition: transform 220ms cubic-bezier(0.22,0.61,0.36,1), border-color 220ms;
}
.featured:hover { transform: translateY(-4px); border-color: var(--fg-on-cream); }
@media (min-width: 768px) {
  /* md */
  .featured {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-7);
    align-items: stretch;
  }
  .featured > .featured-img {
    aspect-ratio: auto;
  }
}
.featured-img {
  background: var(--bg-inverse);
  aspect-ratio: 4/3; display: flex; align-items: center; justify-content: center;
  color: var(--accent-signal);
  font-family: var(--font-display); font-size: 48px;
  text-align: center; line-height: 1;
  padding: 20px;
}
.featured-img img { max-width: 55%; max-height: 55%; object-fit: contain; }
.featured-body { padding: 48px; }
.featured h3 {
  font-family: var(--font-display); font-size: clamp(36px, 6vw, 56px);
  line-height: 0.98;
  margin: 0 0 12px 0;
}
.featured .role {
  font-size: clamp(12px, 3.5vw, 14px); color: var(--fg-on-cream-dim);
  margin: 0 0 24px 0; letter-spacing: 0.3px;
}
.featured p { font-size: 15px; line-height: 1.55; color: var(--fg-on-cream); margin: 0 0 16px 0; max-width: 460px; }

/* Card base class. All card-shaped surfaces inherit from this.
   Carries border-radius, background, border, and motion transition.
   Universal hover lift and touch flash target this base in future commits. */
.card {
  border-radius: var(--radius-card);
  background: var(--bg-primary);
  border: 1px solid var(--accent-secondary);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

/* Sub-page lead paragraph below the page title.
   Used on the COSV sub-page and any future case-study sub-pages. */
.page-intro {
  font-family: var(--font-body);
  font-size: clamp(16px, 1.8vw, 18px);
  line-height: 1.6;
  color: var(--fg-on-cream-dim);
  max-width: 720px;
  margin: 0 0 48px 0;
}

/* Sub-page work cards (e.g. COSV's four projects).
   Sit inside an existing .intent-grid container, inherit corner radius and
   background from .card base, add their own border, padding, hover lift,
   and a top-of-card eyebrow line above the heading. */
.subwork-card {
  border: 1.5px solid var(--accent-secondary);
  padding: clamp(28px, 4vw, 40px);
  display: flex;
  flex-direction: column;
  gap: 16px;
  cursor: pointer;
  transition: transform 220ms cubic-bezier(0.22,0.61,0.36,1), border-color 220ms;
}
.subwork-card:hover {
  transform: translateY(-4px);
  border-color: var(--fg-on-cream);
}
.subwork-eyebrow {
  font-family: var(--font-body);
  font-size: 12px;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: var(--fg-on-cream-dimmer);
}

/* Project grid */
.project-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-5);
}
.pcard {
  border: 1.5px solid var(--accent-secondary);
  background: var(--bg-primary);
  cursor: pointer;
  transition: transform 220ms cubic-bezier(0.22,0.61,0.36,1), border-color 220ms;
  display: flex; flex-direction: column;
  /* Token applied surgically rather than via the .card base class so the
     variant's background and border declarations above stay authoritative.
     overflow: hidden clips the inner .pcard-img top-edge so it follows
     the rounded card corner instead of poking past it. */
  border-radius: var(--radius-card);
  overflow: hidden;
}
.pcard:hover { transform: translateY(-4px); border-color: var(--fg-on-cream); opacity: 1; }
.pcard-img {
  aspect-ratio: 4/3; background: var(--bg-inverse);
  display: flex; align-items: center; justify-content: center;
  color: var(--fg-on-navy-dim);
  font-family: var(--font-display); font-size: 28px;
  text-align: center; padding: 16px;
  line-height: 1;
  overflow: hidden;
  position: relative;
}
.pcard-img img {
  width: 100%; height: 100%; object-fit: cover;
  display: block;
}
.pcard-img .card-logo {
  display: block;
  margin: 0 auto;
  width: auto; height: auto;
  max-width: 60%; max-height: 60%;
  object-fit: contain;
}
.pcard-meta { padding: 18px 20px 22px; flex: 1; display: flex; flex-direction: column; }
.pcard-tag {
  font-size: 11px; letter-spacing: 2.5px; text-transform: uppercase;
  color: var(--fg-on-cream-dimmer); font-weight: 500;
  margin-bottom: 8px;
}
.pcard-name {
  font-family: var(--font-display); font-weight: 400; font-size: clamp(22px, 4vw, 28px);
  line-height: 1;
  margin: 0 0 8px 0; color: var(--fg-on-cream);
}
.pcard-desc { font-size: 13px; line-height: 1.5; color: var(--fg-on-cream-dim); margin: 0; }

/* About teaser navy strip */
.about-teaser {
  display: grid; grid-template-columns: 1fr; gap: var(--space-6); align-items: center;
}
@media (min-width: 768px) {
  /* md */
  .about-teaser {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-8);
  }
}
.about-teaser .photo {
  width: 100%; aspect-ratio: 4/5;
  background: var(--bg-inverse);
  overflow: hidden;
  transition: transform 220ms cubic-bezier(0.22,0.61,0.36,1);
}
.about-teaser .photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.about-teaser .photo:hover { transform: translateY(-4px); }
.about-teaser-h2 { font-size: var(--display-md); }
.about-teaser-italic {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 20px;
  line-height: 1.55;
  color: var(--fg-on-navy-dim);
  margin: 0 0 32px;
  max-width: 520px;
}

/* Footer */
.footer {
  border-top: 1.5px solid var(--accent-secondary);
  padding: 64px 0 32px;
}
.footer-grid {
  display: grid; grid-template-columns: 1fr;
  gap: 48px; padding-bottom: 48px;
}
@media (min-width: 768px) {
  /* md */
  .footer-grid { grid-template-columns: 1fr 1fr 1fr; }
}
.footer-col .ftitle {
  font-family: var(--font-body); font-weight: 500;
  font-size: 11px; letter-spacing: 2.5px; text-transform: uppercase;
  color: var(--fg-on-cream-dimmer); margin-bottom: 16px;
}
.footer-col a, .footer-col span.fitem {
  display: block; font-family: var(--font-body); font-size: 14px;
  color: var(--fg-on-cream); padding: 4px 0;
  text-decoration: none; cursor: pointer; border: none;
}
.footer-col a:hover { opacity: 0.6; }
.footer-bottom {
  padding-top: 24px;
  border-top: 1.5px solid var(--accent-secondary);
  display: flex; justify-content: space-between;
  font-size: 12px; letter-spacing: 0.5px;
  color: var(--fg-on-cream-dimmer);
  font-family: var(--font-body);
  /* Horizontal padding uses --edge-pad-x (shared with .nav) so the nav
     wordmark and the footer wordmark always sit at the same X across all
     viewports: matching the page-content gutter on mobile/tablet, 48px
     on desktop where content centers in --max-content. The full-bleed
     border-top doubles as the full-width footer separator above the
     wordmark/copyright row — no separate element needed because
     .footer-bottom sits outside the padded .container and spans the
     full viewport width. */
  padding-left: var(--edge-pad-x);
  padding-right: var(--edge-pad-x);
}
.footer-bottom .word-mini {
  font-family: var(--font-display); font-size: 14px;
  color: var(--fg-on-cream);
}

/* Pages: prose / case study */
.breadcrumb {
  font-size: 12px; letter-spacing: 2.5px; text-transform: uppercase;
  color: var(--fg-on-cream-dimmer); margin-bottom: 32px;
  padding-top: clamp(88px, 14vw, 140px);
}
.breadcrumb .crumb-link {
  font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
  background: none; border: 0; padding: 0; cursor: pointer;
  transition: color 160ms ease;
}
.breadcrumb .crumb-link:hover { color: var(--fg-on-cream); }
.page-title {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(64px, 11vw, 144px);
  line-height: 1.15;
  margin: 0 0 24px 0; color: var(--fg-on-cream);
}
.page-sub {
  font-family: var(--font-serif); font-style: italic;
  font-size: 22px; line-height: 1.5;
  color: var(--fg-on-cream-dim); max-width: 700px;
  margin: 0 0 56px 0;
}
/* Conditional structural break inside .page-sub. Hidden on phone so natural
   word-wrap controls layout; activates at md+ to enforce the editorial pattern
   of the year range on its own line on desktop / tablet viewports. */
.page-sub-break { display: none; }
@media (min-width: 768px) {
  .page-sub-break { display: initial; }
}
.section-label {
  font-family: var(--font-body); font-weight: 500; line-height: var(--lh-base);
  font-size: 12px; letter-spacing: 3px; text-transform: uppercase;
  color: var(--fg-on-cream-dimmer); margin: 0 0 24px; display: block;
}
.on-navy .section-label { color: var(--fg-on-navy-dim); }

.prose {
  font-family: var(--font-serif);
  font-size: 19px; line-height: 1.65;
  color: var(--fg-on-cream); max-width: 680px;
}
.prose p { margin: 0 0 24px 0; }
.prose-italic { font-style: italic; }

.arch-panel-wordmark { font-size: clamp(20px, 4.5vw, 52px); }
/* Hero logo panel. Base is content-sized so the emblem, wordmark, and tag
   always fit on narrow phones; the wide 21:9 ratio re-enables at md. */
.arch-panel {
  background: var(--bg-inverse);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(40px, 9vw, 72px) 24px;
  margin-bottom: 64px;
}
.arch-panel-emblem { margin-bottom: 16px; }
.arch-panel-emblem img {
  display: block;
  margin: 0 auto;
  height: clamp(72px, 15vw, 240px);
  width: auto;
  object-fit: contain;
}
@media (min-width: 768px) {
  .arch-panel { aspect-ratio: 21/9; padding: 0; }
}

.atglance {
  border: 1.5px solid var(--accent-secondary);
  padding: 0;
  margin-bottom: clamp(48px, 8vw, 96px);
}
.atglance-row {
  display: grid; grid-template-columns: 1fr;
  gap: var(--space-3);
  padding: 18px 24px;
  border-top: 1.5px solid var(--accent-secondary);
  font-size: 14px;
}
@media (min-width: 480px) {
  /* sm */
  .atglance-row { grid-template-columns: 160px 1fr; gap: 0; }
}
.atglance-row:first-child { border-top: 0; }
.atglance-row .lbl {
  font-weight: 600; color: var(--fg-on-cream);
  letter-spacing: 0.3px;
}
.atglance-row .val { color: var(--fg-on-cream-dim); }
.val-url {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 160ms ease, border-color 160ms ease;
}
.val-url:hover {
  color: var(--fg-on-cream);
  border-bottom-color: currentColor;
}
.val-url:focus-visible {
  outline: 2px solid var(--fg-on-cream);
  outline-offset: 2px;
  border-radius: 2px;
}

.pipeline {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 12px;
  /* Extra bottom margin reserves space for the absolutely-positioned (out of
     flow) .pipeline-verified mark under box 7 so it clears the tail paragraph. */
  margin: 32px 0 72px;
  position: relative; /* hosts the absolutely-positioned connector overlay */
}
/* Mobile snake (base, two-column): reorder the boxes so consecutive stages are
   physically adjacent and the connector travels without diagonal jumps back
   across the grid. DOM order stays 1..7 (grid placement, not CSS order, so
   reading/tab order is unchanged); reset to auto at md where the 4- and 7-col
   templates take over. Target:
     row 1: box 1 left,  box 2 right
     row 2: box 4 left,  box 3 right
     row 3: box 5 left,  box 6 right
     row 4:              box 7 right */
.pipeline .stage:nth-child(1) { grid-column: 1; grid-row: 1; }
.pipeline .stage:nth-child(2) { grid-column: 2; grid-row: 1; }
.pipeline .stage:nth-child(3) { grid-column: 2; grid-row: 2; }
.pipeline .stage:nth-child(4) { grid-column: 1; grid-row: 2; }
.pipeline .stage:nth-child(5) { grid-column: 1; grid-row: 3; }
.pipeline .stage:nth-child(6) { grid-column: 2; grid-row: 3; }
.pipeline .stage:nth-child(7) { grid-column: 2; grid-row: 4; }
/* Two states only: the 2-column snake below, all seven in one row at and
   above 1024px. No 4-column middle state, which previously wrapped 7 boxes
   into 4+3 and made the position-driven connector draw a diagonal from box 4
   (top-right) to box 5 (bottom-left). The :nth-child(n) reset keeps the same
   (0,3,0) specificity as the snake placements so it wins by source order;
   a plain .pipeline .stage would lose to the per-index snake rules. */
@media (min-width: 1024px) {
  .pipeline { grid-template-columns: repeat(7, 1fr); }
  .pipeline .stage:nth-child(n) { grid-column: auto; grid-row: auto; }
}
.stage {
  border: 1.5px solid var(--accent-secondary);
  padding: 18px 12px; text-align: center;
  position: relative;
  font-size: 12px; line-height: 1.3;
  color: var(--fg-on-cream);
  background: var(--bg-primary);
  transition: opacity 450ms ease;
}
/* Stage-2 brighten, applied by JS only (so no-JS / reduced-motion stay bright):
   while the animation is armed the boxes sit faint and each brightens to full as
   the dot reaches it. Opacity only, no layout shift. */
.pipeline.is-animating .stage { opacity: 0.35; }
.pipeline.is-animating .stage.is-lit { opacity: 1; }
.stage .num {
  font-family: var(--font-display); font-size: var(--display-xs);
  display: block; margin-bottom: 8px;
  line-height: 1;
  color: var(--fg-on-cream);
}
/* Box 7 (Release Decision) settled look: the calm end state the stage-2 bloom
   keyframe will settle into. Gold border + a soft gold glow, gold numeral. */
.stage-final {
  border-color: var(--accent-signal);
  box-shadow: 0 0 18px -4px rgba(201, 168, 76, 0.4);
}
.stage-final .num { color: var(--accent-signal); }
/* Pipeline connector overlay. The SVG is sized 1:1 in px by usePipelineDraw and
   sits on top of the boxes; the in-gap path never crosses a box face. */
.pipeline-connector-svg {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 2;
  overflow: visible;
}
.pipeline-connector-path {
  fill: none;
  stroke: var(--accent-signal);
  stroke-width: 2;
  stroke-linecap: round;
}
/* The travelling dot (stage 2). Rides box border edges and gap crossings, never
   over a box face. Soft gold glow, no permanent trail. */
.pipeline-dot {
  fill: var(--accent-signal);
  filter: drop-shadow(0 0 4px rgba(201, 168, 76, 0.85));
  transition: opacity 250ms ease;
}
/* Box 7 finale: gold border bloom that rises then settles back to the .stage-
   final look (same box-shadow at 0% and 100% so it lands seamlessly). One-shot. */
@keyframes pipeline-stage-bloom {
  0%   { box-shadow: 0 0 18px -4px rgba(201, 168, 76, 0.4); }
  35%  { box-shadow: 0 0 28px 3px rgba(201, 168, 76, 0.9); }
  100% { box-shadow: 0 0 18px -4px rgba(201, 168, 76, 0.4); }
}
.stage-final.is-bloom { animation: pipeline-stage-bloom 750ms ease forwards; }
/* The pipeline finale word, anchored to box 7 (the final gate), not page-
   centered: it belongs to the Release Decision box. Absolutely positioned
   against the position: relative .stage-final, centered horizontally under it.
   On desktop box 7 is the far-right box; on the phone snake it is the bottom-
   right box; the mark sits under whichever. Stage 1 renders it in its shown
   final state; stage 2 will add the fade-in. EB Garamond italic, gold, quiet
   but clear (per-rule clamp, min floor >= 20px for display-italic type). */
.pipeline-verified {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-top: 12px;
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--accent-signal);
  font-size: clamp(20px, 3vw, 28px);
  line-height: 1.2;
  white-space: nowrap;
  text-align: center;
  transition: opacity 600ms ease;
}
/* Stage 2: while armed/animating the mark is hidden and fades in at the finale.
   Applied by JS only via .is-animating, so no-JS / reduced-motion keep it shown.
   .show-verified wins (0,4,0 vs 0,3,0) regardless of source order. */
.pipeline.is-animating .pipeline-verified { opacity: 0; }
.pipeline.is-animating.show-verified .pipeline-verified { opacity: 1; }
.pipeline-tail {
  font-size: 15px;
  line-height: 1.55;
  color: var(--fg-on-cream-dim);
  max-width: 680px;
  margin-top: 32px;
}

/* Case study Scope section: metrics strip + scope grid + tooling note.
   First used on the MagellanTV sub-page, intended as the prototype shape
   for the 8 remaining single-engagement case studies. The metrics strip
   uses explicit media queries (exactly 3 columns at md+). The scope grid
   uses auto-fit minmax so the genre tiles re-flow naturally from desktop
   to phone. Scope tiles inherit corner radius and background from .card base. */
.scope-metrics {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
  margin-top: 8px;
  margin-bottom: 48px;
}
@media (min-width: 768px) {
  /* auto-fit: handles 2- and 3-metric variants without modifier classes.
     With minmax(200px, 1fr), tracks beyond the child count collapse, so 3 metrics
     render as 3 columns at ~1/3 each and 2 metrics render as 2 columns at ~1/2 each. */
  .scope-metrics {
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--space-6);
  }
}
.metric { text-align: left; }
.metric-num {
  font-family: var(--font-display); font-weight: 400;
  font-size: var(--display-lg);
  line-height: 1; color: var(--fg-on-cream);
  margin-bottom: 8px;
}
.metric-lbl {
  font-family: var(--font-body); font-weight: 500;
  font-size: 12px; letter-spacing: 2.5px; text-transform: uppercase;
  color: var(--fg-on-cream-dimmer);
}
.scope-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--space-4);
  margin-bottom: 16px;
}
.scope-tile {
  padding: 28px 16px;
  text-align: center;
  font-family: var(--font-display); font-weight: 400;
  font-size: var(--display-xs);
  line-height: 1; color: var(--fg-on-cream);
  display: flex; align-items: center; justify-content: center;
  min-height: 96px;
}

.build-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-5); margin-top: 32px;
}
.build-item { border: 1.5px solid var(--accent-secondary); transition: transform 220ms cubic-bezier(0.22,0.61,0.36,1), border-color 220ms; }
.build-item:hover { transform: translateY(-4px); border-color: var(--fg-on-cream); }
.build-img {
  aspect-ratio: 16/10; background: var(--bg-inverse);
  display: flex; align-items: center; justify-content: center;
  color: var(--accent-signal); font-family: var(--font-display);
  font-size: 24px;
  text-align: center; padding: 16px; line-height: 1;
}
.build-cap { padding: 18px 24px; font-size: 13px; line-height: 1.5; color: var(--fg-on-cream-dim); }

/* Campaign showcase grid + tile. JY Production THE CAMPAIGNS section.
   Auto-fit minmax keeps the column count fluid across viewports; tiles extend
   .card for radius / background, add their own border + padding, and use a
   flex column with the watch link pinned to the bottom (margin-top: auto) so
   tiles align cleanly even though scope-line lengths vary. The views line is
   structured with .campaign-views-num as its own span so a later count-up
   motion paste can target the number without touching the surrounding text. */
.campaign-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-5);
  margin-top: 32px;
}
.campaign-tile {
  border: 1.5px solid var(--accent-secondary);
  padding: clamp(28px, 4vw, 40px);
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: transform 220ms cubic-bezier(0.22,0.61,0.36,1), border-color 220ms;
}
.campaign-logos {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-bottom: 14px;
  /* min-height reserves the logo-band space on tiles whose logos array is
     empty (e.g. Tiara), so their title and description sit on the same
     vertical line as logo-bearing tiles. Keep this value in sync with the
     .campaign-logo height below; if one changes, change the other. */
  min-height: 48px;
}
.campaign-logo {
  height: 48px;
  width: auto;
  object-fit: contain;
  display: block;
}
.campaign-tile:hover {
  transform: translateY(-4px);
  border-color: var(--fg-on-cream);
}
.campaign-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(22px, 3.5vw, 28px);
  line-height: 1.15;
  color: var(--fg-on-cream);
  margin: 0;
}
.campaign-scope {
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.55;
  color: var(--fg-on-cream-dim);
  margin: 0;
}
.campaign-foot {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding-top: 8px;
}
.campaign-views { margin: 0; }
.campaign-views-num {
  display: block;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--display-md);
  line-height: 1;
  color: var(--fg-on-cream);
  margin-bottom: 6px;
}
.campaign-views-lbl {
  display: block;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: var(--fg-on-cream-dimmer);
}
.campaign-watch {
  font-size: 13px;
  font-weight: 500;
  color: var(--fg-on-cream);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  align-self: flex-start;
  padding-bottom: 2px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: opacity 160ms;
}
.campaign-watch:hover { opacity: 0.6; }
.campaign-watch .arr { font-size: 14px; line-height: 1; }

/* Scroll-reveal pilot on .campaign-tile.
   Base state is fully visible. The pre-paint guard (.reveal-armed on <html>,
   set in the head before first paint only when JS is on AND motion is allowed)
   snaps every not-yet-revealed tile hidden from the first painted frame, so a
   prerendered tile never shows-then-blinks. IntersectionObserver then adds
   .is-visible per tile as it enters the viewport. The JS hook still adds
   .is-revealing on mount, but that class now only carries the transition + the
   per-tile stagger, NOT the hidden state. Stagger is per-tile-index in CSS
   (60ms steps), so a row cascades rather than landing as a block. If JS does
   not run, or reduced motion is preferred, .reveal-armed is never set and tiles
   stay visible at rest. */
.reveal-armed .campaign-tile:not(.is-visible) {
  opacity: 0;
  translate: 0 20px;
}
.campaign-tile.is-revealing {
  /* The per-tile reveal stagger is fed in via --reveal-delay (set per
     nth-child below). Critically, the delay is applied ONLY to the opacity
     and translate entries via the per-property syntax, never as a bare
     transition-delay shorthand. A bare delay would also delay the
     transform and border-color hover transitions, which made later cards
     feel laggy on hover and stay lifted after cursor-leave. */
  transition:
    transform 220ms cubic-bezier(0.22,0.61,0.36,1),
    border-color 220ms,
    opacity 500ms ease-out var(--reveal-delay, 0ms),
    translate 500ms ease-out var(--reveal-delay, 0ms);
}
.campaign-tile.is-revealing.is-visible {
  opacity: 1;
  translate: 0 0;
}
.campaign-tile.is-revealing:nth-child(2) { --reveal-delay: 60ms; }
.campaign-tile.is-revealing:nth-child(3) { --reveal-delay: 120ms; }
.campaign-tile.is-revealing:nth-child(4) { --reveal-delay: 180ms; }
.campaign-tile.is-revealing:nth-child(5) { --reveal-delay: 240ms; }
.campaign-tile.is-revealing:nth-child(6) { --reveal-delay: 300ms; }
/* Below sm 480, tiles reveal one at a time in a single column, so the faster
   500ms with a 60ms stagger reads better. At sm and up, tiles reveal in
   multi-column rows together, so the slower 700ms with a 120ms stagger gives
   the cascade more room to breathe. */
@media (min-width: 480px) {
  .campaign-tile.is-revealing {
    transition:
      transform 220ms cubic-bezier(0.22,0.61,0.36,1),
      border-color 220ms,
      opacity 700ms ease-out var(--reveal-delay, 0ms),
      translate 700ms ease-out var(--reveal-delay, 0ms);
  }
  .campaign-tile.is-revealing:nth-child(2) { --reveal-delay: 120ms; }
  .campaign-tile.is-revealing:nth-child(3) { --reveal-delay: 240ms; }
  .campaign-tile.is-revealing:nth-child(4) { --reveal-delay: 360ms; }
  .campaign-tile.is-revealing:nth-child(5) { --reveal-delay: 480ms; }
  .campaign-tile.is-revealing:nth-child(6) { --reveal-delay: 600ms; }
}

/* Sitewide scroll-reveal extension. Covers the three card classes used
   across the homepage Selected Work grid, the Selected Work page grid, the
   COSV THE PROJECTS grid, and the Contact intent grid, plus the case study
   scope strip (.scope-metrics). Mirrors the corrected campaign-tile pattern
   at 6519e20: hover transitions (transform, border-color) carry no delay;
   reveal transitions (opacity, translate) source their delay from
   --reveal-delay (falls back to 0ms when unset). These surfaces deliberately
   do NOT use an nth-child stagger — each element fades individually at the
   default 0ms delay as it crosses the viewport threshold, which reads
   cleaner across variable card counts and the filter-driven re-renders on
   the Selected Work page. The bespoke six-tile campaign showcase keeps its
   tight stagger; this is the calmer pattern for the standard surfaces.
   Hidden-state (opacity 0 + translate offset) and visible-state values are
   shared across all four surfaces; transition lists differ: cards keep the
   transform + border-color hover entries; the strip has no hover, so its
   transition carries only opacity and translate.
   Hidden state is supplied by the pre-paint guard (.reveal-armed :not(
   .is-visible)), not by .is-revealing, so prerendered targets paint hidden on
   the first frame for JS+motion visitors and never blink. .is-revealing (added
   by the hook on mount) now only carries the transition below; the visible-
   state rule still keys on .is-revealing.is-visible. No-JS / reduced-motion:
   .reveal-armed is never set, so targets render visible at rest. */
.reveal-armed .pcard:not(.is-visible),
.reveal-armed .subwork-card:not(.is-visible),
.reveal-armed .intent-card:not(.is-visible),
.reveal-armed .featured:not(.is-visible),
.reveal-armed .build-item:not(.is-visible),
.reveal-armed .scope-metrics:not(.is-visible),
.reveal-armed .scope-tile:not(.is-visible),
.reveal-armed .phase:not(.is-visible),
.reveal-armed .reveal-item:not(.is-visible) {
  opacity: 0;
  translate: 0 20px;
}
.pcard.is-revealing.is-visible,
.subwork-card.is-revealing.is-visible,
.intent-card.is-revealing.is-visible,
.featured.is-revealing.is-visible,
.build-item.is-revealing.is-visible,
.scope-metrics.is-revealing.is-visible,
.scope-tile.is-revealing.is-visible,
.phase.is-revealing.is-visible,
.reveal-item.is-revealing.is-visible {
  opacity: 1;
  translate: 0 0;
}
.pcard.is-revealing,
.subwork-card.is-revealing,
.intent-card.is-revealing,
.featured.is-revealing,
.build-item.is-revealing {
  transition:
    transform 220ms cubic-bezier(0.22,0.61,0.36,1),
    border-color 220ms,
    opacity 500ms ease-out var(--reveal-delay, 0ms),
    translate 500ms ease-out var(--reveal-delay, 0ms);
}
.scope-metrics.is-revealing,
.scope-tile.is-revealing,
.phase.is-revealing,
.reveal-item.is-revealing {
  transition:
    opacity 500ms ease-out var(--reveal-delay, 0ms),
    translate 500ms ease-out var(--reveal-delay, 0ms);
}
@media (min-width: 480px) {
  .pcard.is-revealing,
  .subwork-card.is-revealing,
  .intent-card.is-revealing,
  .featured.is-revealing,
  .build-item.is-revealing {
    transition:
      transform 220ms cubic-bezier(0.22,0.61,0.36,1),
      border-color 220ms,
      opacity 700ms ease-out var(--reveal-delay, 0ms),
      translate 700ms ease-out var(--reveal-delay, 0ms);
  }
  .scope-metrics.is-revealing,
  .scope-tile.is-revealing,
  .phase.is-revealing,
  .reveal-item.is-revealing {
    transition:
      opacity 700ms ease-out var(--reveal-delay, 0ms),
      translate 700ms ease-out var(--reveal-delay, 0ms);
  }
}

.roadmap {
  display: grid; grid-template-columns: 1fr;
  gap: var(--space-5); margin-top: 32px;
  position: relative;
}
@media (min-width: 480px) {
  /* sm */
  .roadmap { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 768px) {
  /* md */
  .roadmap { grid-template-columns: repeat(4, 1fr); }
}
.phase { padding-top: 24px; border-top: 1.5px solid var(--fg-on-cream); position: relative; }
.phase .pnum {
  font-family: var(--font-body); font-weight: 500;
  font-size: 11px; letter-spacing: 2.5px; text-transform: uppercase;
  color: var(--fg-on-cream-dimmer); margin-bottom: 8px;
}
.phase .ptitle {
  font-family: var(--font-display); font-weight: 600; font-size: 26px;
  margin: 0 0 12px 0; line-height: 1;
}
.phase p { font-size: 13px; color: var(--fg-on-cream-dim); margin: 0; line-height: 1.5; }

.closing-strip {
  padding: 96px 0; text-align: center;
}
.closing-strip .quote {
  font-family: var(--font-serif); font-style: italic;
  font-size: 32px; line-height: 1.4;
  color: var(--fg-on-navy); max-width: 800px;
  margin: 0 auto 32px;
}

/* Aria specific */
.aria-hero {
  min-height: 100vh; display: flex; flex-direction: column;
  justify-content: center; align-items: center; text-align: center;
  padding-top: clamp(88px, 14vw, 140px); padding-bottom: 80px;
  position: relative; overflow: hidden;
}
.aria-hero > .container { width: min(100%, max-content); }
/* Aria hero is a centered full-height hero, so the breadcrumb is pinned
   top-left to the content column instead of sitting in the centered stack. */
.aria-hero-crumb { position: absolute; top: 0; left: 0; right: 0; }
.aria-hero-crumb .breadcrumb { margin-bottom: 0; text-align: left; }
.aria-hero .breadcrumb { color: var(--fg-on-navy-dim); }
.aria-hero .crumb-link:hover { color: var(--fg-on-navy); }
.aria-hero h1 {
  font-family: var(--font-display); font-size: clamp(96px, 18vw, 240px);
  line-height: 1.15;
  margin: 0 0 32px 0;
  color: var(--fg-on-navy);
}
.aria-hero .sub {
  font-family: var(--font-serif); font-style: italic;
  font-size: clamp(20px, 3vw, 22px); line-height: 1.5;
  color: var(--fg-on-navy); max-width: 680px;
  margin: 0 0 24px 0;
}
.aria-hero .micro {
  font-family: var(--font-serif); font-style: italic;
  font-size: 16px; color: var(--fg-on-navy-dim); max-width: 680px;
}
.aria-chapter-caption {
  margin-top: 16px;
  font-size: 12px;
  letter-spacing: 1px;
  color: var(--fg-on-cream-dimmer);
}
/* Excerpt */
.excerpt-block {
  border-left: 2px solid var(--accent-secondary);
  padding: 8px 0 8px 32px;
  margin: 0;
}
.excerpt-block p {
  font-family: var(--font-serif); font-style: italic;
  font-size: clamp(20px, 3vw, 22px); line-height: 1.55;
  color: var(--fg-on-cream); max-width: 680px; margin: 0;
}

/* Selected work */
.swork-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-5);
}
/* Selected Work filter chip. Lifted from the prior inline-style block on the
   Pages.jsx filter buttons (~lines 25-36) to comply with CLAUDE.md section 5
   inline-style rule, and to give the chips a class hook for the 8px radius
   from --radius-button. Conditional background and color (driven by the
   filter===f render-time state) stay inline by design per section 5. */
.swork-filter {
  font-family: var(--font-body);
  font-size: 12px;
  letter-spacing: 2px;
  text-transform: uppercase;
  padding: 10px 18px;
  cursor: pointer;
  border: 1px solid var(--fg-on-cream);
  border-radius: var(--radius-button);
  /* Inactive look, formerly an inline style on every filter button. */
  background: transparent;
  color: var(--fg-on-cream);
}
.swork-filter.is-active { background: var(--fg-on-cream); color: var(--bg-primary); }
.page-sub--work { font-style: normal; font-family: var(--font-body); color: var(--fg-on-cream-dim); font-size: 18px; }
.swork-filters { display: flex; gap: 8px; margin-bottom: 48px; flex-wrap: wrap; }
.swork-grid--spaced { margin-bottom: 96px; }
.contact-tail-space { height: 96px; }
.eyebrow--about { margin-bottom: 16px; }
.page-title--about { font-size: clamp(56px, 8vw, 96px); margin: 0 0 16px; }

/* Contact */
.intent-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-5);
  margin-top: 32px;
}
.intent-card {
  border: 1.5px solid var(--accent-secondary);
  padding: 32px;
  display: flex; flex-direction: column; gap: 16px;
  cursor: pointer;
  transition: transform 220ms cubic-bezier(0.22,0.61,0.36,1), border-color 220ms;
  /* Token applied surgically; no media panel, so no overflow: hidden. */
  border-radius: var(--radius-card);
}
.intent-card:hover { transform: translateY(-4px); border-color: var(--fg-on-cream); }
.intent-card h2 {
  font-family: var(--font-display); font-weight: 600; font-size: clamp(24px, 4.5vw, 32px);
  line-height: 1;
  margin: 0; color: var(--fg-on-cream);
}
.subwork-card h3 {
  font-family: var(--font-display); font-weight: 600; font-size: clamp(24px, 4.5vw, 32px);
  line-height: 1;
  margin: 0; color: var(--fg-on-cream);
}
/* Reserve a two-line title zone on the Contact intent cards so a one-line title
   ("Hire me for AI roles") occupies the same height as a two-line title and all
   card body paragraphs start on the same row. 2lh tracks the clamp font size at
   every width (no fixed px). Scoped to .intent-card h2 only, so the separate
   .subwork-card h3 title rule is unaffected. */
.intent-card h2 { min-height: 2lh; }
.intent-card p, .subwork-card p { font-size: 14px; line-height: 1.55; color: var(--fg-on-cream-dim); margin: 0; flex: 1; }
.intent-card .cta, .subwork-card .cta { font-size: 13px; font-weight: 500; color: var(--fg-on-cream); border-bottom: 1px solid currentColor; align-self: flex-start; padding-bottom: 2px; }

/* About page */
.about-hero { padding-top: clamp(88px, 14vw, 140px); padding-bottom: 64px; }
.about-hero > .container {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
  align-items: center;
}
@media (min-width: 414px) {
  /* about-hero local breakpoint, not standard sm */
  .about-hero > .container {
    grid-template-columns: 1fr 1.2fr;
    gap: var(--space-7);
  }
}
@media (min-width: 768px) {
  /* md, original desktop value */
  .about-hero > .container { gap: var(--space-8); }
}
.about-hero .photo { aspect-ratio: 4/5; background: var(--bg-inverse); overflow: hidden; }
.about-hero .photo img { width: 100%; height: 100%; object-fit: cover; }
.about-hero-italic {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 22px;
  line-height: 1.5;
  color: var(--fg-on-cream-dim);
  margin: 0;
  max-width: 480px;
}

.about-langs {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  margin-top: var(--space-6);
}
.about-lang {
  display: grid;
  grid-template-columns: minmax(80px, max-content) 1fr;
  gap: var(--space-5);
  align-items: center;
}
@media (min-width: 768px) {
  /* md, restore desktop 3-column treatment */
  .about-langs {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 32px;
  }
  .about-lang { display: block; }
}
.about-lang h3 { font-family: var(--font-display); font-weight: 700; font-size: clamp(22px, 4vw, 28px); margin: 0 0 8px 0; line-height: 1; }
.about-lang p { font-size: 14px; line-height: 1.5; color: var(--fg-on-cream-dim); margin: 0; }

.about-translation {
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.55;
  color: var(--fg-on-cream-dim);
  max-width: 680px;
  margin-top: var(--space-7);
}
@media (min-width: 768px) {
  /* md */
  .about-translation { margin-top: var(--space-8); }
}

/* AboutPage "what I am working on now" 3-up grid. Single-column responsiveness
   ships in phase 4 step 7. */
.now-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
}
@media (min-width: 480px) {
  /* sm */
  .now-grid { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 768px) {
  /* md */
  .now-grid {
    grid-template-columns: 1fr 1fr 1fr;
    gap: var(--space-7);
  }
}
.now-label { font-size: var(--display-sm); font-family: var(--font-display); font-weight: 600; margin: 0 0 12px; line-height: 1; }
.now-desc { font-size: 14px; line-height: 1.55; color: var(--fg-on-cream-dim); margin: 0; }
.about-hero-tagline { font-size: 85%; color: var(--fg-on-cream-dimmer); }

/* utility */
.gold { color: var(--accent-signal); }
.nowrap { white-space: nowrap; }
.divider {
  border: 0;
  border-top: 1.5px solid var(--accent-secondary);
  margin: 64px 0;
}
.on-navy .divider { border-top-color: rgba(244,238,223,0.18); }
