/* ============================================================
   Esther Omah Atasie — portfolio
   A merge of two systems:
     · cinematic pinned hero, chat-bubble voice, marquee columns,
       grayscale switch      → editorial/film direction
     · tab-filtered project cards, numbers band, writing list,
       testimonials, contact panel → structured content direction
   Light theme on a whitish-grey base.
   Namespaced .fo-* to avoid collisions with older stylesheets.
   ============================================================ */

:root {
  color-scheme: light;

  /* The two channels every neutral is mixed from. Flipping these two
     lines is what turns the whole page over into dark. */
  --ink-rgb:   13 13 16;      /* text / hairlines / wireframe fills */
  --paper-rgb: 255 255 255;   /* scrims and highlights that sit on panels */

  /* surface — whitish grey base */
  --bg:        #eeeef1;
  --bg-raise:  #f8f8fa;
  --bg-white:  #fdfdfe;

  /* the media card the hero and every project panel is drawn on */
  --panel:     #ffffff;
  --panel-2:   #fbfbfd;   /* phone bodies */
  --panel-bar: #f0f0f4;   /* the browser-chrome strip in wireframes */

  /* the inverted surface: pure black on light, a raised near-black on dark
     (a true black panel would vanish into a dark page) */
  --black:  #000000;
  --ink:    #0d0d10;
  --ink-2:  #17171c;
  --muted:  rgb(var(--ink-rgb) / 0.62);
  --faint:  rgb(var(--ink-rgb) / 0.40);
  --line:   rgb(var(--ink-rgb) / 0.13);
  --line-2: rgb(var(--ink-rgb) / 0.07);

  /* light-on-dark */
  --on-dark:   #f4f4f6;
  --on-dark-2: rgba(244, 244, 246, 0.70);
  --on-dark-3: rgba(244, 244, 246, 0.42);

  /* accents — sampled from the logo mark */
  --periwinkle: #7b80e4;
  --mauve:      #b98ac2;
  --coral:      #fb8b71;
  --brand: linear-gradient(160deg, var(--periwinkle) 0%, var(--mauve) 48%, var(--coral) 100%);
  --brand-v: linear-gradient(180deg, var(--periwinkle) 0%, var(--mauve) 50%, var(--coral) 100%);

  /* legacy aliases kept so older rules resolve to the new palette */
  --blue:   var(--periwinkle);
  --indigo: var(--periwinkle);
  --green:  var(--mauve);
  --plum:   var(--mauve);
  --clay:   var(--coral);

  /* neutral tints — media placeholders */
  --tint-1: #e3e3e8;
  --tint-2: #e9e9ee;
  --tint-3: #dcdce2;
  --tint-4: #f0f0f3;

  --edge: clamp(18px, 4vw, 56px);
  /* The page had four spines: the nav pill and the work CTA at 1180, the
     footer's wrap content at 1068, and the project cards at 1060. Everything
     now measures to --stage-max, so nav, cards, CTA and footer share one
     left and right edge. --max is the wrap's OUTER width, i.e. the card
     width plus the padding the wrap adds back inside. */
  --max: calc(var(--stage-max) + 2 * var(--edge));
  --stage-max: 1060px;   /* hero card + project panels share this width */

  /* type — Bricolage for headings, Inter for everything functional,
     Fraunces italic as the accent face (emphasis + pull quotes) */
  --font-display: "Bricolage Grotesque", "Helvetica Neue", sans-serif;
  --font-serif:   "Fraunces", Georgia, serif;
  --font-body:    "Inter", system-ui, sans-serif;

  --r-pill: 999px;
  --r-lg: 40px;
  --r-md: 24px;
  --r-sm: 16px;
  --r-bubble: 64px;

  /* dark panels sit on a light page and need no edge; on a dark page they do */
  --inv-line: transparent;
}

/* ============================================================
   DARK THEME
   Declared once and applied two ways: [data-theme="dark"] for an
   explicit choice, and prefers-color-scheme for people who have
   never touched the switch. The :not([data-theme="light"]) guard
   means an explicit "light" still wins on a dark OS.
   ============================================================ */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { color-scheme: dark; }
}
:root[data-theme="dark"] { color-scheme: dark; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ink-rgb:   240 240 245;
    --paper-rgb: 16 16 20;
    --bg: #0b0b0f; --bg-raise: #141419; --bg-white: #17171d;
    --panel: #121217; --panel-2: #17171d; --panel-bar: #1d1d24;
    --black: #1a1a21; --ink: #f0f0f5; --ink-2: #dcdce4;
    --line: rgb(var(--ink-rgb) / 0.17); --line-2: rgb(var(--ink-rgb) / 0.10);
    --tint-1: #202027; --tint-2: #1b1b21; --tint-3: #26262e; --tint-4: #17171c;
  --inv-line: rgb(var(--ink-rgb) / 0.11);
  }
}
:root[data-theme="dark"] {
  --ink-rgb:   240 240 245;
  --paper-rgb: 16 16 20;
  --bg: #0b0b0f; --bg-raise: #141419; --bg-white: #17171d;
  --panel: #121217; --panel-2: #17171d; --panel-bar: #1d1d24;
  --black: #1a1a21; --ink: #f0f0f5; --ink-2: #dcdce4;
  --line: rgb(var(--ink-rgb) / 0.17); --line-2: rgb(var(--ink-rgb) / 0.10);
  --tint-1: #202027; --tint-2: #1b1b21; --tint-3: #26262e; --tint-4: #17171c;
  --inv-line: rgb(var(--ink-rgb) / 0.11);
}

/* every inverted surface picks up the edge together */
.fo-nav, .fo-numbers, .fo-contact, .fo-ab__now, .fo-ab__cap {
  border: 1px solid var(--inv-line);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

body.fo {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* clip, not hidden: setting overflow-x:hidden forces overflow-y to auto,
     which makes body a scroll container and breaks position:sticky on every
     descendant — that is why the product tab bar would not stick on mobile.
     overflow-x:clip clips the same way without creating a scrollport. */
  overflow-x: clip;
  transition: background-color .45s ease, color .45s ease;
}
@media (prefers-reduced-motion: reduce) { body.fo { transition: none; } }
/* :where() keeps the reset at zero specificity so component rules
   (nav links, ghost buttons) can set their own colour without a fight. */
:where(body.fo) a { color: inherit; text-decoration: none; }
body.fo img { display: block; max-width: 100%; }
body.fo.is-locked { overflow: hidden; }

.fo-display { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.032em; line-height: 1.06; }

/* Fraunces earns its place as the accent voice, never as a heading:
   emphasis inside body copy, and the testimonial quotes. Italic only —
   that's the only cut loaded. */
:where(body.fo) em { font-family: var(--font-serif); font-style: italic; font-weight: 400; }
.fo-vcard blockquote,
.fo-msg--pull {
  font-family: var(--font-serif); font-style: italic; font-weight: 400;
  letter-spacing: -0.004em;
}
.fo-wrap { max-width: var(--max); margin: 0 auto; padding-left: var(--edge); padding-right: var(--edge); }
.fo-center { text-align: center; }
.fo-h2 { font-size: clamp(28px, 4.4vw, 50px); margin: 0 0 12px; }
.fo-sub { font-size: 16px; color: var(--muted); max-width: 62ch; margin: 0 auto; }
.fo-section { padding: clamp(56px, 8vw, 100px) 0; }

/* page-wide colour ⇄ grayscale */
.fo-page { transition: filter .5s ease; }
body.is-gray .fo-page { filter: grayscale(1); }

/* ============================================================
   BUTTONS
   ============================================================ */
.fo-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 42px; padding: 0 20px;
  border-radius: var(--r-pill);
  font-size: 14px; font-weight: 500; font-family: inherit;
  border: 1px solid transparent;
  cursor: pointer; white-space: nowrap;
  transition: background .22s ease, color .22s ease, border-color .22s ease, transform .22s ease;
}
.fo-btn:active { transform: scale(.97); }
.fo-btn--ghost  { border-color: rgba(244,244,246,.3); color: var(--on-dark); background: transparent; }
.fo-btn--ghost:hover { border-color: var(--on-dark); }
.fo-btn--light  { background: var(--on-dark); color: var(--ink); }
.fo-btn--light:hover { background: #fff; }
.fo-btn--ink    { background: var(--black); color: var(--on-dark); border-color: var(--inv-line); }
.fo-btn--ink:hover { background: var(--ink-2); }
.fo-btn--outline{ border-color: var(--line); color: var(--ink); background: transparent; }
.fo-btn--outline:hover { border-color: var(--ink); }

/* primary CTA — carries the logo gradient */
.fo-btn--brand {
  position: relative; color: #fff; border: 0;
  background: var(--brand); background-size: 160% 160%;
  background-position: 0% 50%;
  box-shadow: 0 10px 26px -14px rgba(123,128,228,.85);
  transition: background-position .55s cubic-bezier(.2,.8,.2,1),
              box-shadow .3s ease, transform .22s ease;
}
.fo-btn--brand:hover {
  background-position: 100% 50%;
  box-shadow: 0 14px 32px -12px rgba(251,139,113,.9);
}

/* ============================================================
   1. HERO — pins for a full extra viewport.
   White placeholder stands in for the real film/portrait, so the
   overlaid UI is dark-on-light.
   ============================================================ */
.fo-hero { position: relative; height: 115vh; }
.fo-hero__stage {
  position: sticky; top: 0;
  height: 100vh; min-height: 560px;
  overflow: hidden;
  /* one set of insets for the card and the UI overlaid on it.
     --hx centres the card once the viewport is wider than --stage-max. */
  --hero-t: clamp(104px, 13vh, 150px);
  --hero-b: clamp(30px, 13vh, 168px);
  --hx: max(var(--edge), calc((100% - var(--stage-max)) / 2));
}
/* ============================================================
   HERO — one claim, at size. Everything else waits.
   ============================================================ */
.fo-hero__stage {
  display: flex; flex-direction: column; justify-content: center;
  padding: 0 var(--edge);
}
.fo-claim {
  margin: 0; max-width: 15ch;
  font-size: clamp(44px, 8.6vw, 132px);
  line-height: .94; letter-spacing: -.045em; color: var(--ink);
}
.fo-claim span { display: block; }
.fo-claim span:last-child {
  background: var(--brand);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.fo-claim__foot {
  position: absolute; left: var(--edge); right: var(--edge);
  bottom: clamp(22px, 4vh, 40px);
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  font-size: 11px; letter-spacing: .04em; color: var(--faint);
}
.fo-claim__scroll { display: inline-flex; align-items: center; gap: 9px; }
.fo-claim__scroll i {
  display: block; width: 34px; height: 1px; background: var(--line);
  position: relative; overflow: hidden;
}
.fo-claim__scroll i::after {
  content: ""; position: absolute; inset: 0; width: 40%; background: var(--brand);
  animation: fo-scrollhint 2.2s ease-in-out infinite;
}
@keyframes fo-scrollhint {
  0% { transform: translateX(-100%); }
  60%, 100% { transform: translateX(250%); }
}
@media (max-width: 780px) {
  .fo-hero { height: auto; }
  .fo-hero__stage { position: static; height: auto; min-height: 76vh; padding: 130px var(--edge) 70px; }
  .fo-claim__foot { position: static; margin-top: 40px; }
}
@media (prefers-reduced-motion: reduce) { .fo-claim__scroll i::after { animation: none; } }

/* ============================================================
   2. NAV — capsule pinned to the top, visible from the start
   ============================================================ */
.fo-nav {
  position: fixed; z-index: 700;
  top: clamp(14px, 2.2vh, 22px); left: 50%;
  transform: translateX(-50%);
  width: min(calc(100% - 2 * var(--edge)), var(--stage-max));
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding: 9px 9px 9px 10px;
  /* glass rather than a hard fill, so it reads on either theme:
     paper channel + blur means light-on-white and dark-on-black */
  background: rgb(var(--paper-rgb) / .74);
  backdrop-filter: blur(22px) saturate(1.5);
  -webkit-backdrop-filter: blur(22px) saturate(1.5);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  box-shadow: 0 14px 40px -24px rgb(var(--ink-rgb) / .45);
}
.fo-brand {
  display: inline-flex; align-items: center; gap: 11px;
  color: var(--ink); white-space: nowrap;
}
.fo-brand__name { font-family: var(--font-display); font-weight: 800; font-size: 21px; letter-spacing: -0.03em; }
.fo-brand__pic {
  width: 36px; height: 36px; border-radius: 50%; flex-shrink: 0;
  background-color: var(--periwinkle); background-image: var(--brand);
  background-size: cover; background-position: center;
  border: 1.5px solid rgba(244,244,246,.24);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 600; color: #fff;
  transition: transform .3s cubic-bezier(.16,1,.3,1);
}
.fo-brand:hover .fo-brand__pic { transform: scale(1.06); }
/* once a real photo is set, hide the stand-in initial */
.fo-brand__pic[style*="url"] { color: transparent; background-image: none; }

.fo-nav__links { display: flex; gap: 26px; }
.fo-nav__links {
  position: relative; display: inline-flex; align-items: center; gap: 2px;
  padding: 3px; border-radius: 999px;
  border: 0; background: rgb(var(--ink-rgb) / .055);
}
.fo-nav__links a {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 13.5px; color: var(--muted); padding: 7px 15px; border-radius: 999px;
  transition: color .25s ease;
}
.fo-nav__links a:hover { color: var(--ink); }
/* no markers at all — the chip is the only thing saying where you are */
.fo-nav__links a[aria-current="page"] { color: var(--ink); font-weight: 600; }
/* one indicator that slides between them */
.fo-nav__ind {
  position: absolute; top: 3px; bottom: 3px; left: 0; width: 0;
  border-radius: 999px; background: var(--bg-white, #fff);
  border: 0; pointer-events: none;
  box-shadow: 0 1px 2px rgb(var(--ink-rgb) / .10), 0 4px 12px -5px rgb(var(--ink-rgb) / .20);
  transition: transform .5s cubic-bezier(.22,1,.28,1), width .5s cubic-bezier(.22,1,.28,1), opacity .3s ease;
  opacity: 0;
}
.fo-nav__ind.is-on { opacity: 1; }
.fo-nav__actions { display: flex; align-items: center; gap: 8px; }

.fo-icon-btn {
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid var(--line); background: transparent;
  color: var(--ink); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 15px; line-height: 1;
  transition: border-color .22s ease, background .22s ease;
}
.fo-icon-btn:hover { border-color: var(--ink); background: rgb(var(--ink-rgb) / .07); }

.fo-burger {
  display: none; width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid rgba(244,244,246,.28); background: transparent;
  cursor: pointer; position: relative;
}
.fo-burger i {
  position: absolute; left: 50%; top: 50%; width: 16px; height: 1.6px;
  background: var(--ink); border-radius: 2px;
  transform: translate(-50%, -50%);
  transition: transform .3s cubic-bezier(.2,.8,.2,1);
}
.fo-burger i:nth-child(1) { transform: translate(-50%, calc(-50% - 4.5px)); }
.fo-burger i:nth-child(2) { transform: translate(-50%, calc(-50% + 4.5px)); }
body.is-menu .fo-burger i:nth-child(1) { transform: translate(-50%, -50%) rotate(45deg); }
body.is-menu .fo-burger i:nth-child(2) { transform: translate(-50%, -50%) rotate(-45deg); }

.fo-sheet {
  position: fixed; inset: 0; z-index: 690;
  background: var(--black); color: var(--on-dark);
  padding: 108px var(--edge) 40px;
  display: flex; flex-direction: column; gap: 4px;
  opacity: 0; visibility: hidden; transform: translateY(-10px);
  transition: opacity .32s ease, transform .32s ease, visibility 0s linear .32s;
}
.fo-sheet.is-open { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
.fo-sheet a {
  font-family: var(--font-display); font-weight: 700; font-size: 32px; letter-spacing: -.03em;
  padding: 14px 0; border-bottom: 1px solid rgba(244,244,246,.14);
}

/* ============================================================
   3 + 9. POST CARDS — chat-bubble voice
   ============================================================ */
.fo-post-block { padding: clamp(56px, 8vw, 96px) 0; display: flex; justify-content: center; }
.fo-bubbles { width: 100%; max-width: 640px; padding: 0 var(--edge); }
.fo-msgs { display: flex; flex-direction: column; gap: 10px; align-items: flex-start; margin-bottom: 22px; }
.fo-msg {
  margin: 0; background: var(--bg-white);
  border-radius: var(--r-bubble);
  padding: 18px 28px;
  font-size: 16px; line-height: 1.6;
  box-shadow: 0 2px 10px -6px rgba(23,23,28,.25);
}
.fo-msg--lead { font-size: 19px; font-weight: 500; }
/* The opening bubble carries the positioning line, so it is set in the
   display face — the type contrast is what made the first read work.
   Scoped to the thread: the sign-off block uses --lead as a small label. */
.fo-thread .fo-msg--lead {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(21px, 2.5vw, 33px);
  line-height: 1.26;
  letter-spacing: -.022em;
  color: var(--ink);
}
.fo-thread .fo-msg--lead b { font-weight: 700; }
.fo-msg em { font-style: italic; color: var(--coral); }
.fo-post-foot {
  display: flex; justify-content: space-between; align-items: center;
  gap: 18px; flex-wrap: wrap;
  padding-top: 20px; border-top: 1px solid var(--line-2);
}
.fo-poster { display: flex; align-items: center; gap: 11px; }
.fo-av {
  width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0;
  background: var(--brand);
}
.fo-poster b { display: block; font-size: 13.5px; }
.fo-poster span { font-size: 12px; color: var(--faint); }
.fo-post-btns { display: flex; gap: 10px; flex-wrap: wrap; }

/* ============================================================
   4. WORK — full-bleed sticky stage, one project per screen.
   The white panel fills the viewport; meta/title/CTA are overlaid
   inside it rather than stacked below, so it reads edge-to-edge.
   ============================================================ */
.fo-showcase { position: relative; }
.fo-showcase__wrap { position: relative; }        /* height set in JS: N x 100vh */
.fo-showcase__stage {
  position: sticky; top: 0;
  height: 100vh; min-height: 560px;
  overflow: hidden;
}

.fo-proj {
  position: absolute; inset: 0;
  /* one set of insets drives the panel and everything overlaid on it */
  --pt: clamp(94px, 11vh, 130px);   /* clears the nav capsule */
  --pb: clamp(42px, 9.4vh, 120px);
  /* every overlay reads --px, so centring here re-centres the whole panel */
  --px: max(var(--edge), calc((100% - var(--stage-max)) / 2));
  --pad: clamp(20px, 2.4vw, 38px);
  --ease: cubic-bezier(.16, 1, .3, 1);   /* long, settling ease */
  opacity: 0; visibility: hidden;
  transition: opacity .8s var(--ease), visibility 0s linear .95s;
}
.fo-proj.is-on { opacity: 1; visibility: visible; transition-delay: 0s; }

/* --- slow, staged entrance: panel rises, text follows --- */
.fo-proj__role, .fo-proj__idx {
  opacity: 0; transform: translateY(-12px);
  transition: opacity .7s var(--ease), transform .8s var(--ease);
  transition-delay: .12s;
}
.fo-proj.is-on .fo-proj__role,
.fo-proj.is-on .fo-proj__idx { opacity: 1; transform: none; }

.fo-proj h3 {
  opacity: 0; transform: translateY(38px);
  transition: opacity .8s var(--ease), transform .95s var(--ease);
  transition-delay: .18s;
}
.fo-proj.is-on h3 { opacity: 1; transform: none; }
.fo-proj__tags {
  opacity: 0; transform: translateY(38px);
  transition: opacity .8s var(--ease), transform .95s var(--ease);
  transition-delay: .24s;
}
.fo-proj.is-on .fo-proj__tags { opacity: 1; transform: none; }

.fo-proj__side {
  opacity: 0; transform: translateY(26px);
  transition: opacity .8s var(--ease), transform .95s var(--ease);
  transition-delay: .3s;
}
.fo-proj.is-on .fo-proj__side { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .fo-proj, .fo-proj__media, .fo-proj__role,
  .fo-proj__idx, .fo-proj h3, .fo-proj__side {
    transition: none !important; transform: none !important;
  }
}

/* white placeholder panel — fills the screen.
   Positioning and entrance state live in ONE rule; declaring
   .fo-proj__media twice let the later copy win the cascade. */
.fo-proj__media {
  position: absolute;
  inset: var(--pt) var(--px) var(--pb);
  background: var(--panel);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  overflow: hidden;   /* the filmstrip and cluster are wider than the panel by design */
  display: flex; align-items: flex-start; justify-content: flex-start;
  box-shadow: 0 40px 80px -60px rgba(23,23,28,.5);
  opacity: 0;
  transform: translateY(46px) scale(.965);
  transition: transform .95s var(--ease), opacity .7s var(--ease);
}
.fo-proj.is-on .fo-proj__media { opacity: 1; transform: none; }

/* overlays, inset inside the panel */
.fo-proj__role {
  position: absolute; z-index: 2;
  top: calc(var(--pt) + var(--pad)); left: calc(var(--px) + var(--pad));
  display: flex; flex-wrap: wrap; gap: 6px 12px;
  font-size: 12.5px; color: var(--muted);
}
.fo-proj__role span { position: relative; }
.fo-proj__role span + span::before {
  content: ""; position: absolute; left: -7px; top: 50%; transform: translateY(-50%);
  width: 1px; height: 10px; background: var(--line);
}
.fo-proj__idx {
  position: absolute; z-index: 2;
  top: calc(var(--pt) + var(--pad)); right: calc(var(--px) + var(--pad));
  font-size: 12px; letter-spacing: .16em; color: var(--faint);
}
.fo-proj__body {
  position: absolute; z-index: 2;
  left: calc(var(--px) + var(--pad)); right: calc(var(--px) + var(--pad));
  bottom: calc(var(--pb) + var(--pad));
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 30px; flex-wrap: wrap;
}
.fo-proj h3 {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(32px, 5.4vw, 66px); line-height: 1;
  letter-spacing: -0.015em; margin: 0;
}
.fo-proj__side { max-width: 40ch; }
.fo-proj__side p { color: var(--muted); font-size: 15px; margin: 0 0 14px; }
/* numbers and counts carry the weight against the muted line */
.fo-proj__side p b { color: var(--ink); font-weight: 600; }

/* scope chips — what was actually done. They live under the project name, in the
   left column's slack, NOT under the blurb: .fo-proj__body is pinned to the panel's
   bottom edge and grows upward, so height added on the right rides up into the
   screens. The left column has 130px+ spare under the h3. */
.fo-proj__lead {
  display: flex; flex-direction: column; align-items: flex-start; gap: 18px;
  /* let the title wrap rather than let the whole row wrap: a stacked body is
     taller than the panel leaves room for and rides up into the screens */
  flex: 1 1 300px; min-width: 0;   /* basis, not auto: flex-wrap decides on the
                                      base size, so an auto basis wraps the row
                                      before flex-shrink ever runs */
}
.fo-proj__tags {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 6px; max-width: 34ch;
}
.fo-proj__tags li {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); background: rgb(123 128 228 / .12);
  padding: 5px 9px; border-radius: 5px; white-space: nowrap;
}

.fo-proj__go {
  position: relative;
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 14px; font-weight: 500;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--line);
  transition: gap .25s ease;
}
.fo-proj__go::after {
  content: ""; position: absolute; left: 0; bottom: -1px;
  width: 0; height: 2px; background: var(--brand);
  transition: width .35s cubic-bezier(.2,.8,.2,1);
}
.fo-proj__go:hover { gap: 14px; }
.fo-proj__go:hover::after { width: 100%; }

/* progress rail */
.fo-showcase__rail {
  position: absolute; z-index: 6;
  /* left:auto + width:max-content, or an absolutely positioned flex column
     stretches to the containing block instead of hugging its labels */
  left: auto; width: max-content;
  right: max(18px, calc((100% - var(--stage-max)) / 2 - 150px));
  top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
}
.fo-rail__item {
  display: flex; align-items: baseline; gap: 10px;
  background: none; border: 0; padding: 7px 0; cursor: pointer;
  font-family: inherit; text-align: left; color: var(--faint);
  opacity: .5;
  transition: opacity .35s ease, color .35s ease, transform .45s cubic-bezier(.16,1,.3,1);
}
.fo-rail__item i {
  font-style: normal; font-size: 10px; letter-spacing: .1em;
  font-variant-numeric: tabular-nums; color: inherit;
}
.fo-rail__item span {
  font-size: 13px; white-space: nowrap;
  border-bottom: 1px solid transparent;
  transition: border-color .35s ease;
}
.fo-rail__item:hover { opacity: .85; transform: translateX(2px); }
.fo-rail__item.is-on {
  opacity: 1; color: var(--ink); transform: translateX(4px);
}
.fo-rail__item.is-on i { color: var(--coral); }
.fo-rail__item.is-on span { border-bottom-color: var(--coral); font-weight: 500; }

/* the rail has nowhere to sit on narrow screens */
@media (max-width: 1240px) {
  .fo-showcase__rail { right: 20px; }
  .fo-rail__item span { display: none; }
  .fo-rail__item { gap: 0; }
}
@media (max-width: 940px) { .fo-showcase__rail { display: none; } }

.fo-proj {
  position: absolute; inset: 0;
  /* one set of insets drives the panel and everything overlaid on it */
  --pt: clamp(94px, 11vh, 130px);   /* clears the nav capsule */
  --pb: clamp(42px, 9.4vh, 120px);
  /* every overlay reads --px, so centring here re-centres the whole panel */
  --px: max(var(--edge), calc((100% - var(--stage-max)) / 2));
  --pad: clamp(20px, 2.4vw, 38px);
  --ease: cubic-bezier(.16, 1, .3, 1);   /* long, settling ease */
  opacity: 0; visibility: hidden;
  transition: opacity .8s var(--ease), visibility 0s linear .95s;
}
.fo-proj.is-on { opacity: 1; visibility: visible; transition-delay: 0s; }

/* --- slow, staged entrance: panel rises, text follows --- */
.fo-proj__role, .fo-proj__idx {
  opacity: 0; transform: translateY(-12px);
  transition: opacity .7s var(--ease), transform .8s var(--ease);
  transition-delay: .12s;
}
.fo-proj.is-on .fo-proj__role,
.fo-proj.is-on .fo-proj__idx { opacity: 1; transform: none; }

.fo-proj h3 {
  opacity: 0; transform: translateY(38px);
  transition: opacity .8s var(--ease), transform .95s var(--ease);
  transition-delay: .18s;
}
.fo-proj.is-on h3 { opacity: 1; transform: none; }

.fo-proj__side {
  opacity: 0; transform: translateY(26px);
  transition: opacity .8s var(--ease), transform .95s var(--ease);
  transition-delay: .3s;
}
.fo-proj.is-on .fo-proj__side { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .fo-proj, .fo-proj__media, .fo-proj__role,
  .fo-proj__idx, .fo-proj h3, .fo-proj__side {
    transition: none !important; transform: none !important;
  }
}

/* white placeholder panel — fills the screen.
   Positioning and entrance state live in ONE rule; declaring
   .fo-proj__media twice let the later copy win the cascade. */
.fo-proj__media {
  position: absolute;
  inset: var(--pt) var(--px) var(--pb);
  background: var(--panel);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  overflow: hidden;   /* the filmstrip and cluster are wider than the panel by design */
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 40px 80px -60px rgba(23,23,28,.5);
  opacity: 0;
  transform: translateY(46px) scale(.965);
  transition: transform .95s var(--ease), opacity .7s var(--ease);
}
.fo-proj.is-on .fo-proj__media { opacity: 1; transform: none; }

/* overlays, inset inside the panel */
.fo-proj__role {
  position: absolute; z-index: 2;
  top: calc(var(--pt) + var(--pad)); left: calc(var(--px) + var(--pad));
  display: flex; flex-wrap: wrap; gap: 6px 12px;
  font-size: 12.5px; color: var(--muted);
}
.fo-proj__role span { position: relative; }
.fo-proj__role span + span::before {
  content: ""; position: absolute; left: -7px; top: 50%; transform: translateY(-50%);
  width: 1px; height: 10px; background: var(--line);
}
.fo-proj__idx {
  position: absolute; z-index: 2;
  top: calc(var(--pt) + var(--pad)); right: calc(var(--px) + var(--pad));
  font-size: 12px; letter-spacing: .16em; color: var(--faint);
}
.fo-proj__body {
  position: absolute; z-index: 2;
  left: calc(var(--px) + var(--pad)); right: calc(var(--px) + var(--pad));
  bottom: calc(var(--pb) + var(--pad));
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 30px; flex-wrap: wrap;
}
.fo-proj h3 {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(32px, 5.4vw, 66px); line-height: 1;
  letter-spacing: -0.015em; margin: 0;
}
.fo-proj__side { max-width: 40ch; }
.fo-proj__side p { color: var(--muted); font-size: 15px; margin: 0 0 14px; }
.fo-proj__go {
  position: relative;
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 14px; font-weight: 500;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--line);
  transition: gap .25s ease;
}
.fo-proj__go::after {
  content: ""; position: absolute; left: 0; bottom: -1px;
  width: 0; height: 2px; background: var(--brand);
  transition: width .35s cubic-bezier(.2,.8,.2,1);
}
.fo-proj__go:hover { gap: 14px; }
.fo-proj__go:hover::after { width: 100%; }

/* mobile: unpin and stack */
@media (max-width: 1180px) {
  .fo-showcase__wrap { height: auto !important; }
  .fo-showcase__stage { position: static; height: auto; min-height: 0; }
  .fo-showcase__rail { display: none; }
  .fo-proj {
    position: static; opacity: 1; visibility: visible;
    /* the card is content-driven here, so this is what makes it longer */
    padding: clamp(44px, 7vw, 76px) 0; border-top: 1px solid var(--line-2);
  }
  .fo-proj__media {
    /* was a flat 250px at every size, and the responsive override for it
       lived in the about/footer block at 940 — so it never reached a
       tablet. Height now follows the shorter of the viewport's height
       and width: tall enough to show a screen on an iPad, short enough
       that a phone card is not taller than the screen. */
    position: static; inset: auto;
    height: clamp(300px, min(46vh, 40vw), 560px);
    margin: 0 var(--edge) clamp(26px, 4vw, 42px); box-shadow: none;
  }
  .fo-proj__role, .fo-proj__idx {
    position: static; padding: 0 var(--edge); margin-bottom: 10px;
  }
  .fo-proj__body {
    position: static; padding: 0 var(--edge);
    flex-direction: column; align-items: flex-start; gap: 14px;
  }
}

/* ============================================================
   5. NUMBERS
   ============================================================ */
.fo-numbers {
  position: relative; background: var(--black); color: var(--on-dark);
  border-radius: var(--r-lg); padding: 64px clamp(24px, 4vw, 56px) 52px;
}
/* NB: must stay `absolute`. As a relative <span> it falls back to an inline
   box, and transforms are ignored on inline boxes — which knocks the label
   off-centre and drops it inside the panel. */
.fo-numbers__tag {
  position: absolute; z-index: 2;
  top: -19px; left: 50%; transform: translateX(-50%);
  background: var(--bg); color: var(--ink); border: 1px solid var(--line);
  padding: 9px 22px; border-radius: var(--r-pill);
  font-size: 12px; letter-spacing: .13em; text-transform: uppercase;
  white-space: nowrap;
}
.fo-numbers__grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  align-items: stretch;
}
.fo-numbers__grid .fo-stat + .fo-stat {
  border-left: 1px solid rgba(244,244,246,.13);
}
.fo-stat {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  text-align: center; padding: 4px clamp(10px, 2vw, 26px);
}
.fo-stat b {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(40px, 5.6vw, 66px); line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--acc);
}
.fo-stat b > span { font: inherit; color: inherit; }   /* the counter, not the label */
.fo-stat i { display: block; width: 26px; height: 2px; border-radius: 2px; background: var(--acc); }
/* direct child only — otherwise this also swallows the counter span inside <b> */
.fo-stat > span { font-size: 13.5px; line-height: 1.45; color: var(--on-dark-3); max-width: 16ch; }
.fo-stat:nth-child(1) { --acc: var(--periwinkle); }
.fo-stat:nth-child(2) { --acc: var(--mauve); }
.fo-stat:nth-child(3) { --acc: var(--coral); }

/* ============================================================
   6a. ABOUT — annotated portrait + rules you can open
   ============================================================ */
.fo-ab {
  display: grid; grid-template-columns: minmax(0, .82fr) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 72px); align-items: start;
}

/* --- the portrait stack --- */
.fo-ab__art { position: relative; padding: 14px 22px 34px 14px; }
.fo-ab__ghost {
  position: absolute; inset: 34px 0 0 34px;
  border-radius: var(--r-md);
  background: var(--brand); opacity: .16;
}
.fo-ab__photo {
  position: relative; z-index: 1;
  aspect-ratio: 4 / 5;
  border-radius: var(--r-md); overflow: hidden;
  background: var(--bg-raise); border: 1px solid var(--line-2);
  display: flex; align-items: center; justify-content: center;
  transform: rotate(-1.6deg);
  transition: transform .7s cubic-bezier(.16,1,.3,1);
}
.fo-ab__art:hover .fo-ab__photo { transform: rotate(0deg) scale(1.012); }
.fo-ab__cap {
  position: absolute; left: 14px; bottom: 14px; z-index: 2;
  display: inline-flex; align-items: center; gap: 9px;
  padding: 9px 16px; border-radius: var(--r-pill);
  background: var(--black); color: var(--on-dark);
  font-size: 12.5px; white-space: nowrap;
}
.fo-ab__cap i { width: 8px; height: 8px; border-radius: 50%; background: var(--brand); flex-shrink: 0; }
.fo-ab__sticker {
  position: absolute; z-index: 3; right: 0; top: 4px;
  width: 96px; height: 96px; border-radius: 50%;
  background: var(--brand); color: #fff;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  font-size: 11.5px; line-height: 1.2; text-align: center; letter-spacing: .04em;
  transform: rotate(-11deg);
  box-shadow: 0 18px 34px -18px rgba(123,128,228,.8);
}
.fo-ab__sticker b {
  display: block; font-family: var(--font-display);
  font-weight: 800; font-size: 28px; line-height: 1; letter-spacing: -0.03em;
}

/* --- the words --- */
.fo-ab__body p { color: var(--muted); }
.fo-ab__body p b { color: var(--ink); font-weight: 600; }
.fo-ab__spark {
  background: var(--brand); -webkit-background-clip: text; background-clip: text;
  color: transparent;
}

/* --- lead line: one paragraph, not three --- */
.fo-ab__lead {
  font-size: clamp(16.5px, 1.55vw, 19px); line-height: 1.6;
  color: var(--muted); max-width: 46ch; margin: 18px 0 0;
}
.fo-ab__lead em { color: var(--ink); }

/* --- where AI fits: two columns, one shared readout --- */
/* lives inside the About column, so it reads as part of the writing
   rather than a card parked underneath it */
.fo-fits {
  margin-top: 30px; padding-top: 26px;
  border-top: 1px solid var(--line-2);
}
.fo-fits__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; margin-bottom: 20px;
}
.fo-fits__head h3 { margin: 0; font-size: clamp(18px, 1.9vw, 22px); }
.fo-fits__hint { font-size: 12.5px; color: var(--faint); }

.fo-fits__grid {
  display: grid; grid-template-columns: 1fr auto 1fr;
  gap: clamp(14px, 1.8vw, 26px); align-items: start;
}
.fo-fits__rule {
  width: 1px; align-self: stretch; min-height: 100%;
  background: linear-gradient(180deg, transparent, var(--line), transparent);
}
.fo-fits__col { display: flex; flex-direction: column; align-items: flex-start; gap: 9px; }
.fo-fits__label {
  font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 5px;
}

.fo-fit {
  --dot: var(--periwinkle);
  position: relative; display: inline-flex; align-items: center; gap: 10px;
  border: 1px solid var(--line-2); background: var(--bg-white);
  border-radius: var(--r-pill); padding: 8px 15px 8px 13px;
  font-family: inherit; font-size: 13.5px; color: var(--ink);
  cursor: pointer; text-align: left;
  transition: transform .35s cubic-bezier(.16,1,.3,1), border-color .3s ease, box-shadow .3s ease;
}
.fo-fit::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: var(--dot); flex-shrink: 0;
  transition: transform .35s cubic-bezier(.16,1,.3,1);
}
.fo-fit:hover, .fo-fit.is-on {
  transform: translateX(5px);
  border-color: var(--dot);
  box-shadow: 0 10px 24px -16px rgb(var(--ink-rgb) / .55);
}
.fo-fit:hover::before, .fo-fit.is-on::before { transform: scale(1.5); }
.fo-fits__col--me .fo-fit { --dot: var(--coral); }

.fo-fits__note {
  margin: 22px 0 0; padding-top: 18px;
  border-top: 1px solid var(--line-2);
  font-size: 14.5px; line-height: 1.55; color: var(--muted);
  min-height: 3.2em;
}
.fo-fits__note b { color: var(--ink); font-weight: 600; }

/* --- the status strip --- */
.fo-ab__now {
  margin-top: clamp(34px, 5vw, 56px);
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 15px 22px; border-radius: var(--r-pill);
  background: var(--black); color: var(--on-dark-2); font-size: 14px;
}
.fo-ab__now b { color: var(--on-dark); font-weight: 600; }
.fo-ab__now a { margin-left: auto; color: var(--on-dark); font-size: 13.5px; white-space: nowrap; }
.fo-ab__now a:hover { opacity: .72; }
.fo-ab__dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--coral); flex-shrink: 0;
  box-shadow: 0 0 0 0 rgba(251,139,113,.65);
  animation: fo-pulse 2.4s infinite;
}
@keyframes fo-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(251,139,113,.6); }
  70%  { box-shadow: 0 0 0 11px rgba(251,139,113,0); }
  100% { box-shadow: 0 0 0 0 rgba(251,139,113,0); }
}

@media (max-width: 860px) {
  .fo-ab { grid-template-columns: 1fr; gap: 38px; }
  .fo-ab__art { max-width: 420px; }
  .fo-ab__now a { margin-left: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .fo-ab__dot { animation: none; }
}

/* ============================================================
   6. SPLIT FEATURE (about)
   ============================================================ */
.fo-split { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: center; }
.fo-split p { color: var(--muted); }
.fo-split p b { color: var(--ink); font-weight: 600; }
.fo-split__media {
  border-radius: var(--r-md); min-height: 340px;
  background: var(--tint, var(--tint-2));
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.fo-slot {
  font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--faint);
  border: 1px dashed var(--line); border-radius: var(--r-pill);
  padding: 9px 16px; background: rgb(var(--paper-rgb) / .55);
}
.fo-taglist { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 20px; }
.fo-taglist span {
  font-size: 13px; color: var(--muted);
  background: var(--bg-raise); border: 1px solid var(--line-2);
  padding: 8px 14px; border-radius: var(--r-pill);
}

/* ============================================================
   7. WRITING
   ============================================================ */
.fo-posts { display: flex; flex-direction: column; }
.fo-post {
  display: grid; grid-template-columns: 120px 1fr auto;
  align-items: baseline; gap: 20px; padding: 22px 6px;
  border-top: 1px solid var(--line-2);
  transition: padding-left .3s cubic-bezier(.2,.8,.2,1);
}
.fo-posts .fo-post:last-child { border-bottom: 1px solid var(--line-2); }
.fo-post:hover { padding-left: 16px; }
.fo-post__date { font-size: 13px; color: var(--faint); }
.fo-post__title { font-size: 17px; font-weight: 500; transition: color .25s ease; }
.fo-post:hover .fo-post__title, .fo-post:hover .fo-post__go { color: var(--periwinkle); }
.fo-post__go { font-size: 13px; color: var(--faint); white-space: nowrap; }

/* ============================================================
   8. VOICES — a deck you drag, fling and cycle through
   ============================================================ */
.fo-voices__head {
  display: flex; justify-content: space-between; align-items: flex-end;
  gap: 24px; flex-wrap: wrap; margin-bottom: 30px;
}
.fo-voices__hint {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 13px; color: var(--muted);
  background: var(--bg-raise); border: 1px solid var(--line-2);
  padding: 9px 16px; border-radius: var(--r-pill);
}
.fo-voices__hint i {
  width: 22px; height: 22px; border-radius: 50%; background: var(--brand);
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff; font-size: 11px; flex-shrink: 0;
}

.fo-deckwrap {
  display: grid; grid-template-columns: 1fr auto;
  gap: 40px; align-items: center;
}

/* the stack */
.fo-vdeck {
  position: relative;
  height: 340px;
  margin-bottom: 56px;               /* room for the fanned cards underneath */
  touch-action: pan-y;               /* let vertical page-scroll through */
}
.fo-vcard {
  position: absolute; inset: 0; margin: 0;
  background: var(--bg-white);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  padding: clamp(26px, 3.4vw, 42px);
  display: flex; flex-direction: column; justify-content: space-between;
  box-shadow: 0 26px 50px -34px rgba(13,13,16,.45);
  cursor: grab;
  user-select: none;
  will-change: transform;
  transition: transform .6s cubic-bezier(.16,1,.3,1),
              opacity .5s ease, box-shadow .4s ease;
}
.fo-vcard.is-dragging { cursor: grabbing; transition: none; }
.fo-vcard.is-front { box-shadow: 0 34px 64px -32px rgba(13,13,16,.55); }
.fo-vcard:not(.is-front) { cursor: default; pointer-events: none; }

/* --- each card wears one colour from the logo, plus black and white ---
   Colours are set on every card, not just the front one, so the stack
   reads as a deck rather than a pile of white rectangles. */
.fo-vcard {
  --card-bg: var(--bg-white);
  --card-fg: var(--ink);
  --card-fg-2: var(--faint);
  --card-line: var(--line-2);
  --card-grid: rgb(var(--ink-rgb) / .05);
  --card-mark: var(--brand);
  --card-av: var(--brand);
  background: var(--card-bg);
  border-color: var(--card-line);
  color: var(--card-fg);
}
.fo-vcard--ink {
  --card-bg: var(--black); --card-fg: var(--on-dark); --card-fg-2: var(--on-dark-3);
  --card-line: var(--inv-line); --card-grid: rgba(244,244,246,.055);
  --card-mark: var(--brand); --card-av: var(--brand);
}
.fo-vcard--peri {
  --card-bg: var(--periwinkle); --card-fg: #0d0d10; --card-fg-2: rgb(var(--ink-rgb) / .60);
  --card-line: transparent; --card-grid: rgb(var(--ink-rgb) / .06);
  --card-mark: rgba(255,255,255,.62); --card-av: var(--black);
}
.fo-vcard--mauve {
  --card-bg: var(--mauve); --card-fg: #0d0d10; --card-fg-2: rgb(var(--ink-rgb) / .60);
  --card-line: transparent; --card-grid: rgb(var(--ink-rgb) / .06);
  --card-mark: rgba(255,255,255,.66); --card-av: var(--black);
}
.fo-vcard--coral {
  --card-bg: var(--coral); --card-fg: #0d0d10; --card-fg-2: rgb(var(--ink-rgb) / .60);
  --card-line: transparent; --card-grid: rgb(var(--ink-rgb) / .06);
  --card-mark: rgba(255,255,255,.7); --card-av: var(--black);
}
.fo-vcard--paper {
  --card-bg: var(--bg-white); --card-fg: var(--ink); --card-fg-2: var(--faint);
  --card-line: var(--line); --card-grid: rgb(var(--ink-rgb) / .045);
  --card-mark: var(--mauve); --card-av: var(--mauve);
}

.fo-vcard::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  pointer-events: none;
  background-image:
    linear-gradient(to right, var(--card-grid) 1px, transparent 1px),
    linear-gradient(to bottom, var(--card-grid) 1px, transparent 1px);
  background-size: 42px 42px;
  mask-image: radial-gradient(110% 90% at 18% 16%, #000 18%, transparent 74%);
  -webkit-mask-image: radial-gradient(110% 90% at 18% 16%, #000 18%, transparent 74%);
}
.fo-vcard > * { position: relative; z-index: 1; }

.fo-vmark {
  font-family: var(--font-serif); font-style: italic; font-weight: 600;
  font-size: clamp(64px, 8vw, 104px); line-height: .7;
  background: var(--card-mark); -webkit-background-clip: text; background-clip: text;
  color: transparent; height: .42em; display: block;
}
.fo-vcard blockquote {
  margin: 0; font-family: var(--font-serif); font-style: italic; font-weight: 400;
  font-size: clamp(19px, 2.2vw, 28px); line-height: 1.34; letter-spacing: -0.004em;
  color: var(--card-fg);
}
.fo-vfoot { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.fo-vwho { display: flex; align-items: center; gap: 12px; }
.fo-vav {
  width: 42px; height: 42px; border-radius: 50%;
  background: var(--card-av); flex-shrink: 0;
}
.fo-vname b { display: block; font-size: 14.5px; color: var(--card-fg); }
.fo-vname span { font-size: 12.5px; color: var(--card-fg-2); }
.fo-vcount { font-size: 12px; letter-spacing: .14em; color: var(--card-fg-2); }

/* side rail of people */
.fo-vrail { display: flex; flex-direction: column; gap: 12px; }
.fo-vpick {
  display: flex; align-items: center; gap: 10px;
  background: none; border: 0; padding: 5px; cursor: pointer;
  font-family: inherit; text-align: left;
  border-radius: var(--r-pill);
  opacity: .42; transition: opacity .3s ease, transform .3s ease;
}
.fo-vpick:hover { opacity: .8; transform: translateX(3px); }
.fo-vpick.is-on { opacity: 1; }
.fo-vpick i {
  width: 34px; height: 34px; border-radius: 50%; background: var(--pick, var(--brand));
  flex-shrink: 0; position: relative;
}
/* dots mirror the colour of the card they pull up */
.fo-vpick:nth-child(1) { --pick: var(--black); }
.fo-vpick:nth-child(2) { --pick: var(--periwinkle); }
.fo-vpick:nth-child(3) { --pick: var(--mauve); }
.fo-vpick:nth-child(4) { --pick: var(--coral); }
.fo-vpick.is-on i::after {
  content: ""; position: absolute; inset: -4px;
  border-radius: 50%; border: 1.5px solid var(--ink);
}
.fo-vpick span { font-size: 13px; color: var(--ink); white-space: nowrap; }

.fo-note { font-size: 13px; color: var(--faint); margin: 26px 0 0; }

@media (max-width: 860px) {
  .fo-deckwrap { grid-template-columns: 1fr; gap: 26px; }
  .fo-vrail { flex-direction: row; flex-wrap: wrap; }
  .fo-vpick span { display: none; }
  .fo-vdeck { height: 380px; }
}

/* ============================================================
   9. ELSEWHERE — marquee columns
   ============================================================ */
.fo-elsewhere { padding: clamp(48px, 7vw, 84px) 0; overflow: hidden; }
.fo-cols {
  display: flex; gap: 18px; padding: 0 var(--edge); height: 560px;
  mask-image: linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent);
}
.fo-col { flex: 1; min-width: 0; overflow: hidden; }
.fo-col__track { display: flex; flex-direction: column; gap: 18px; animation: fo-up 30s linear infinite; }
.fo-col:nth-child(2) .fo-col__track { animation-duration: 38s; animation-direction: reverse; }
.fo-col:nth-child(3) .fo-col__track { animation-duration: 34s; }
.fo-col:nth-child(4) .fo-col__track { animation-duration: 42s; animation-direction: reverse; }
.fo-elsewhere:hover .fo-col__track { animation-play-state: paused; }
@keyframes fo-up { from { transform: translateY(0); } to { transform: translateY(-50%); } }

.fo-scard {
  border-radius: var(--r-sm); border: 1px solid var(--line-2);
  background: var(--bg-white); padding: 12px;
  display: flex; flex-direction: column; gap: 11px;
}
.fo-scard__art { aspect-ratio: 9 / 13; border-radius: 10px; background: var(--art, var(--tint-1)); }
.fo-scard__who { display: flex; align-items: center; gap: 9px; }
.fo-scard__who .fo-av { width: 24px; height: 24px; }
.fo-scard__who b { font-size: 12.5px; }
.fo-scard__who span { font-size: 11.5px; color: var(--faint); }

/* ============================================================
   10. AI
   ============================================================ */
.fo-ai { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.fo-ai__item { background: var(--bg-raise); border: 1px solid var(--line-2); border-radius: var(--r-sm); padding: 24px; }
.fo-ai__n { font-size: 12px; color: var(--faint); margin-bottom: 14px; display: block; }
.fo-ai__item b { display: block; font-family: var(--font-display); font-size: 17px; margin-bottom: 8px; }
.fo-ai__item p { margin: 0; font-size: 14.5px; color: var(--muted); }

/* ============================================================
   11. CONTACT + FOOTER
   ============================================================ */
.fo-contact {
  background: var(--black); color: var(--on-dark);
  border-radius: var(--r-lg);
  padding: clamp(40px, 7vw, 84px) clamp(24px, 5vw, 64px);
  text-align: center;
}
.fo-contact h2 { font-size: clamp(28px, 4.4vw, 46px); margin: 0 0 14px; }
.fo-contact p { color: var(--on-dark-3); max-width: 54ch; margin: 0 auto 28px; }
.fo-contact__cta { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

/* toast */
.fo-toast {
  position: fixed; z-index: 999; left: 50%; bottom: 28px;
  transform: translate(-50%, 16px);
  background: var(--ink); color: var(--on-dark);
  padding: 12px 22px; border-radius: var(--r-pill); font-size: 14px;
  opacity: 0; pointer-events: none;
  transition: opacity .28s ease, transform .28s ease;
}
.fo-toast.is-on { opacity: 1; transform: translate(-50%, 0); }

/* reveal */
.fo-rev { opacity: 0; transform: translateY(20px); transition: opacity .7s cubic-bezier(.2,.7,.2,1), transform .7s cubic-bezier(.2,.7,.2,1); }
.fo-rev.is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .fo-rev { opacity: 1; transform: none; transition: none; }
  .fo-col__track { animation: none; }
  html { scroll-behavior: auto; }
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 940px) {
  .fo-nav__links { display: none; }
  .fo-burger { display: block; }
  .fo-nav__actions .fo-btn--ghost { display: none; }
  .fo-grid, .fo-quotes, .fo-split { grid-template-columns: 1fr; }
  .fo-ai { grid-template-columns: 1fr; }
  .fo-cols { height: 440px; }
  .fo-col:nth-child(4) { display: none; }
}
@media (max-width: 680px) {
  .fo-hero { height: 170vh; }
  .fo-hero__chip { display: none; }
  .fo-cols { height: 380px; }
  .fo-col:nth-child(3) { display: none; }
  .fo-post { grid-template-columns: 1fr; gap: 6px; }
  .fo-post__go { display: none; }
  .fo-numbers { padding: 40px 24px; }
}

/* ============================================================
   BRAND — logo-derived accents on the black surfaces
   ============================================================ */

/* faint grid on black panels, echoing the logo lockup */
.fo-numbers, .fo-contact { position: relative; overflow: hidden; }
.fo-numbers::before, .fo-contact::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(244,244,246,.055) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(244,244,246,.055) 1px, transparent 1px);
  background-size: 46px 46px;
  mask-image: radial-gradient(120% 100% at 50% 50%, #000 30%, transparent 78%);
  -webkit-mask-image: radial-gradient(120% 100% at 50% 50%, #000 30%, transparent 78%);
}
/* the tag is deliberately excluded — it must keep `position: absolute` */
.fo-numbers > *:not(.fo-numbers__tag),
.fo-contact > * { position: relative; z-index: 1; }

/* grayscale toggle reads as the brand dot */
.fo-icon-btn { position: relative; }
.fo-icon-btn::after {
  content: ""; position: absolute; inset: -1px;
  border-radius: 50%; padding: 1px;
  background: var(--brand);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: 0; transition: opacity .25s ease;
}
.fo-icon-btn:hover::after { opacity: 1; }

/* availability dot in the hero chip */
.fo-hero__chip .av { background: var(--brand); }

/* selection */
::selection { background: var(--coral); color: #fff; }

/* focus ring */
:where(a, button):focus-visible {
  outline: 2px solid var(--periwinkle);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ============================================================
   PROJECT TREATMENTS — each panel shows its work differently.
   Wireframes below stand in for real screenshots; swap the
   .fo-scr blocks for <img>/<video> when assets arrive.
   ============================================================ */

/* --- shared fake-screen primitive --- */
.fo-scr {
  background: var(--panel-2); border: 1px solid rgb(var(--ink-rgb) / .09);
  border-radius: 10px; overflow: hidden;
  display: flex; flex-direction: column;
  box-shadow: 0 18px 40px -26px rgba(13,13,16,.45);
}
.fo-scr__bar {
  height: 26px; background: var(--panel-bar); flex-shrink: 0;
  border-bottom: 1px solid rgb(var(--ink-rgb) / .07);
  display: flex; align-items: center; gap: 5px; padding: 0 10px;
}
.fo-scr__bar i { width: 7px; height: 7px; border-radius: 50%; background: rgb(var(--ink-rgb) / .16); }
.fo-scr__body { flex: 1; padding: 14px; display: flex; gap: 10px; min-height: 0; }
.fo-scr__side { width: 24%; display: flex; flex-direction: column; gap: 7px; }
.fo-scr__main { flex: 1; display: flex; flex-direction: column; gap: 9px; min-height: 0; }
.fo-scr i.l { display: block; height: 9px; border-radius: 4px; background: rgb(var(--ink-rgb) / .10); flex-shrink: 0; }
.fo-scr i.l.sm { width: 55%; }
.fo-scr i.l.xs { width: 34%; }
.fo-scr .blk { flex: 1; border-radius: 8px; background: rgb(var(--ink-rgb) / .055); }
.fo-scr .cht {
  flex: 1; border-radius: 8px; position: relative; overflow: hidden;
  background: linear-gradient(180deg, rgba(123,128,228,.20), rgba(251,139,113,.14));
}
.fo-scr .cht::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 62%;
  background:
    linear-gradient(to top, rgb(var(--paper-rgb) / .55), transparent),
    repeating-linear-gradient(90deg, rgb(var(--ink-rgb) / .10) 0 2px, transparent 2px 26px);
}
.fo-scr .rw { display: flex; gap: 8px; flex-shrink: 0; }
.fo-scr .rw .t { flex: 1; height: 34px; border-radius: 7px; background: rgb(var(--ink-rgb) / .05); }
.fo-scr .pil { width: 74px; height: 22px; border-radius: 999px; background: var(--brand); opacity: .85; flex-shrink: 0; }

.fo-phone {
  width: clamp(140px, 13vw, 186px); border-radius: 22px; background: var(--panel-2);
  border: 1px solid rgb(var(--ink-rgb) / .10); padding: 12px 11px;
  display: flex; flex-direction: column; gap: 9px;
  box-shadow: 0 22px 44px -24px rgba(13,13,16,.5);
}
.fo-phone .notch { width: 46px; height: 5px; border-radius: 3px; background: rgb(var(--ink-rgb) / .14); margin: 0 auto 4px; }

/* media becomes a positioning context for each treatment */
.fo-proj__media { position: absolute; }
.fo-proj__media > .fo-slot { position: absolute; }

/* ---------- 01 · FILMSTRIP ---------- */
.fo-proj--strip .fo-rail {
  position: absolute; top: 12%; left: 0; height: 66%;
  display: flex; gap: 20px; padding-left: 44%;
  will-change: transform;
}
.fo-proj--strip .fo-rail .fo-scr { width: clamp(260px, 26vw, 360px); flex-shrink: 0; }

/* ---------- 02 · DEVICE CLUSTER ---------- */
.fo-proj--cluster .fo-cluster { position: absolute; inset: 0; }
.fo-proj--cluster .fo-scr.lap {
  position: absolute; left: 40%; top: 14%; width: 52%; height: 60%;
  transform: rotate(-1.2deg);
}
.fo-proj--cluster .fo-phone.p1 { position: absolute; left: 32%; top: 32%; transform: rotate(4deg); z-index: 2; }
.fo-proj--cluster .fo-phone.p2 { position: absolute; left: 60%; top: 48%; transform: rotate(-5deg); z-index: 3; }

/* ---------- 03 · BEFORE / AFTER ---------- */
.fo-proj--wipe .fo-pair { position: absolute; top: 12%; left: 40%; width: 55%; height: 68%; }
.fo-proj--wipe .fo-pair .fo-scr { position: absolute; inset: 0; }
.fo-proj--wipe .fo-after { clip-path: inset(0 0 0 var(--split, 50%)); }
.fo-proj--wipe .fo-before .fo-scr__body { filter: saturate(.12); }
.fo-proj--wipe .fo-before .cht { background: rgb(var(--ink-rgb) / .09); }
.fo-proj--wipe .fo-before .pil { background: rgb(var(--ink-rgb) / .22); }
.fo-proj--wipe .fo-handle {
  position: absolute; top: 0; bottom: 0; left: var(--split, 50%);
  width: 2px; background: var(--brand); z-index: 4; cursor: ew-resize;
}
.fo-proj--wipe .fo-handle::after {
  content: "⇄"; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%);
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--brand); color: #fff;
  display: flex; align-items: center; justify-content: center; font-size: 15px;
  box-shadow: 0 6px 18px -6px rgba(123,128,228,.9);
}
.fo-proj--wipe .fo-lbl {
  position: absolute; top: 10px; z-index: 5;
  font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase;
  background: rgb(var(--paper-rgb) / .92); border: 1px solid var(--line-2);
  padding: 5px 10px; border-radius: var(--r-pill); color: var(--muted);
}
.fo-proj--wipe .fo-lbl.b { left: 10px; }
.fo-proj--wipe .fo-lbl.a { right: 10px; }

/* ---------- 04 · FANNING STACK ---------- */
.fo-proj--fan .fo-deck { position: absolute; left: 44%; top: 15%; width: 47%; height: 62%; }
.fo-proj--fan .fo-deck .fo-scr {
  position: absolute; inset: 0;
  transform-origin: bottom center;
  transition: transform 1s cubic-bezier(.16,1,.3,1);
}

/* ---------- 05 · LIVE LOOP ---------- */
.fo-proj--loop .fo-frame { position: absolute; top: 12%; left: 40%; width: 55%; height: 68%; }
.fo-proj--loop .fo-frame .fo-scr { height: 100%; }
.fo-proj--loop .fo-cursor {
  position: absolute; width: 13px; height: 19px; z-index: 4; background: var(--ink);
  clip-path: polygon(0 0, 0 78%, 26% 60%, 46% 100%, 66% 88%, 46% 50%, 78% 48%);
}
.fo-proj--loop.is-live .fo-cursor { animation: fo-cursor 6s cubic-bezier(.5,0,.5,1) infinite; }
@keyframes fo-cursor {
  0%,22%  { left: 22%; top: 28%; }
  38%,56% { left: 62%; top: 44%; }
  74%     { left: 40%; top: 72%; }
  100%    { left: 22%; top: 28%; }
}
.fo-proj--loop .fo-pulse {
  position: absolute; z-index: 3; width: 44px; height: 44px; border-radius: 50%;
  border: 2px solid var(--periwinkle); opacity: 0;
}
.fo-proj--loop.is-live .fo-pulse { animation: fo-pulse 6s ease-out infinite; }
@keyframes fo-pulse {
  0%,20%  { opacity: 0; transform: scale(.4); left: 20%; top: 25%; }
  24%     { opacity: .8; transform: scale(1); }
  32%     { opacity: 0; transform: scale(1.5); }
  33%,54% { opacity: 0; left: 60%; top: 41%; transform: scale(.4); }
  58%     { opacity: .8; transform: scale(1); }
  66%     { opacity: 0; transform: scale(1.5); }
  100%    { opacity: 0; }
}
.fo-proj--loop .fo-rec {
  position: absolute; z-index: 6; top: calc(var(--pt) + var(--pad)); left: 50%;
  transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  background: rgb(var(--paper-rgb) / .92); border: 1px solid var(--line-2);
  padding: 6px 13px; border-radius: var(--r-pill); color: var(--muted);
}
.fo-proj--loop .fo-rec i { width: 7px; height: 7px; border-radius: 50%; background: var(--coral); }
.fo-proj--loop.is-live .fo-rec i { animation: fo-rec 1.4s ease-in-out infinite; }
@keyframes fo-rec { 0%,100% { opacity: 1; } 50% { opacity: .25; } }

/* ---------- 06 · UNDER NDA ---------- */
.fo-proj--nda .fo-shot { position: absolute; top: 12%; left: 42%; width: 57%; height: 68%; }
.fo-proj--nda .fo-shot .fo-scr__body { filter: blur(5px); }
.fo-proj--nda .fo-veil {
  position: absolute; inset: 0; z-index: 3;
  background: linear-gradient(90deg, var(--panel) 32%, rgb(var(--paper-rgb) / 0) 74%);
}
.fo-proj--nda .fo-lock {
  position: absolute; z-index: 4;
  left: calc(var(--px) + var(--pad));
  bottom: calc(var(--pb) + var(--pad) + 128px);
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--muted);
  background: var(--bg-raise); border: 1px solid var(--line-2);
  padding: 8px 15px; border-radius: var(--r-pill);
}

@media (max-width: 1180px) {
  .fo-proj--strip .fo-rail,
  .fo-proj--cluster .fo-cluster,
  .fo-proj--wipe .fo-pair,
  .fo-proj--fan .fo-deck,
  .fo-proj--loop .fo-frame,
  .fo-proj--nda .fo-shot { position: absolute; inset: 10% 8%; width: auto; height: auto; left: 8%; top: 10%; }
  .fo-proj--strip .fo-rail { padding-left: 0; inset: 12% auto auto 0; height: 70%; }
  .fo-proj--nda .fo-lock { position: static; margin: 0 var(--edge) 10px; }
  .fo-proj--nda .fo-veil { background: linear-gradient(180deg, rgb(var(--paper-rgb) / .2), var(--panel)); }
}

/* ============================================================
   TABLET — the gap between the 940px collapse and phone rules.
   Everything below is stacking, not restyling.
   ============================================================ */
@media (max-width: 1024px) {
  .fo-fits__grid { gap: 22px; }
  .fo-footer__top { gap: 34px; }
  .fo-footer__nav { gap: 20px; }
}

@media (max-width: 940px) {
  /* the about grid was still two columns here, squeezing the portrait */
  .fo-ab { grid-template-columns: 1fr; gap: 34px; }
  .fo-ab__art { max-width: 420px; }
  .fo-footer__top { grid-template-columns: 1fr; }
  .fo-footer__mark { font-size: clamp(30px, 6vw, 44px); }
}

@media (max-width: 1120px) {
  .fo-fits__grid { grid-template-columns: 1fr; gap: 24px; }
  .fo-fits__rule {
    width: auto; height: 1px; min-height: 0; align-self: auto;
    background: linear-gradient(90deg, transparent, var(--line), transparent);
  }
  .fo-fits__note { min-height: 0; }
  /* three big figures side by side stop fitting well before phone width */
  .fo-numbers__grid { grid-template-columns: 1fr; gap: 4px; }
  .fo-numbers__grid .fo-stat + .fo-stat {
    border-left: 0;
    border-top: 1px solid rgba(244,244,246,.14);
    padding-top: 24px; margin-top: 20px;
  }
  .fo-stat > span { max-width: none; }
  .fo-footer__nav { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 26px 20px; }
}

@media (max-width: 560px) {
  .fo-footer__bottom { flex-direction: column; align-items: flex-start; gap: 14px; }
  .fo-footer__nav { grid-template-columns: 1fr 1fr; }
  .fo-fits__head { margin-bottom: 20px; }
}

/* labelled placeholder slots in Elsewhere, so the intent is obvious */
.fo-scard__art { position: relative; display: flex; align-items: center; justify-content: center; }
.fo-scard__tag {
  font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--faint); border: 1px dashed var(--line);
  padding: 5px 10px; border-radius: var(--r-pill);
}

/* ============================================================
   INNER PAGES — no hero, so the nav needs no reveal and the
   page needs a head of its own
   ============================================================ */
body.fo-inner .fo-nav { opacity: 1; visibility: visible; transform: translateX(-50%); }
.fo-phead { padding: clamp(120px, 15vh, 190px) 0 clamp(38px, 5vw, 62px); }
.fo-phead__h { font-size: clamp(38px, 6.6vw, 82px); margin: 14px 0 0; }
.fo-phead__sub {
  margin: 22px 0 0; max-width: 52ch;
  font-size: clamp(16px, 1.6vw, 19.5px); line-height: 1.6; color: var(--muted);
}
.fo-phead__sub em { color: var(--ink); }

/* the AI block at full page width rather than inside a column */
.fo-fits--page { border-top: 0; margin-top: 0; padding: clamp(26px, 3.2vw, 42px); border-radius: var(--r-md); background: var(--bg-raise); border: 1px solid var(--line-2); }
.fo-fits--page .fo-fits__head h2 { margin: 0; font-size: clamp(22px, 2.6vw, 32px); }
.fo-fits--page .fo-fit { font-size: 14.5px; padding: 9px 17px 9px 14px; }

/* how I work */
.fo-tenets { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(18px, 2.4vw, 32px); }
.fo-tenets li {
  position: relative; padding: 26px 24px 28px;
  background: var(--bg-white); border: 1px solid var(--line-2); border-radius: var(--r-sm);
}
.fo-tenets li::after {
  content: ""; position: absolute; left: 24px; right: 24px; top: 0; height: 2px;
  background: var(--brand); border-radius: 2px;
  transform: scaleX(0); transform-origin: left;
  transition: transform .55s cubic-bezier(.16,1,.3,1);
}
.fo-tenets li:hover::after { transform: scaleX(1); }
.fo-tenets__n { font-size: 11.5px; letter-spacing: .13em; color: var(--faint); }
.fo-tenets b { display: block; font-family: var(--font-display); font-weight: 700; font-size: 18px; letter-spacing: -.02em; margin: 12px 0 8px; }
.fo-tenets p { margin: 0; font-size: 14.5px; color: var(--muted); }

@media (max-width: 940px) { .fo-tenets { grid-template-columns: 1fr; } }

/* ============================================================
   CAREER TRAJECTORY — horizontal focus-carousel.
   Cards scale and fade by distance from a fixed centre playhead;
   the year behind changes as the nearest card passes it.
   ============================================================ */
.fo-tl {
  position: relative; overflow: hidden;
  background: var(--black); color: var(--on-dark);
  border: 1px solid var(--inv-line);
  border-radius: var(--r-lg);
  margin: 0 var(--edge) clamp(56px, 8vw, 100px);
  padding: clamp(44px, 6vw, 74px) 0 clamp(26px, 3vw, 40px);
}
.fo-tl__ghosts { position: absolute; inset: 0; pointer-events: none; overflow: hidden; z-index: 0; }
.fo-tl__ghost {
  position: absolute; top: 52%; left: 50%; transform: translate(-50%, -50%);
  font-family: var(--font-display); font-weight: 800; letter-spacing: -0.05em;
  font-size: clamp(150px, 26vw, 380px); line-height: 1;
  color: var(--on-dark); opacity: 0;
  transition: opacity .8s ease;
  white-space: nowrap;
}
.fo-tl__ghost.is-on { opacity: .06; }

.fo-tl__head {
  position: relative; z-index: 3;
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 8px;
}
.fo-tl__head h2 { margin: 0; font-size: clamp(24px, 3.2vw, 40px); }
.fo-tl__hint { font-size: 12.5px; color: var(--on-dark-3); }

.fo-tl__playhead {
  position: absolute; z-index: 2; left: 50%; width: 1px;
  top: clamp(112px, 14vw, 168px); bottom: clamp(64px, 7vw, 92px);
  background: linear-gradient(180deg, transparent, rgba(244,244,246,.22), transparent);
  pointer-events: none;
}

.fo-tl__track {
  position: relative; z-index: 3;
  display: flex; align-items: flex-start; gap: clamp(26px, 3.4vw, 52px);
  overflow-x: auto; overscroll-behavior-x: contain;
  padding: 26px 0 14px; cursor: grab;
  scrollbar-width: none; -ms-overflow-style: none;
  scroll-snap-type: x proximity;
}
.fo-tl__track::-webkit-scrollbar { display: none; }
.fo-tl__track.is-dragging { cursor: grabbing; scroll-snap-type: none; }
.fo-tl__track:focus-visible { outline: 2px solid var(--periwinkle); outline-offset: 4px; }
.fo-tl__spacer { flex: 0 0 44vw; }

.fo-tl__item {
  flex: 0 0 clamp(230px, 24vw, 290px);
  scroll-snap-align: center;
  display: flex; flex-direction: column; align-items: center; text-align: center;
  opacity: .28; transform: scale(.8);
  will-change: transform, opacity;
}
.fo-tl__date {
  font-size: 12px; font-weight: 600; letter-spacing: .1em;
  color: var(--coral); margin-bottom: 6px;
}
.fo-tl__title {
  font-family: var(--font-display); font-weight: 700; letter-spacing: -.02em;
  font-size: 19px; color: var(--on-dark); margin: 0 0 14px;
}
.fo-tl__card {
  width: 100%; text-align: left;
  background: rgba(244,244,246,.04);
  border: 1px solid rgba(244,244,246,.09);
  border-radius: var(--r-sm);
  padding: 14px; display: flex; flex-direction: column; gap: 12px;
}
.fo-tl__role {
  font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--on-dark-3);
}
.fo-tl__card p { margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--on-dark-2); }

.fo-tl__foot {
  position: relative; z-index: 3;
  display: flex; align-items: center; gap: 18px; margin-top: 12px;
}
.fo-tl__arrows { display: flex; gap: 8px; }
.fo-tl__arrow {
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid rgba(244,244,246,.24); background: transparent;
  color: var(--on-dark); font-size: 15px; cursor: pointer;
  transition: background .22s ease, border-color .22s ease, transform .22s ease;
}
.fo-tl__arrow:hover { background: rgba(244,244,246,.1); border-color: var(--on-dark); }
.fo-tl__arrow:active { transform: scale(.94); }
.fo-tl__bar { flex: 1; height: 2px; border-radius: 2px; background: rgba(244,244,246,.14); overflow: hidden; }
.fo-tl__bar span { display: block; height: 100%; width: 0; background: var(--brand); border-radius: 2px; }

@media (max-width: 680px) {
  .fo-tl { margin-left: 0; margin-right: 0; border-radius: 0; border-left: 0; border-right: 0; }
  .fo-tl__spacer { flex-basis: 32vw; }
}
@media (prefers-reduced-motion: reduce) {
  .fo-tl__item { transition: none; }
}

/* ============================================================
   FOOTER — a closing beat, not a link dump.
   Order: the ask (status + email), then the map (links), then
   the oversized wordmark cropped by the page edge, then admin.
   ============================================================ */
.fo-foot { padding: clamp(56px, 7vw, 90px) 0 26px; }

/* --- 1. the ask: the address, at size, as a real target ---
   Letters lift and warm toward the pointer, and a soft wash tracks it
   behind them, so the whole line reads as something you touch. --- */
.fo-mail__eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--font-body); font-weight: 500;
  font-size: 10px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 16px;
}
.fo-mail__eyebrow::before { content: ""; width: 24px; height: 2px; background: var(--brand); }

.fo-bigmail {
  position: relative; display: block; width: 100%; text-align: left;
  background: none; border: 0; padding: 4px 0 0; cursor: pointer;
  font-family: var(--font-display); font-weight: 800; letter-spacing: -0.04em;
  font-size: clamp(26px, 6.7vw, 84px); line-height: 1.08;
  color: var(--ink);
}
/* the wash follows the pointer and only exists while you're over the line */
.fo-bigmail::before {
  content: ""; position: absolute; z-index: 0; pointer-events: none;
  left: var(--mx, 50%); top: var(--my, 50%);
  width: 460px; height: 460px; border-radius: 50%;
  transform: translate(-50%, -50%) scale(var(--glow, 0));
  background: radial-gradient(circle, rgb(var(--ink-rgb) / .11), transparent 66%);
  transition: transform .45s cubic-bezier(.16, 1, .3, 1);
}
.fo-bigmail__t {
  position: relative; z-index: 1; display: inline-block;
  background-image: linear-gradient(var(--coral), var(--coral));
  background-repeat: no-repeat; background-position: 0 100%; background-size: 0% 3px;
  transition: background-size .55s cubic-bezier(.16, 1, .3, 1);
}
.fo-bigmail:hover .fo-bigmail__t { background-size: 100% 3px; }
/* one span per character; --l is 0..1, set from the pointer's distance */
.fo-bigmail__ch {
  display: inline-block; will-change: transform;
  transform: translateY(calc(var(--l, 0) * -14px));
  color: color-mix(in srgb, var(--coral) calc(var(--l, 0) * 100%), var(--ink));
  transition: transform .45s cubic-bezier(.16, 1, .3, 1), color .45s ease;
}
.fo-bigmail__flash {
  position: absolute; inset: 4px auto auto 0; z-index: 2;
  color: var(--coral); opacity: 0; transform: translateY(8px);
  pointer-events: none;
  transition: opacity .25s ease, transform .4s cubic-bezier(.16, 1, .3, 1);
}
.fo-bigmail.is-copied .fo-bigmail__flash { opacity: 1; transform: none; }
.fo-bigmail.is-copied .fo-bigmail__t { opacity: 0; }
.fo-bigmail.is-copied .fo-bigmail__hint { opacity: 0; }
.fo-bigmail__hint {
  display: block; margin-top: 14px;
  font-family: var(--font-body); font-weight: 400; letter-spacing: 0.14em;
  font-size: 10px; text-transform: uppercase; color: var(--faint);
  opacity: 0; transform: translateY(-4px);
  transition: opacity .3s ease, transform .35s cubic-bezier(.16, 1, .3, 1);
}
.fo-bigmail:hover .fo-bigmail__hint { opacity: 1; transform: none; }

.fo-mail__acts {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  margin-top: clamp(22px, 2.6vw, 32px);
}
.fo-mail__act {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 12px 22px; border-radius: 999px;
  border: 1px solid var(--line); color: var(--ink);
  font-size: 13.5px; font-weight: 500; text-decoration: none;
  transition: background .35s ease, border-color .35s ease, color .35s ease;
}
.fo-mail__act i { font-style: normal; transition: transform .35s cubic-bezier(.16, 1, .3, 1); }
.fo-mail__act:hover { background: var(--brand); border-color: transparent; color: #fff; }
.fo-mail__act:hover i { transform: translateX(5px); }
.fo-mail__note { font-size: 12.5px; color: var(--faint); }

@media (prefers-reduced-motion: reduce) {
  .fo-bigmail__ch { transform: none; }
  .fo-bigmail::before { display: none; }
}

.fo-foot__ask { padding: clamp(30px, 4vw, 48px) 0 clamp(34px, 4.4vw, 54px); border-bottom: 1px solid var(--line-2); }

/* --- 2. the marquee band, and the ruled index --- */
.fo-band {
  display: block; overflow: hidden;
  margin: clamp(28px, 3.6vw, 44px) 0 0;
  padding: clamp(14px, 1.8vw, 22px) 0;
  border-top: 1px solid var(--line-2); border-bottom: 1px solid var(--line-2);
  color: inherit;
}
.fo-band__row {
  display: flex; align-items: center; gap: clamp(20px, 3vw, 44px);
  width: max-content;
  animation: fo-marq 28s linear infinite;
  font-family: var(--font-display); font-weight: 800; letter-spacing: -.03em;
  font-size: clamp(22px, 3.4vw, 44px);
}
.fo-band:hover .fo-band__row { animation-play-state: paused; }
.fo-band__row i {
  font-style: normal; font-size: .3em;
  background: var(--brand); -webkit-background-clip: text; background-clip: text; color: transparent;
}
.fo-band:hover .fo-band__row > span {
  background: var(--brand); -webkit-background-clip: text; background-clip: text; color: transparent;
}

.fo-index {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(20px, 3vw, 40px);
  padding: clamp(32px, 4vw, 50px) 0 clamp(10px, 1.5vw, 18px);
}
.fo-index__col { display: flex; flex-direction: column; }
.fo-index__h {
  font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--faint); padding-bottom: 10px; border-bottom: 1px solid var(--line);
}
.fo-index__col a {
  display: grid; grid-template-columns: 1fr auto 14px;
  gap: 10px; align-items: baseline;
  padding: 11px 0; border-bottom: 1px solid var(--line-2);
  transition: padding-left .35s cubic-bezier(.16,1,.3,1), color .22s ease;
}
.fo-index__col a b { font-size: 14.5px; font-weight: 500; color: var(--ink); }
.fo-index__col a span { font-size: 12px; color: var(--faint); }
.fo-index__col a i {
  font-style: normal; font-size: 12px; justify-self: end; color: var(--faint);
  opacity: 0; transform: translateX(-4px);
  transition: opacity .25s ease, transform .3s cubic-bezier(.16,1,.3,1);
}
.fo-index__col a:hover { padding-left: 8px; }
.fo-index__col a:hover i { opacity: 1; transform: none; color: var(--coral); }
.fo-index__meta p { margin: 14px 0 14px; font-size: 14px; line-height: 1.6; color: var(--muted); }
.fo-foot__clock {
  display: inline-flex; align-items: center; gap: 7px; align-self: flex-start;
  font-size: 12.5px; color: var(--faint);
  padding: 7px 13px; border-radius: var(--r-pill);
  border: 1px solid var(--line-2); background: var(--bg-raise);
}
.fo-foot__clock i { width: 6px; height: 6px; border-radius: 50%; background: var(--periwinkle); }
.fo-foot__clock b { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }

/* --- 3. the signature: every letter answers the cursor --- */
.fo-foot__markwrap {
  overflow: hidden; margin: clamp(6px, 1.5vw, 18px) 0 clamp(18px, 2.5vw, 30px);
  line-height: .78;
}
.fo-foot__mark {
  display: block; white-space: nowrap;
  font-size: clamp(52px, 13.4vw, 196px);
  letter-spacing: -.045em;
  color: transparent;
  -webkit-text-stroke: 1px rgb(var(--ink-rgb) / .26);
}
.fo-foot__mark i {
  display: inline-block; font-style: normal;
  will-change: transform;
  transition: transform .45s cubic-bezier(.16,1,.3,1),
              color .35s ease, -webkit-text-stroke-color .35s ease;
}
/* the letter under the cursor fills with the brand and lifts; its neighbours
   follow at a decaying amount, so the whole word ripples */
.fo-foot__mark i.is-lit {
  color: transparent;
  background: var(--brand);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-stroke-color: transparent;
}
@media (prefers-reduced-motion: reduce) {
  .fo-foot__mark i { transition: none; transform: none !important; }
}

/* --- 4. admin --- */
.fo-foot__base {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; padding-top: 22px;
  border-top: 1px solid var(--line-2);
  font-size: 12.5px; color: var(--faint);
}
.fo-foot__totop {
  display: inline-flex; align-items: center; gap: 7px;
  background: none; border: 1px solid var(--line); border-radius: var(--r-pill);
  padding: 8px 15px; cursor: pointer;
  font-family: inherit; font-size: 12.5px; color: var(--muted);
  transition: border-color .25s ease, color .25s ease;
}
.fo-foot__totop i { font-style: normal; transition: transform .35s cubic-bezier(.16,1,.3,1); }
.fo-foot__totop:hover { border-color: var(--ink); color: var(--ink); }
.fo-foot__totop:hover i { transform: translateY(-3px); }

@media (max-width: 640px) { .fo-index { grid-template-columns: 1fr; gap: 30px 20px; } }
@media (max-width: 560px) {
  .fo-foot__base { flex-direction: column; align-items: flex-start; gap: 14px; }
  .fo-foot__cta { align-items: flex-start; }
}
@media (prefers-reduced-motion: reduce) { .fo-foot__status i { animation: none; } }

/* ============================================================
   BENTO — the details, four coloured cards.
   Palette stays on the logo (coral / periwinkle / black / mauve)
   rather than introducing the amber from the reference.
   ============================================================ */
.fo-bento {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(14px, 1.6vw, 22px);
  align-items: start;
}
.fo-bcard {
  --cf: #0d0d10;                       /* card foreground */
  --cf-2: rgba(13,13,16,.62);
  --cl: rgba(13,13,16,.14);            /* card hairline */
  position: relative; overflow: hidden;
  border-radius: var(--r-md);
  padding: clamp(24px, 2.6vw, 34px);
  background: var(--cb); color: var(--cf);
  display: flex; flex-direction: column;
  min-height: 320px;
}
/* the faint plotting grid at the top of each card, as in the reference */
.fo-bcard::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 46%;
  pointer-events: none; opacity: .5;
  background-image:
    linear-gradient(to right, var(--cl) 1px, transparent 1px),
    linear-gradient(to bottom, var(--cl) 1px, transparent 1px);
  background-size: 34px 34px;
  mask-image: linear-gradient(#000, transparent);
  -webkit-mask-image: linear-gradient(#000, transparent);
}
.fo-bcard > * { position: relative; z-index: 1; }
.fo-bcard--coral { --cb: var(--coral); }
.fo-bcard--peri  { --cb: var(--periwinkle); }
.fo-bcard--mauve { --cb: var(--mauve); }
.fo-bcard--ink {
  --cb: var(--black); --cf: var(--on-dark); --cf-2: var(--on-dark-2);
  --cl: rgba(244,244,246,.14);
  border: 1px solid var(--inv-line);
}

.fo-bcard__head { display: flex; align-items: baseline; gap: 14px; margin-bottom: 22px; }
.fo-bcard__head h2 { margin: 0; font-size: clamp(22px, 2.5vw, 30px); font-style: normal; }
.fo-bcard__badge { font-size: 12.5px; color: var(--cf-2); }
.fo-bcard__sub { margin: -12px 0 20px; font-size: 14px; color: var(--cf-2); max-width: 38ch; }
.fo-bcard__foot { margin-top: auto; padding-top: 24px; }
.fo-bcard__label { display: block; font-size: 13px; color: var(--cf-2); margin-bottom: 12px; }

/* experience list */
.fo-xp { list-style: none; margin: 0; padding: 0 0 0 22px; position: relative; }
.fo-xp::before { content: ""; position: absolute; left: 4px; top: 8px; bottom: 8px; width: 1px; background: var(--cl); }
.fo-xp li { position: relative; padding-bottom: 22px; }
.fo-xp li::before {
  content: ""; position: absolute; left: -22px; top: 7px;
  width: 9px; height: 9px; border-radius: 50%; background: var(--cf);
}
.fo-xp b { display: block; font-size: 16.5px; font-weight: 600; }
.fo-xp span { font-size: 13.5px; color: var(--cf-2); }

.fo-logos { display: flex; flex-wrap: wrap; gap: 8px; }
.fo-logos span {
  font-size: 12.5px; color: var(--cf-2);
  border: 1px solid var(--cl); border-radius: var(--r-pill);
  padding: 6px 12px;
}

/* connect */
.fo-links { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.fo-links a {
  display: flex; align-items: center; gap: 13px;
  padding: 9px 10px; margin-left: -10px; border-radius: var(--r-sm);
  font-size: 15px;
  transition: background .25s ease, transform .3s cubic-bezier(.16,1,.3,1);
}
.fo-links a:hover { background: rgba(255,255,255,.24); transform: translateX(4px); }
.fo-links i {
  width: 30px; height: 30px; border-radius: 8px; flex-shrink: 0;
  background: var(--cf); color: var(--cb);
  display: inline-flex; align-items: center; justify-content: center;
  font-style: normal; font-size: 13px; font-weight: 700;
}
.fo-hire { display: flex; align-items: center; gap: 14px; border-top: 1px solid var(--cl); }
.fo-hire__ico { font-size: 24px; }
.fo-hire b { display: block; font-size: 14.5px; }
.fo-hire__mail { font-size: 13.5px; color: var(--cf-2); }
.fo-hire__mail span { color: var(--cf); font-weight: 600; }
.fo-hire__mail:hover span { text-decoration: underline; }

/* skills marquee — two rows travelling opposite ways */
.fo-marq { display: flex; flex-direction: column; gap: 12px; margin: 0 -34px; overflow: hidden; }
.fo-marq__row { display: flex; gap: 12px; width: max-content; animation: fo-marq 34s linear infinite; }
.fo-marq__row--back { animation-direction: reverse; animation-duration: 40s; }
.fo-marq__row:nth-child(3) { animation-duration: 46s; }
.fo-marq:hover .fo-marq__row { animation-play-state: paused; }
.fo-marq__row span {
  white-space: nowrap; font-size: 14px; color: var(--cf);
  background: rgba(244,244,246,.08); border: 1px solid var(--cl);
  padding: 10px 18px; border-radius: var(--r-pill);
}
@keyframes fo-marq { from { transform: translateX(0); } to { transform: translateX(-50%); } }
/* a pill can be pointed at, and says what it means below */
.fo-marq__row span { cursor: default; transition: background .25s ease, color .25s ease, border-color .25s ease; }
.fo-marq__row span:hover,
.fo-marq__row span:focus-visible {
  background: rgb(var(--paper-rgb) / .14); color: #fff; outline: none;
}
#fo-skillnote { transition: opacity .25s ease, color .25s ease; }
#fo-skillnote.is-on { color: rgb(var(--paper-rgb) / .92); }
@media (prefers-reduced-motion: reduce) {
  .fo-marq__row { animation: none; }
  .fo-marq { margin: 0; flex-wrap: wrap; }
  .fo-marq__row { flex-wrap: wrap; width: auto; }
}

/* stacks */
.fo-stack { display: flex; flex-wrap: wrap; gap: 9px; }
.fo-stack span {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 13.5px; padding: 7px 14px 7px 7px;
  background: rgba(255,255,255,.3); border: 1px solid var(--cl);
  border-radius: var(--r-pill);
  transition: transform .3s cubic-bezier(.16,1,.3,1);
}
.fo-stack span:hover { transform: translateY(-2px); }
.fo-stack i {
  width: 26px; height: 26px; border-radius: 7px;
  background: var(--cf); color: var(--cb);
  display: inline-flex; align-items: center; justify-content: center;
  font-style: normal; font-size: 11px; font-weight: 700;
}

@media (max-width: 860px) {
  .fo-bento { grid-template-columns: 1fr; }
  .fo-marq { margin: 0 -24px; }
}

/* presence line — avatar pill plus a status that rotates */
.fo-presence { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.fo-presence__who {
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--coral); color: #0d0d10;
  padding: 6px 18px 6px 6px; border-radius: var(--r-pill);
  font-size: 16px; font-weight: 600;
}
.fo-presence__who i {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--brand); color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-style: normal; font-size: 13px; font-weight: 600;
  background-size: cover; background-position: center;
}
.fo-presence__status {
  font-size: 15px; color: var(--muted);
  transition: opacity .3s ease, transform .3s ease;
}
.fo-presence__status.is-out { opacity: 0; transform: translateY(-5px); }

/* about page head — the name at full size, then who that person is */
.fo-phead__h { margin: 18px 0 0; }
.fo-phead__h span {
  display: block; line-height: .9; letter-spacing: -.045em;
  font-size: clamp(46px, 11.5vw, 152px);
}
.fo-phead__last {
  color: transparent;
  -webkit-text-stroke: 1.5px rgb(var(--ink-rgb) / .34);
  background: var(--brand);
  -webkit-background-clip: text; background-clip: text;
  background-size: 0% 100%; background-repeat: no-repeat;
  transition: background-size 1s cubic-bezier(.16,1,.3,1);
}
.fo-phead:hover .fo-phead__last { background-size: 100% 100%; }
.fo-roles {
  display: flex; flex-wrap: wrap; gap: 6px 0;
  margin: 26px 0 0; max-width: 44ch;
  font-size: clamp(13px, 1.4vw, 15.5px); color: var(--muted);
}
.fo-roles span::after { content: ",\00a0"; color: var(--faint); }
.fo-roles span:last-child::after { content: "."; }
.fo-roles span { transition: color .25s ease; }
.fo-roles span:hover { color: var(--coral); }

/* credits table — a body of work reads stronger as a filmography than as bullets */
.fo-credits { margin: -4px 0 0; }
.fo-credits__head, .fo-credit {
  display: grid; grid-template-columns: 64px minmax(0, 1.1fr) minmax(0, 1.3fr) 18px;
  gap: 10px; align-items: baseline;
}
.fo-credits__head {
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--cf-2); padding-bottom: 9px; border-bottom: 1px solid var(--cl);
}
.fo-credit {
  padding: 11px 0; border-bottom: 1px solid var(--cl);
  color: inherit; position: relative;
  transition: padding-left .35s cubic-bezier(.16,1,.3,1);
}
.fo-credit span { font-size: 12.5px; color: var(--cf-2); }
.fo-credit b { font-size: 14.5px; font-weight: 600; }
.fo-credit i {
  font-style: normal; font-size: 13px; justify-self: end;
  opacity: 0; transform: translateX(-4px);
  transition: opacity .25s ease, transform .3s cubic-bezier(.16,1,.3,1);
}
a.fo-credit:hover { padding-left: 8px; }
a.fo-credit:hover i { opacity: .75; transform: none; }
a.fo-credit:hover b { text-decoration: underline; text-underline-offset: 3px; }
.fo-credit.is-flat { cursor: default; }
@media (max-width: 520px) {
  .fo-credits__head, .fo-credit { grid-template-columns: 56px 1fr 14px; }
  .fo-credits__head span:nth-child(3), .fo-credit > span:nth-child(3) { grid-column: 2; font-size: 11.5px; }
}

/* ============================================================
   COLLAGE — scenes and activities. A pinned-up wall, not a grid:
   every frame sits at a slight angle and straightens on hover.
   ============================================================ */
.fo-collage__head { margin-bottom: clamp(26px, 3vw, 40px); }
.fo-collage {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: clamp(120px, 13vw, 180px);
  grid-auto-flow: dense;          /* let later frames back-fill the holes */
  gap: clamp(12px, 1.6vw, 22px);
}
.fo-collage > * { min-height: 0; }
.fo-ph {
  margin: 0; position: relative;
  border-radius: var(--r-sm); overflow: hidden;
  background: var(--bg-raise); border: 1px solid var(--line-2);
  aspect-ratio: auto; height: 100%;
  transition: transform .5s cubic-bezier(.16,1,.3,1), box-shadow .5s ease, z-index 0s;
}
.fo-ph--tall { aspect-ratio: auto; grid-row: span 2; }
.fo-ph--wide { aspect-ratio: auto; grid-column: span 2; }
/* alternating tilt so the wall reads as pinned up rather than laid out */
.fo-ph:nth-child(4n+1) { transform: rotate(-1.4deg); }
.fo-ph:nth-child(4n+2) { transform: rotate(1deg); }
.fo-ph:nth-child(4n+3) { transform: rotate(.7deg); }
.fo-ph:nth-child(4n+4) { transform: rotate(-.9deg); }
.fo-ph:hover {
  transform: rotate(0deg) scale(1.03); z-index: 2;
  box-shadow: 0 26px 50px -30px rgb(var(--ink-rgb) / .6);
}
.fo-ph img { width: 100%; height: 100%; object-fit: cover; }


.fo-ph:hover figcaption { opacity: 1; transform: none; }

@media (max-width: 860px) {
  .fo-collage { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: clamp(110px, 22vw, 150px); }
  .fo-ph--wide { grid-column: span 2; }
  .fo-ph--tall { grid-row: span 2; }
}

/* ============================================================
   RÉSUMÉ — the credits table, made expandable
   ============================================================ */
.fo-phead__cta { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 28px; }
.fo-cvhead {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; margin-bottom: 20px;
}
.fo-cvhead h2 { margin: 0; }
.fo-cvhead__hint { font-size: 12.5px; color: var(--faint); }

.fo-roles-list { border-top: 1px solid var(--line); }
.fo-role { border-bottom: 1px solid var(--line-2); position: relative; }
.fo-role::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--brand-v); transform: scaleY(0); transform-origin: top;
  transition: transform .45s cubic-bezier(.16,1,.3,1);
}
.fo-role.is-open::before { transform: scaleY(1); }
.fo-role__btn {
  width: 100%; display: grid;
  grid-template-columns: 92px minmax(0, 1.4fr) minmax(0, 1fr) 26px;
  gap: 16px; align-items: center;
  background: none; border: 0; cursor: pointer; text-align: left;
  font-family: inherit; color: var(--ink);
  padding: 20px 4px 20px 0;
  transition: padding-left .4s cubic-bezier(.16,1,.3,1);
}
.fo-role.is-open .fo-role__btn, .fo-role__btn:hover { padding-left: 16px; }
.fo-role__yr {
  font-size: 12.5px; color: var(--faint);
  font-variant-numeric: tabular-nums; letter-spacing: .04em;
}
.fo-role__co b {
  display: block; font-family: var(--font-display); font-weight: 700;
  letter-spacing: -.02em; font-size: clamp(17px, 1.9vw, 21px);
}
.fo-role__co > span { font-size: 13.5px; color: var(--muted); }
.fo-role__tag { font-size: 12.5px; color: var(--faint); }
.fo-role__x {
  position: relative; width: 26px; height: 26px; border-radius: 50%;
  border: 1px solid var(--line); justify-self: end;
  transition: background .35s ease, border-color .35s ease, transform .45s cubic-bezier(.16,1,.3,1);
}
.fo-role__x::before, .fo-role__x::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 9px; height: 1.5px; background: var(--ink); border-radius: 2px;
  transform: translate(-50%, -50%);
  transition: opacity .3s ease, background .3s ease;
}
.fo-role__x::after { transform: translate(-50%, -50%) rotate(90deg); }
.fo-role.is-open .fo-role__x { background: var(--brand); border-color: transparent; transform: rotate(90deg); }
.fo-role.is-open .fo-role__x::before { background: #fff; }
.fo-role.is-open .fo-role__x::after { opacity: 0; }

.fo-role__body {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .55s cubic-bezier(.16,1,.3,1);
}
.fo-role.is-open .fo-role__body { grid-template-rows: 1fr; }
.fo-role__body > div { overflow: hidden; }
.fo-role__body p {
  margin: 0 0 12px; padding-left: 16px; max-width: 62ch;
  font-size: 15px; color: var(--muted);
}
.fo-role__body ul { margin: 0; padding: 0 0 24px 32px; }
.fo-role__body li { font-size: 14.5px; color: var(--muted); padding: 3px 0; }
.fo-role__body li::marker { color: var(--coral); }

/* ruled key/value lists — same language as the footer index */
.fo-cvsplit { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(30px, 5vw, 64px); }
/* the skills card sizes to its own content rather than stretching to the
   taller Education column, which would leave dead space above its footer */
.fo-cvsplit > .fo-bcard { align-self: start; }
.fo-ruled { border-top: 1px solid var(--line); }
.fo-ruled > div {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 20px; padding: 13px 0; border-bottom: 1px solid var(--line-2);
}
.fo-ruled b { font-size: 14.5px; font-weight: 500; }
.fo-ruled span { font-size: 13px; color: var(--faint); text-align: right; }

@media (max-width: 820px) {
  .fo-cvsplit { grid-template-columns: 1fr; }
  .fo-role__btn { grid-template-columns: 72px 1fr 24px; }
  .fo-role__tag { display: none; }
}

/* ============================================================
   CASE STUDY
   ============================================================ */
.fo-cs__head { padding-bottom: clamp(26px, 3vw, 40px); }
.fo-cs__head .fo-phead__h span { font-size: clamp(40px, 8.4vw, 108px); }

/* facts, as label over value */
.fo-facts {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(14px, 2vw, 30px);
  padding: 22px 0; margin-bottom: clamp(24px, 3vw, 38px);
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.fo-facts span {
  display: block; font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 7px;
}
.fo-facts b { font-size: 14.5px; font-weight: 500; }

.fo-cs__hero {
  border-radius: var(--r-md); overflow: hidden;
  background: var(--panel); border: 1px solid var(--line-2);
  aspect-ratio: 16 / 9;
  display: flex; align-items: center; justify-content: center;
  margin-bottom: clamp(40px, 6vw, 80px);
}
.fo-cs__hero img { width: 100%; height: 100%; object-fit: cover; }

.fo-cs__body { display: flex; flex-direction: column; gap: clamp(46px, 6vw, 84px); }
.fo-cs__block h2 { margin-bottom: 18px; }
.fo-cs__lede {
  margin: 0; max-width: 62ch;
  font-size: clamp(16px, 1.6vw, 19px); line-height: 1.65; color: var(--muted);
}

.fo-cs__step {
  display: grid; grid-template-columns: 48px minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(18px, 3vw, 40px); align-items: start;
  padding: clamp(24px, 3vw, 38px) 0; border-top: 1px solid var(--line-2);
}
.fo-cs__step:first-of-type { border-top: 1px solid var(--line); }
.fo-cs__n {
  font-size: 12px; letter-spacing: .12em; color: var(--coral);
  font-variant-numeric: tabular-nums;
}
.fo-cs__step h3 { margin: 0 0 10px; font-size: clamp(18px, 2vw, 23px); }
.fo-cs__step p { margin: 0; font-size: 15px; line-height: 1.62; color: var(--muted); }
.fo-cs__shot {
  border-radius: var(--r-sm); overflow: hidden;
  background: var(--panel); border: 1px solid var(--line-2);
  aspect-ratio: 4 / 3;
  display: flex; align-items: center; justify-content: center;
  transition: transform .5s cubic-bezier(.16,1,.3,1), box-shadow .5s ease;
}
.fo-cs__shot:hover { transform: translateY(-4px); box-shadow: 0 26px 50px -32px rgb(var(--ink-rgb) / .55); }

/* prev / next */
.fo-cs__nav {
  display: grid; grid-template-columns: 1fr 1fr; gap: 14px;
  margin-top: clamp(50px, 7vw, 90px);
}
.fo-cs__nav a {
  display: flex; flex-direction: column; gap: 7px;
  padding: 22px 24px; border-radius: var(--r-md);
  background: var(--bg-raise); border: 1px solid var(--line-2);
  transition: transform .4s cubic-bezier(.16,1,.3,1), border-color .3s ease;
}
.fo-cs__nav a:hover { transform: translateY(-3px); border-color: var(--periwinkle); }
.fo-cs__nav a.is-next { text-align: right; align-items: flex-end; }
.fo-cs__nav span { font-size: 12px; color: var(--faint); }
.fo-cs__nav b {
  font-family: var(--font-display); font-weight: 700; letter-spacing: -.02em;
  font-size: clamp(17px, 2vw, 22px);
}

@media (max-width: 860px) {
  .fo-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fo-cs__step { grid-template-columns: 40px 1fr; }
  .fo-cs__shot { grid-column: 1 / -1; }
}
@media (max-width: 560px) { .fo-cs__nav { grid-template-columns: 1fr; } }

/* work index — the same ruled-table language as the résumé and footer */
.fo-widx { border-top: 1px solid var(--line); }
.fo-widx__head, .fo-widx__row {
  display: grid; grid-template-columns: 48px minmax(0, 1.6fr) 96px minmax(0, 1fr) 22px;
  gap: 18px; align-items: center;
}
.fo-widx__head {
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--faint); padding: 12px 0; border-bottom: 1px solid var(--line-2);
}
.fo-widx__row {
  padding: 22px 0; border-bottom: 1px solid var(--line-2);
  transition: padding-left .4s cubic-bezier(.16,1,.3,1);
}
.fo-widx__row:hover { padding-left: 14px; }
.fo-widx__n { font-size: 12px; color: var(--faint); font-variant-numeric: tabular-nums; }
.fo-widx__t b {
  display: block; font-family: var(--font-display); font-weight: 700;
  letter-spacing: -.02em; font-size: clamp(19px, 2.4vw, 28px);
}
.fo-widx__t span, .fo-widx__y, .fo-widx__s { font-size: 13px; color: var(--muted); }
.fo-widx__row i {
  font-style: normal; justify-self: end; color: var(--faint);
  opacity: 0; transform: translateX(-5px);
  transition: opacity .25s ease, transform .3s cubic-bezier(.16,1,.3,1);
}
.fo-widx__row:hover i { opacity: 1; transform: none; color: var(--coral); }
@media (max-width: 780px) {
  .fo-widx__head { display: none; }
  .fo-widx__row { grid-template-columns: 40px 1fr 20px; }
  .fo-widx__y, .fo-widx__s { display: none; }
}

/* ============================================================
   REAL PHOTOGRAPHY — a tall portrait inside landscape frames, so
   the framing is set with object-position rather than by cropping.
   ============================================================ */
.fo-hero__img {
  width: 100%; height: 100%;
  object-fit: cover;
  /* pull the crop up: the face sits in the top third of the frame */
  object-position: 50% 22%;
}
.fo-ab__img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 18%;
}
/* the nav avatar is a face crop, so bias it higher still */
.fo-brand__pic[style*="url"] {
  background-size: cover;
  background-position: 50% 20%;
  color: transparent;
  background-image: none;
}
@media (max-width: 680px) {
  .fo-hero__img { object-position: 50% 18%; }
}

/* The hero photograph is dark in both themes, so the UI laid over it must be
   light in both — otherwise light mode puts ink-on-black. A soft scrim keeps
   it legible whatever photo goes in later. */
.fo-hero__media::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 1;
  background:
    linear-gradient(180deg, rgba(0,0,0,.42) 0%, rgba(0,0,0,0) 26%),
    linear-gradient(0deg, rgba(0,0,0,.30) 0%, rgba(0,0,0,0) 18%);
}
.fo-hero__mark { color: #fff; text-shadow: 0 2px 24px rgba(0,0,0,.35); }
.fo-hero__chip {
  background: rgba(255,255,255,.14);
  border-color: rgba(255,255,255,.24);
  color: rgba(255,255,255,.86);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.fo-hero__chip b { color: #fff; }
.fo-hero__bar {
  background: rgba(255,255,255,.12);
  border-color: rgba(255,255,255,.2);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
}
.fo-hero__bar .who b { color: #fff; }
.fo-hero__bar .who span { color: rgba(255,255,255,.72); }
.fo-socialrow a { color: rgba(255,255,255,.72); }
.fo-socialrow a:hover { color: #fff; }

/* the social row lost its spacing when the old hero block was replaced */
.fo-hero__foot .fo-socialrow { display: flex; gap: 18px; flex-wrap: wrap; }
.fo-hero__foot .fo-socialrow a {
  font-size: 12.5px; font-weight: 500; color: var(--faint);
  transition: color .22s ease;
}
.fo-hero__foot .fo-socialrow a:hover { color: var(--ink); }

/* group name + copy together and let the CTAs sit at the foot, rather than
   spreading three blocks across the full height and leaving a hole */
.fo-hero__words { justify-content: flex-start; }
.fo-hero__copy { margin-top: clamp(18px, 2.4vw, 30px); }
.fo-hero__foot { margin-top: auto; }

/* case study: the three-surface card set, and a sourcing note */
.fo-cs__back {
  display: block; width: max-content; margin-bottom: 18px;
  font-size: 13px; color: var(--faint);
  transition: color .22s ease, transform .3s cubic-bezier(.16,1,.3,1);
}
.fo-cs__back:hover { color: var(--ink); transform: translateX(-3px); }

.fo-tri {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(14px, 1.8vw, 22px); margin-top: 26px;
}
.fo-tri__card {
  display: flex; flex-direction: column; gap: 8px;
  padding: 26px 24px 28px; border-radius: var(--r-sm);
  background: var(--bg-raise); border: 1px solid var(--line-2);
  position: relative; overflow: hidden;
  transition: transform .4s cubic-bezier(.16,1,.3,1), border-color .3s ease;
}
.fo-tri__card::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: var(--brand-v); transform: scaleX(0); transform-origin: left;
  transition: transform .5s cubic-bezier(.16,1,.3,1);
}
.fo-tri__card:hover { transform: translateY(-3px); border-color: var(--line); }
.fo-tri__card:hover::before { transform: scaleX(1); }
.fo-tri__n { font-size: 11.5px; letter-spacing: .13em; color: var(--coral); }
.fo-tri__card b {
  font-family: var(--font-display); font-weight: 700; letter-spacing: -.02em;
  font-size: 18px; color: var(--ink);
}
.fo-tri__who { font-size: 12px; color: var(--faint); }
.fo-tri__card p { margin: 6px 0 0; font-size: 14.5px; line-height: 1.55; color: var(--muted); }

.fo-cs__note {
  margin: 18px 0 0; padding: 16px 20px; border-radius: var(--r-sm);
  background: var(--bg-raise); border: 1px solid var(--line-2);
  font-size: 13.5px; line-height: 1.6; color: var(--faint); max-width: 68ch;
}

@media (max-width: 860px) { .fo-tri { grid-template-columns: 1fr; } }

/* ============================================================
   PROJECT SWITCHER — a segmented control whose indicator travels
   to the option you picked, so the movement itself says which
   one you left and which one you landed on.
   ============================================================ */
.fo-seg {
  position: relative; display: inline-flex; align-items: center; gap: 2px;
  margin: 92px auto 0; padding: 4px; border-radius: 18px;
  border: 0.5px solid var(--line);          /* hairline, as in the reference */
  background: rgb(var(--paper-rgb) / .05); backdrop-filter: blur(12px);
}
.fo-seg__wrap { display: flex; justify-content: center; }
/* the indicator: one element that moves, rather than five that light up */
.fo-seg__pill {
  position: absolute; top: 4px; bottom: 4px; left: 0; width: 0;
  border-radius: 14px;                       /* 18 outer − 4 padding */
  background: var(--bg-raise); border: 1px solid var(--line-2);
  transition: transform .52s cubic-bezier(.22, 1, .28, 1), width .52s cubic-bezier(.22, 1, .28, 1);
  pointer-events: none;
}
.fo-seg__b {
  position: relative; z-index: 1;            /* sits above the travelling pill */
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  padding: 9px 14px; border: 0; background: none; border-radius: 14px;
  font-family: var(--font-body); font-size: 13px; color: var(--faint);
  white-space: nowrap; transition: color .3s ease;
}
.fo-seg__b img { width: 18px; height: 18px; border-radius: 5px; opacity: .6; transition: opacity .3s ease; }
.fo-seg__b:hover { color: var(--ink); }
.fo-seg__b.is-on { color: var(--ink); font-weight: 600; }
.fo-seg__b.is-on img, .fo-seg__b:hover img { opacity: 1; }

@media (max-width: 1000px) {
  .fo-seg { display: none; }
}
@media (prefers-reduced-motion: reduce) { .fo-seg__pill { transition: none; } }

/* ============================================================
   WORK — a horizontal accordion. Every project is a column; the
   open one fills the middle and scrolls inside itself, the rest
   wait either side as spines. Nothing here scrolls the page.
   ============================================================ */
.fo-ac {
  display: flex; align-items: stretch;
  height: calc(100vh - 128px); margin-top: 14px;
  border-top: 1px solid var(--line-2); border-bottom: 1px solid var(--line-2);
  overflow: hidden;
}
.fo-ac__col {
  position: relative; display: flex; min-width: 0;
  flex: 0 0 50px;
  border-right: 1px solid var(--line-2);
  transition: flex-basis .72s cubic-bezier(.22, 1, .28, 1), flex-grow .72s cubic-bezier(.22, 1, .28, 1),
              background .5s ease;
}
.fo-ac__col:last-child { border-right: 0; }
.fo-ac__col.is-open { flex: 1 1 auto; }

/* --- the spine, which is all you see when a project is closed --- */
.fo-ac__spine {
  position: relative; overflow: hidden;
  flex: 0 0 50px; width: 50px; background: none; border: 0; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 16px;
  padding: 24px 0 20px; color: var(--faint);
  transition: background .4s ease, color .4s ease;
}
.fo-ac__spine:hover { background: var(--bg-raise); color: var(--ink); }
.fo-ac__spine__logo {
  width: 26px; height: 26px; border-radius: 7px; display: block; flex: none;
  opacity: .78; transition: opacity .35s ease, transform .45s cubic-bezier(.22, 1, .28, 1);
}
.fo-ac__col:not(.is-open):hover .fo-ac__spine__logo { opacity: 1; transform: scale(1.08); }
.fo-ac__spine__n { font-family: var(--font-body); font-size: 11px; letter-spacing: .12em; }
.fo-ac__spine__name {
  writing-mode: vertical-rl; margin-top: 6px;
  font-family: var(--font-display); font-weight: 700; font-size: 15px;
  letter-spacing: -.01em; white-space: nowrap; color: var(--ink);
}
.fo-ac__spine__chp {
  margin-top: auto; font-family: var(--font-body); font-size: 10px;
  letter-spacing: .1em; color: var(--faint);
}
/* the open column keeps a slim coloured edge instead of a spine */
.fo-ac__spine { transition: background .4s ease, color .4s ease, flex-basis .72s cubic-bezier(.22, 1, .28, 1); }
.fo-ac__col.is-open .fo-ac__spine { flex-basis: 6px; width: 6px; padding: 0; background: var(--vc); pointer-events: none; }
.fo-ac__col.is-open .fo-ac__spine > * { display: none; }
.fo-ac__col.is-open .fo-ac__spine__logo { display: none; }

/* --- the spine reacts before you commit to it --- */
.fo-ac__col:not(.is-open):hover { flex-basis: 64px; }
.fo-ac__col:not(.is-open):hover .fo-ac__spine__n { color: var(--vc); }
.fo-ac__col:not(.is-open):hover .fo-ac__spine__name { transform: translateY(-4px); }
.fo-ac__spine__n, .fo-ac__spine__name {
  transition: color .35s ease, transform .45s cubic-bezier(.22, 1, .28, 1);
}
/* a hairline of the project's colour climbing the closed spine */
.fo-ac__spine::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
  background: var(--vc); transform: scaleX(0); transform-origin: 50% 100%;
  transition: transform .5s cubic-bezier(.22, 1, .28, 1);
}
.fo-ac__col:not(.is-open):hover .fo-ac__spine::before { transform: scaleX(1); }
.fo-ac__col.is-open .fo-ac__spine::before { display: none; }

/* --- the contents arrive in sequence once the column has opened --- */
@keyframes fo-ac-rise {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}
.fo-ac__col.is-open .fo-ac__head,
.fo-ac__col.is-open .fo-ac__facts,
.fo-ac__col.is-open .fo-ac__t,
.fo-ac__col.is-open .fo-ac__lede,
.fo-ac__col.is-open .fo-ac__shot--hero {
  animation: fo-ac-rise .62s cubic-bezier(.22, 1, .28, 1) both;
}
.fo-ac__col.is-open .fo-ac__head      { animation-delay: .16s; }
.fo-ac__col.is-open .fo-ac__t         { animation-delay: .22s; }
.fo-ac__col.is-open .fo-ac__facts     { animation-delay: .28s; }
.fo-ac__col.is-open .fo-ac__lede      { animation-delay: .30s; }
.fo-ac__col.is-open .fo-ac__shot--hero{ animation-delay: .36s; }

/* the name in the header slides across as the column widens */
@keyframes fo-ac-slide {
  from { opacity: 0; transform: translateX(-22px); }
  to   { opacity: 1; transform: none; }
}
.fo-ac__col.is-open .fo-ac__name { animation: fo-ac-slide .62s cubic-bezier(.22, 1, .28, 1) .18s both; }

/* --- the panel: the only thing on this page that scrolls --- */
.fo-ac__panel {
  /* Pinned to the width it will have when open, so the copy is set once and
     the widening column reveals it instead of re-wrapping it every frame.
     This has to be flex-basis: a plain `width` loses to `flex: 1`. */
  flex: 0 0 var(--ac-open, auto);
  min-width: 0; opacity: 0; pointer-events: none; transition: opacity .18s ease;
}
.fo-ac__col.is-open .fo-ac__panel {
  opacity: 1; pointer-events: auto; transition: opacity .34s ease .1s;
}
.fo-ac__scroll {
  height: 100%; width: 100%; overflow-y: auto; overscroll-behavior: contain;
  padding: clamp(24px, 2.4vw, 34px) clamp(18px, 1.8vw, 28px) 80px;
  scrollbar-width: thin;
}
.fo-ac__head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 20px;
  padding-bottom: 22px; border-bottom: 1px solid var(--line-2); margin-bottom: 30px;
}
.fo-ac__namewrap { display: flex; align-items: center; gap: 14px; min-width: 0; }
.fo-ac__logo { width: 44px; height: 44px; border-radius: 11px; flex: none; display: block; }
.fo-ac__name { margin: 0; font-size: clamp(28px, 3.4vw, 50px); font-weight: 800; letter-spacing: -.035em; color: var(--ink); }
.fo-ac__name sup { font-size: .3em; font-weight: 500; color: var(--vc); vertical-align: super; margin-left: 6px; }
.fo-ac__close {
  flex: none; width: 34px; height: 34px; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--line); background: none; color: var(--ink); font-size: 12px;
}
.fo-ac__close:hover { background: var(--bg-raise); }

/* --- details on the side, study in the main measure --- */
.fo-ac__grid { display: grid; grid-template-columns: 124px minmax(0, 1fr); gap: clamp(18px, 1.8vw, 28px); align-items: start; }
.fo-ac__facts { position: sticky; top: 0; }
.fo-ac__fact { padding: 0 0 18px; }
.fo-ac__fact span {
  display: block; font-family: var(--font-body); font-size: 10.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 5px;
}
.fo-ac__fact b { display: block; font-family: var(--font-body); font-weight: 400; font-size: 13.5px; line-height: 1.36; color: var(--ink); hyphens: auto; }
.fo-ac__link {
  color: var(--ink); text-decoration: none; word-break: break-all;
  border-bottom: 1px solid var(--line); transition: color .3s ease, border-color .3s ease;
}
.fo-ac__link:hover { color: var(--vc); border-color: var(--vc); }
/* names credited in the fact panel read as words, not as URLs */
.fo-ac__link--name { word-break: normal; overflow-wrap: anywhere; }
.fo-ac__link i { font-style: normal; font-size: .85em; }
.fo-ac__share {
  margin-top: 6px; padding: 9px 12px; width: 100%; border-radius: 3px; cursor: pointer;
  border: 1px solid var(--line); background: none; color: var(--ink);
  font-family: var(--font-body); font-size: 12px;
}
.fo-ac__share:hover { background: var(--bg-raise); }

.fo-ac__t {
  margin: 0 0 20px; font-family: var(--font-display); font-weight: 700;
  font-size: clamp(24px, 2.4vw, 36px); line-height: 1.12; letter-spacing: -.032em;
  color: var(--ink); max-width: 24ch;
}
.fo-ac__lede { margin: 0 0 4px; font-size: clamp(17px, 1.3vw, 21px); line-height: 1.5; color: var(--ink); }
.fo-ac__h {
  margin: clamp(34px, 4vw, 52px) 0 14px; font-family: var(--font-display);
  font-weight: 800; font-size: clamp(19px, 1.7vw, 25px); letter-spacing: -.028em; color: var(--ink);
}
.fo-ac__body { margin: 0 0 15px; font-size: 16px; line-height: 1.72; color: var(--muted); max-width: 68ch; }
.fo-ac__body:last-of-type { margin-bottom: 0; }
/* --- the long-form case study: subsections, lists, flows, sourced figures --- */
.fo-ac__sub {
  display: flex; align-items: baseline; gap: 14px;
  margin: clamp(34px, 4vw, 50px) 0 14px; padding-top: 20px;
  border-top: 1px solid var(--line-2);
}
.fo-ac__sub span {
  flex: none; font-family: var(--font-body); font-size: 12px; letter-spacing: .1em; color: var(--vc);
}
.fo-ac__sub b {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(18px, 1.5vw, 23px); letter-spacing: -.024em; color: var(--ink);
}
.fo-ac__list { margin: 0 0 16px; padding-left: 0; list-style: none; max-width: 68ch; }
.fo-ac__list li {
  position: relative; padding-left: 20px; margin-bottom: 8px;
  font-size: 16px; line-height: 1.66; color: var(--muted);
}
.fo-ac__list li::before {
  content: ""; position: absolute; left: 2px; top: .68em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--vc); opacity: .8;
}
/* a journey written as steps, kept on one visual line */
.fo-ac__flow {
  margin: 0 0 18px; padding: 14px 16px; border-radius: 5px;
  border: 1px solid var(--line-2); background: rgb(var(--ink-rgb) / .04);
  font-family: var(--font-body); font-size: 14px; line-height: 1.7; color: var(--ink);
  max-width: 68ch;
}
/* figures that came from public reporting, visibly separated from the work */
.fo-ac__note {
  margin: 18px 0; padding: 20px 22px; border-radius: 6px;
  border: 1px solid var(--line-2); border-left: 3px solid var(--vc);
  background: rgb(var(--ink-rgb) / .04); max-width: 68ch;
}
.fo-ac__note p { margin: 0 0 12px; font-size: 15px; line-height: 1.66; color: var(--muted); }
.fo-ac__note p:last-child { margin-bottom: 0; }

.fo-ac__credits {
  margin: 30px 0 0; padding-top: 18px; border-top: 1px solid var(--line-2);
  font-family: var(--font-body); font-size: 13.5px; color: var(--faint);
}
.fo-ac__step { display: grid; grid-template-columns: 42px minmax(0, 1fr); gap: 18px; padding: 22px 0; border-bottom: 1px solid var(--line-2); }
.fo-ac__step > span { font-family: var(--font-body); font-size: 11.5px; letter-spacing: .1em; color: var(--faint); padding-top: 6px; }
.fo-ac__step b { display: block; font-family: var(--font-display); font-weight: 700; font-size: clamp(18px, 1.4vw, 22px); letter-spacing: -.02em; color: var(--ink); margin-bottom: 8px; }
.fo-ac__step p { margin: 0; font-size: 16px; line-height: 1.72; color: var(--muted); max-width: 68ch; }
.fo-ac__shot {
  margin: 20px 0 0; border-radius: 6px; border: 1px solid var(--line-2);
  overflow: hidden; background: var(--bg-raise);
}
.fo-ac__shot img { width: 100%; height: auto; display: block; }
.fo-ac__shot figcaption {
  padding: 10px 14px; font-family: var(--font-body); font-size: 12px;
  color: var(--faint); border-top: 1px solid var(--line-2);
}
.fo-ac__shot span { font-family: var(--font-body); font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: rgb(var(--paper-rgb) / .7); }
.fo-ac__shot--hero { margin-top: 26px; aspect-ratio: 16 / 9; }
.fo-ac__strip { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.fo-ac__shot--sm { margin: 0; aspect-ratio: 3 / 4; }

/* --- the jump control: pinned inside the open column so switching
       projects never depends on reaching the end of a study --- */
.fo-ac__jump {
  position: absolute; right: 22px; bottom: 22px; z-index: 8;
  display: none; align-items: stretch; gap: 8px;
}
.fo-ac__col.is-open .fo-ac__jump { display: flex; }
.fo-ac__jump__b {
  display: inline-flex; align-items: center; gap: 10px; cursor: pointer;
  padding: 0 14px; height: 52px; border-radius: 999px;
  border: 1px solid var(--line); color: var(--ink);
  background: rgb(var(--paper-rgb) / .07); backdrop-filter: blur(14px);
  font-family: var(--font-body); font-size: 13px;
  transition: background .3s ease, border-color .3s ease, transform .4s cubic-bezier(.22,1,.28,1);
}
.fo-ac__jump__b:first-child { width: 52px; justify-content: center; padding: 0; font-size: 15px; }
.fo-ac__jump__b:hover { transform: translateY(-2px); border-color: transparent; }
.fo-ac__jump__b:first-child:hover { background: rgb(var(--paper-rgb) / .16); }
.fo-ac__jump__next { position: relative; overflow: hidden; isolation: isolate; padding-right: 12px; }
.fo-ac__jump__next::before {
  content: ""; position: absolute; inset: 0; z-index: -1; background: var(--nc);
  transform: translateY(101%); transition: transform .42s cubic-bezier(.22,1,.28,1);
}
.fo-ac__jump__next:hover::before { transform: none; }
.fo-ac__jump__next img { width: 24px; height: 24px; border-radius: 6px; flex: none; }
.fo-ac__jump__t { display: flex; flex-direction: column; line-height: 1.15; text-align: left; min-width: 0; }
.fo-ac__jump__t i {
  font-style: normal; font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--faint); transition: color .3s ease;
}
.fo-ac__jump__t b { font-weight: 600; font-size: 13px; white-space: nowrap; transition: color .3s ease; }
.fo-ac__jump__go { font-size: 15px; color: var(--faint); transition: color .3s ease, transform .4s cubic-bezier(.22,1,.28,1); }
.fo-ac__jump__next:hover .fo-ac__jump__t i,
.fo-ac__jump__next:hover .fo-ac__jump__t b,
.fo-ac__jump__next:hover .fo-ac__jump__go { color: #fff; }
.fo-ac__jump__next:hover .fo-ac__jump__go { transform: translateX(4px); }

/* the study shouldn't run underneath the control */
.fo-ac__col.is-open .fo-ac__scroll { padding-bottom: 108px; }

@media (max-width: 1000px) {
  .fo-ac__jump { position: static; display: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  .fo-ac__jump__b, .fo-ac__jump__next::before, .fo-ac__jump__go { transition: none; }
}

/* --- the way onward, for anyone who never reads the spines --- */
.fo-ac__next {
  display: block; width: 100%; text-align: left; cursor: pointer;
  margin: clamp(44px, 5vw, 70px) 0 0; padding: clamp(22px, 2.4vw, 32px);
  border: 1px solid var(--line); border-radius: 6px; background: none;
  position: relative; overflow: hidden; isolation: isolate;
  transition: border-color .35s ease, transform .5s cubic-bezier(.22, 1, .28, 1);
}
.fo-ac__next::before {
  content: ""; position: absolute; inset: 0; z-index: -1; background: var(--nc);
  transform: translateY(101%); transition: transform .5s cubic-bezier(.22, 1, .28, 1);
}
.fo-ac__next:hover { border-color: transparent; transform: translateY(-3px); }
.fo-ac__next:hover::before { transform: none; }
.fo-ac__next__k {
  display: block; font-family: var(--font-body); font-size: 10.5px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 14px; transition: color .35s ease;
}
.fo-ac__next__row { display: flex; align-items: center; gap: 14px; }
.fo-ac__next__logo { width: 40px; height: 40px; border-radius: 10px; flex: none; }
.fo-ac__next__name {
  flex: 1; min-width: 0; font-size: clamp(22px, 2.2vw, 32px); font-weight: 800;
  letter-spacing: -.035em; color: var(--ink); transition: color .35s ease;
}
.fo-ac__next__go {
  flex: none; font-size: clamp(20px, 2vw, 28px); color: var(--faint);
  transition: color .35s ease, transform .5s cubic-bezier(.22, 1, .28, 1);
}
.fo-ac__next:hover .fo-ac__next__go { transform: translateX(8px); }
.fo-ac__next__head {
  display: block; margin-top: 12px; font-family: var(--font-body); font-size: 14px;
  line-height: 1.55; color: var(--muted); transition: color .35s ease;
}
.fo-ac__next:hover .fo-ac__next__k,
.fo-ac__next:hover .fo-ac__next__name,
.fo-ac__next:hover .fo-ac__next__go,
.fo-ac__next:hover .fo-ac__next__head { color: #fff; }

/* --- the handover, made legible: the incoming column is edged in its own
       colour and travels in the direction you moved, while the spine you
       just closed holds its colour so you can see where it went --- */
.fo-ac__col { overflow: hidden; }

/* the column you just left stays marked long enough to find */
.fo-ac__col.is-from .fo-ac__spine { background: var(--bg-raise); }
.fo-ac__col.is-from .fo-ac__spine::before { transform: scaleX(1); }
.fo-ac__col.is-from .fo-ac__spine__logo { opacity: 1; }
.fo-ac__col.is-from .fo-ac__spine__name { color: var(--ink); }
.fo-ac__col.is-from .fo-ac__spine__n { color: var(--vc); }

/* and the open one is unmistakably the open one */
.fo-ac__count {
  flex: none; font-family: var(--font-body); font-size: 13px; letter-spacing: .06em;
  color: var(--faint); padding-top: 6px;
}
.fo-ac__count i { font-style: normal; margin: 0 3px; opacity: .5; }

@media (prefers-reduced-motion: reduce) {
    .fo-ac__next, .fo-ac__next::before, .fo-ac__next__go { transition: none; }
}

@media (max-width: 1000px) {
  .fo-ac { flex-direction: column; height: auto; margin-top: 84px; overflow: visible; }
  .fo-ac__col { flex: none !important; border-right: 0; border-bottom: 1px solid var(--line-2); flex-direction: column; }
  .fo-ac__spine { flex-basis: auto !important; width: 100% !important; flex-direction: row; gap: 12px; padding: 18px var(--edge) !important; }
  .fo-ac__spine__name { writing-mode: horizontal-tb; margin-top: 0; }
  .fo-ac__spine__chp { margin-top: 0; margin-left: auto; }
  .fo-ac__col.is-open .fo-ac__spine__logo { display: block; }
  .fo-ac__col.is-open .fo-ac__spine { background: none; pointer-events: auto; }
  .fo-ac__col.is-open .fo-ac__spine > * { display: block; }
  .fo-ac__panel { display: none; flex: 1 1 auto; }
  .fo-ac__col.is-open .fo-ac__panel { display: block; }
  .fo-ac__scroll { height: auto; overflow: visible; padding: 0 var(--edge) 40px; }
  /* minmax(0,1fr), not 1fr: a 1fr track has an automatic minimum, so the
     no-wrap tab row's min-content width grew the whole column. */
  .fo-ac__grid { grid-template-columns: minmax(0, 1fr); }
  .fo-ac__facts { position: static; }
}
@media (prefers-reduced-motion: reduce) {
  .fo-ac__col, .fo-ac__spine, .fo-ac__panel { transition: none; }
  .fo-ac__col.is-open .fo-ac__head, .fo-ac__col.is-open .fo-ac__facts,
  .fo-ac__col.is-open .fo-ac__t, .fo-ac__col.is-open .fo-ac__lede,
  .fo-ac__col.is-open .fo-ac__shot--hero, .fo-ac__col.is-open .fo-ac__name { animation: none; }
  .fo-ac__col:not(.is-open):hover { flex-basis: 50px; }
}

/* ============================================================
   FOOTER SOCIALS — one slim strip. Pointing at a name floods it
   with its own colour from the left; the rest stay quiet.
   ============================================================ */
.fo-social { padding: clamp(24px, 3vw, 34px) 0 clamp(6px, 1vw, 12px); }
.fo-social__h {
  display: block; font-family: var(--font-body); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 12px;
}
.fo-social__grid {
  display: flex; flex-wrap: wrap; gap: 8px;
}
.fo-social__card {
  position: relative; overflow: hidden; isolation: isolate;
  display: inline-flex; align-items: center;
  padding: 11px 20px; border-radius: 999px;
  border: 1px solid var(--line); text-decoration: none; color: var(--ink);
  transition: transform .4s cubic-bezier(.16,1,.3,1), border-color .3s ease;
}
.fo-social__card::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(100deg, var(--vc) 0%, rgb(var(--ink-rgb) / .35) 140%);
  transform: translateX(-101%);
  transition: transform .45s cubic-bezier(.16,1,.3,1);
}
.fo-social__card:hover, .fo-social__card:focus-visible {
  transform: translateY(-2px); border-color: transparent; outline: none;
}
.fo-social__card:hover::before, .fo-social__card:focus-visible::before { transform: none; }
.fo-social__card b {
  font-size: 13.5px; font-weight: 600; letter-spacing: -.01em; line-height: 1;
  transition: color .3s ease;
}
.fo-social__card:hover b { color: #fff; }

.fo-social__ico {
  flex: 0 0 auto; width: 15px; height: 15px; margin-right: 9px;
  color: var(--ink); opacity: .78; transition: color .3s ease, opacity .3s ease;
}
.fo-social__card:hover .fo-social__ico,
.fo-social__card:focus-visible .fo-social__ico { color: #fff; opacity: 1; }


@media (prefers-reduced-motion: reduce) {
  .fo-social__card, .fo-social__card::before { transition: none; }
}

/* ============================================================
   HOMEPAGE → CASE STUDIES — the way through, after the showcase
   ============================================================ */
.fo-worktocs { padding-block: clamp(30px, 4vw, 54px) clamp(10px, 2vw, 24px); }
.fo-worktocs__go {
  position: relative; display: flex; align-items: center; justify-content: space-between;
  gap: clamp(16px, 3vw, 40px);
  padding: clamp(26px, 3.2vw, 40px) clamp(24px, 3vw, 38px);
  border: 1px solid var(--line); border-radius: 18px;
  text-decoration: none; color: var(--ink); overflow: hidden; isolation: isolate;
  transition: border-color .35s ease, transform .45s cubic-bezier(.16,1,.3,1),
              color .35s ease;
}
.fo-worktocs__go::before {
  content: ""; position: absolute; inset: 0; z-index: -1; background: var(--brand);
  transform: translateX(-101%); transition: transform .55s cubic-bezier(.16,1,.3,1);
}
.fo-worktocs__go:hover, .fo-worktocs__go:focus-visible {
  border-color: transparent; transform: translateY(-3px); color: #fff; outline: none;
}
.fo-worktocs__go:hover::before, .fo-worktocs__go:focus-visible::before { transform: none; }
.fo-worktocs__big {
  font-size: clamp(26px, 4vw, 52px); font-weight: 800; letter-spacing: -.035em; line-height: 1.02;
}
.fo-worktocs__chip {
  flex: none; display: grid; place-items: center;
  width: clamp(46px, 4.4vw, 60px); height: clamp(46px, 4.4vw, 60px);
  border-radius: 50%; border: 1px solid var(--line-2);
  font-size: clamp(18px, 2vw, 24px); color: var(--ink);
  transition: background-color .35s ease, border-color .35s ease,
              color .35s ease, transform .45s cubic-bezier(.16,1,.3,1);
}
/* the label rides the colour change on the anchor itself; only the chip
   inverts into a solid white pill */
.fo-worktocs__go:hover .fo-worktocs__chip,
.fo-worktocs__go:focus-visible .fo-worktocs__chip {
  background: #fff; border-color: #fff; color: #14141a; transform: translateX(4px);
}

@media (prefers-reduced-motion: reduce) {
  .fo-worktocs__go, .fo-worktocs__go::before, .fo-worktocs__chip { transition: none; }
}

/* ============================================================
   OFF THE CLOCK — a reel. One band of the page, dragged
   sideways. Photos keep their own aspect and sit at slightly
   different heights so the rail never reads as a ruler.
   ============================================================ */
.fo-reel { position: relative; margin-top: clamp(16px, 2vw, 26px); }
.fo-reel__track {
  display: flex; align-items: center; gap: clamp(12px, 1.4vw, 20px);
  height: clamp(240px, 34vh, 400px);
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x proximity; scrollbar-width: none;
  cursor: grab; padding: 26px 0;
  /* bleed to the page edges so the reel reads as a band, not a box */
  margin: 0 calc(var(--edge) * -1); padding-left: var(--edge); padding-right: var(--edge);
  -webkit-overflow-scrolling: touch;
}
.fo-reel__track::-webkit-scrollbar { display: none; }
.fo-reel__track.is-drag { cursor: grabbing; scroll-snap-type: none; }

.fo-reel__ph {
  position: relative; flex: none; height: 100%;
  padding: 0; border: 0; background: none; cursor: pointer;
  border-radius: 12px; overflow: hidden; scroll-snap-align: center;
  transform: translateY(var(--off)) rotate(var(--tilt));
  box-shadow: 0 16px 44px rgb(0 0 0 / .30);
  transition: transform .5s cubic-bezier(.16,1,.3,1), opacity .35s ease, box-shadow .45s ease;
}
.fo-reel__ph img {
  height: 100%; width: auto; display: block; pointer-events: none;
  user-select: none; -webkit-user-drag: none;
}
.fo-reel__track:hover .fo-reel__ph { opacity: .5; }
.fo-reel__track .fo-reel__ph:hover,
.fo-reel__track .fo-reel__ph:focus-visible {
  opacity: 1; outline: none; z-index: 3;
  transform: translateY(calc(var(--off) - 8px)) rotate(0deg) scale(1.04);
  box-shadow: 0 30px 74px rgb(0 0 0 / .46);
}
.fo-reel__cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 28px 12px 10px; text-align: left;
  background: linear-gradient(to top, rgb(0 0 0 / .78), transparent);
  opacity: 0; transform: translateY(8px);
  transition: opacity .3s ease, transform .4s cubic-bezier(.16,1,.3,1);
}
.fo-reel__cap b { font-family: var(--font-body); font-size: 11.5px; font-weight: 500; color: #fff; white-space: nowrap; }
.fo-reel__cap i { font-style: normal; font-size: 11px; color: rgb(255 255 255 / .8); }
.fo-reel__ph:hover .fo-reel__cap, .fo-reel__ph:focus-visible .fo-reel__cap { opacity: 1; transform: none; }

.fo-reel__foot { display: flex; align-items: center; gap: 18px; margin-top: 14px; }
.fo-reel__arrows { display: flex; gap: 8px; flex: none; }
.fo-reel__arrow {
  width: 34px; height: 34px; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--line); background: none; color: var(--ink); font-size: 13px;
  transition: background .3s ease, border-color .3s ease, transform .3s ease;
}
.fo-reel__arrow:hover { background: var(--bg-raise); transform: translateY(-1px); }
.fo-reel__bar { flex: 1; height: 2px; background: var(--line-2); border-radius: 2px; overflow: hidden; }
.fo-reel__bar span { display: block; height: 100%; width: 0; background: var(--brand); border-radius: 2px; }
.fo-reel__hint {
  flex: none; font-family: var(--font-body); font-size: 10px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--faint);
}

@media (max-width: 720px) {
  .fo-reel__track { height: clamp(210px, 40vw, 280px); }
  .fo-reel__hint { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .fo-reel__ph { transition: none; }
}

/* --- the viewer --- */
.fo-lb {
  position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center;
  gap: clamp(8px, 2vw, 28px); padding: clamp(16px, 4vw, 54px);
  background: rgb(var(--paper-rgb) / .04); backdrop-filter: blur(18px);
  background-color: rgb(6 6 9 / .88);
  opacity: 0; transition: opacity .3s ease;
}
.fo-lb[hidden] { display: none; }
.fo-lb.is-on { opacity: 1; }
.fo-lb__stage { margin: 0; display: flex; flex-direction: column; gap: 12px; align-items: center; max-height: 100%; }
.fo-lb__stage img {
  max-width: min(1100px, 82vw); max-height: 78vh; width: auto; height: auto;
  border-radius: 12px; display: block; box-shadow: 0 30px 90px rgb(0 0 0 / .5);
}
.fo-lb__stage figcaption {
  font-family: var(--font-body); font-size: 12px; letter-spacing: .04em;
  color: rgb(255 255 255 / .7);
}
.fo-lb__close, .fo-lb__nav {
  flex: none; width: 44px; height: 44px; border-radius: 50%; cursor: pointer;
  background: rgb(255 255 255 / .08); border: 1px solid rgb(255 255 255 / .16); color: #fff;
  font-size: 15px; line-height: 1; transition: background .3s ease, transform .3s ease;
}
.fo-lb__close { position: absolute; top: clamp(14px, 3vw, 30px); right: clamp(14px, 3vw, 30px); }
.fo-lb__close:hover, .fo-lb__nav:hover { background: rgb(255 255 255 / .18); transform: scale(1.06); }
@media (max-width: 600px) {
  .fo-lb__nav { position: absolute; bottom: 22px; }
  .fo-lb__nav--prev { left: 22px; } .fo-lb__nav--next { right: 22px; }
}
@media (prefers-reduced-motion: reduce) {
  .fo-ph, .fo-ph img, .fo-ph__cap { transition: none; }
  .fo-ph:nth-child(odd), .fo-ph:nth-child(even), .fo-ph:nth-child(3n) { transform: none; }
}

/* ── click-through walkthrough ─────────────────────────────────── */
.fo-proto{margin:26px 0 30px;border:1px solid var(--line-2);border-radius:12px;overflow:hidden;
  background:rgb(var(--ink-rgb)/.03)}
.fo-proto__bar{display:flex;align-items:center;gap:10px;padding:11px 14px;
  border-bottom:1px solid var(--line-2);background:rgb(var(--ink-rgb)/.04)}
.fo-proto__tag{font-size:10px;letter-spacing:.09em;text-transform:uppercase;font-weight:650;
  color:var(--vc);border:1px solid currentColor;border-radius:100px;padding:2px 8px;flex:none}
.fo-proto__title{font-size:13px;font-weight:600;color:rgb(var(--ink-rgb)/.86);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fo-proto__count{margin-left:auto;flex:none;font-size:11px;font-variant-numeric:tabular-nums;
  color:rgb(var(--ink-rgb)/.5)}
.fo-proto__count i{font-style:normal;color:rgb(var(--ink-rgb)/.85);font-weight:650}

.fo-proto__stage{position:relative;display:block;width:100%;cursor:pointer;
  background:#0d0d0d;line-height:0;outline:none}
.fo-proto__stage:focus-visible{box-shadow:inset 0 0 0 2px var(--vc)}
.fo-proto__stage .fo-proto__shot{display:none;width:100%;height:auto}
.fo-proto__stage .fo-proto__shot.is-on{display:block;animation:fo-proto-in .22s ease both}
@keyframes fo-proto-in{from{opacity:0}to{opacity:1}}
.fo-proto__cue{position:absolute;right:12px;bottom:12px;line-height:1.2;
  font-size:11px;font-weight:600;letter-spacing:.02em;color:#fff;
  background:rgb(0 0 0/.66);border:1px solid rgb(255 255 255/.22);
  border-radius:100px;padding:6px 12px;pointer-events:none;
  transition:opacity .2s ease}
.fo-proto__stage:hover .fo-proto__cue{opacity:0}
.fo-proto.is-done .fo-proto__cue{opacity:1}

.fo-proto__steps{display:flex;flex-wrap:wrap;gap:0;margin:0;padding:0;list-style:none;
  border-top:1px solid var(--line-2)}
.fo-proto__steps li{flex:1 1 0;min-width:104px}
.fo-proto__steps li + li .fo-proto__step{border-left:1px solid var(--line-2)}
.fo-proto__step{display:flex;flex-direction:column;gap:3px;width:100%;height:100%;
  padding:9px 10px;background:none;border:0;border-top:2px solid transparent;
  font:inherit;text-align:left;cursor:pointer;color:rgb(var(--ink-rgb)/.5);
  transition:color .16s ease,border-color .16s ease,background .16s ease}
.fo-proto__step i{font-style:normal;font-size:10px;font-variant-numeric:tabular-nums;
  letter-spacing:.06em;opacity:.7}
.fo-proto__step span{font-size:11.5px;line-height:1.3;font-weight:550}
.fo-proto__step:hover{color:rgb(var(--ink-rgb)/.8);background:rgb(var(--ink-rgb)/.04)}
.fo-proto__step.is-on{color:rgb(var(--ink-rgb)/.95);border-top-color:var(--vc);
  background:rgb(var(--ink-rgb)/.05)}
.fo-proto figcaption{padding:10px 14px 13px;border-top:1px solid var(--line-2);
  font-size:12px;line-height:1.5;color:rgb(var(--ink-rgb)/.62)}
@media (max-width:640px){
  .fo-proto__steps li{min-width:50%;flex:1 1 50%}
  .fo-proto__steps li:nth-child(odd) .fo-proto__step{border-left:0}
  .fo-proto__step span{font-size:11px}
}
@media (prefers-reduced-motion:reduce){.fo-proto__stage .fo-proto__shot.is-on{animation:none}}

/* proper browser mockups in the showcase filmstrip */
.fo-mock {
  margin: 0; flex-shrink: 0; align-self: center;
  width: clamp(380px, 44vw, 600px);
  border-radius: 14px; overflow: hidden;
  background: #17181b;
  border: 1px solid rgb(var(--ink-rgb) / .10);
  box-shadow: 0 34px 70px -34px rgba(13,13,16,.55), 0 2px 6px -2px rgba(13,13,16,.18);
}
.fo-mock__chrome {
  display: flex; align-items: center; gap: 12px;
  height: 38px; padding: 0 14px;
  background: #1e1f23; border-bottom: 1px solid rgb(255 255 255 / .07);
}
.fo-mock__dots { display: flex; gap: 7px; flex: none; }
.fo-mock__dots i { width: 11px; height: 11px; border-radius: 50%; }
.fo-mock__dots i:nth-child(1) { background: #ff5f57; }
.fo-mock__dots i:nth-child(2) { background: #febc2e; }
.fo-mock__dots i:nth-child(3) { background: #28c840; }
.fo-mock__url {
  flex: 1; min-width: 0; text-align: center;
  font-size: 11px; letter-spacing: .01em; color: rgb(255 255 255 / .42);
  background: rgb(255 255 255 / .06); border-radius: 999px;
  padding: 4px 12px; margin-right: 46px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fo-proj--strip .fo-rail .fo-mock > img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover; object-position: top center;
}
@media (max-width: 640px) {
  .fo-mock { width: min(84vw, 380px); }
  .fo-mock__chrome { height: 30px; padding: 0 10px; }
  .fo-mock__dots i { width: 8px; height: 8px; }
  .fo-mock__url { font-size: 9px; margin-right: 34px; padding: 3px 9px; }
}

/* Mobile showcase fix.
   The unscoped `.fo-proj__media{position:absolute}` further up the file lands
   after the max-width:940px rule that makes this box static, so on phones the
   media collapsed to ~2px and its overflow:hidden clipped the whole filmstrip.
   Making it `relative` keeps it in flow (so it has a width) while still
   containing the absolutely-positioned rail. */
@media (max-width: 1180px) {
  .fo-proj__media { position: relative !important; inset: auto !important; }
}

/* hero CTA — sits with her name in the foot line, so the claim stays alone */
.fo-hero__cta { margin-top: clamp(18px, 2.8vh, 32px); align-self: center; }

/* Hero as a conversation. Her lines arrive from the left with an avatar;
   the call to action is the reply you send back, so the CTA is part of the
   thread instead of a button parked underneath it. */
.fo-thread {
  margin-top: clamp(18px, 3vh, 34px);
  max-width: 640px; margin-inline: auto;
  display: grid; gap: 10px; text-align: left;
}
.fo-thread__in { display: flex; align-items: flex-start; gap: 12px; }
/* avatar sits with the first message, not stranded at the bottom of the stack */
.fo-thread__pic { margin-top: 6px; }
.fo-thread__pic {
  width: 34px; height: 34px; flex: none; border-radius: 50%;
  background: var(--brand) center/cover no-repeat;
  box-shadow: 0 2px 8px -4px rgba(23,23,28,.5);
}
.fo-thread .fo-msgs { margin: 0; gap: 8px; align-items: flex-start; }
.fo-thread .fo-msg {
  border-radius: var(--r-bubble) var(--r-bubble) var(--r-bubble) 10px;
}
.fo-thread .fo-msg--out {
  /* must out-specify `.fo-thread .fo-msg` above or it inherits the
     incoming tail corner */
  border-radius: var(--r-bubble) var(--r-bubble) 10px var(--r-bubble);
}
.fo-msg--out {
  justify-self: end; align-self: end;
  display: inline-flex; align-items: center; gap: 9px;
  margin: 2px 0 0; padding: 15px 26px;
  border-radius: var(--r-bubble) var(--r-bubble) 10px var(--r-bubble);
  background: var(--brand); background-size: 170% 170%; background-position: 0% 50%;
  color: #fff; font-size: 16px; font-weight: 550; line-height: 1.4;
  box-shadow: 0 12px 28px -16px rgba(123,128,228,.95);
  transition: background-position .55s cubic-bezier(.2,.8,.2,1),
              transform .24s ease, box-shadow .3s ease;
}
.fo-msg--out i { font-style: normal; transition: transform .32s cubic-bezier(.22,1,.28,1); }
.fo-msg--out:hover { background-position: 100% 50%; transform: translateY(-2px);
  box-shadow: 0 16px 34px -14px rgba(251,139,113,.9); }
.fo-msg--out:hover i { transform: translateX(4px); }
@media (prefers-reduced-motion: reduce) { .fo-msg--out, .fo-msg--out i { transition: none; } }
@media (max-width: 780px) {
  .fo-thread { max-width: none; }
  .fo-thread__pic { width: 28px; height: 28px; }
  .fo-msg--out { padding: 13px 22px; font-size: 15px; }
}



/* Hero bubbles are above the fold, so they are visible by default.
   No reveal animation: neither the IntersectionObserver nor a CSS keyframe
   is guaranteed to have run at first paint, and an invisible hero is a worse
   failure than a missing fade. The claim above them isn't animated either. */
.fo-hero__bubbles .fo-msg { opacity: 1; transform: none; }

/* Centred hero. The stage was a left-aligned column; centre the stack and the
   two blocks inside it. .fo-msgs pinned its bubbles to flex-start for the
   left-aligned section this content used to live in, so that needs undoing. */
.fo-hero__stage { align-items: center; text-align: center; }
.fo-claim { margin-inline: auto; }
.fo-hero__bubbles { margin-inline: auto; }
.fo-hero__bubbles .fo-msgs { align-items: center; }

/* Tighter nav. Height was set by the 40px icon button plus 9px padding; every
   piece here steps down together so the capsule stays balanced. */
.fo-nav { padding: 6px 6px 6px 8px; gap: 12px; }
.fo-brand { gap: 9px; }
.fo-brand__pic { width: 30px; height: 30px; }
.fo-brand__name { font-size: 17.5px; }
.fo-nav__links a { font-size: 12.5px; padding: 6px 13px; }
.fo-nav__actions { gap: 6px; }
.fo-nav .fo-icon-btn { width: 34px; height: 34px; }

/* ── case study: chat bubbles + pull quote ─────────────────────── */
/* The questions a customer actually asks, set as the hero's chat blobs. */
.fo-ac__asks { margin: 4px 0 22px; padding: 0; list-style: none;
  display: flex; flex-direction: column; align-items: flex-start; gap: 9px; }
.fo-ac__asks li { max-width: 82%; }
.fo-ac__asks li span {
  display: inline-block; padding: 13px 22px;
  background: var(--bg-white); border-radius: var(--r-bubble);
  box-shadow: 0 2px 10px -6px rgba(23,23,28,.25);
  font-size: 15.5px; line-height: 1.5; color: var(--ink);
}
.fo-ac__asks li:nth-child(even) { padding-left: 26px; }

/* one line, given room to land */
.fo-ac__pull {
  margin: 26px 0; padding: 0 0 0 20px;
  border-left: 2px solid var(--vc);
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(19px, 1.75vw, 26px); line-height: 1.34;
  letter-spacing: -.026em; color: var(--ink); max-width: 30ch;
}
/* body copy: a touch larger, a slightly tighter measure */
.fo-ac__body { font-size: 17px; line-height: 1.75; max-width: 64ch; }
.fo-ac__list li { font-size: 17px; }
@media (max-width: 640px) {
  .fo-ac__asks li { max-width: 100%; }
  .fo-ac__asks li:nth-child(even) { padding-left: 0; }
  .fo-ac__body, .fo-ac__list li { font-size: 16px; }
}

/* ── theme switch ─────────────────────────────────────────────────
   Was a unicode half-circle swapped on click. Now a real switch: both
   destinations visible, the knob shows which one you're in. */
.fo-toggle { padding: 0; border: 0; background: none; cursor: pointer; line-height: 0;
  border-radius: 999px; -webkit-tap-highlight-color: transparent; }
.fo-toggle__track {
  position: relative; display: inline-flex; align-items: center; justify-content: space-between;
  width: 60px; height: 32px; padding: 0 8px; border-radius: 999px;
  border: 1px solid var(--line);
  background: rgb(var(--ink-rgb) / .05);
  transition: background .28s ease, border-color .28s ease;
}
.fo-toggle:hover .fo-toggle__track { border-color: rgb(var(--ink-rgb) / .34); }
.fo-toggle:focus-visible { outline: none; }
.fo-toggle:focus-visible .fo-toggle__track { box-shadow: 0 0 0 3px rgb(var(--ink-rgb) / .16); }
.fo-toggle__ico { position: relative; z-index: 2; width: 14px; height: 14px; flex: none;
  color: rgb(var(--ink-rgb) / .40); transition: color .28s ease; }
.fo-toggle.is-dark .fo-toggle__ico--sun { color: rgb(var(--ink-rgb) / .34); }
.fo-toggle:not(.is-dark) .fo-toggle__ico--sun { color: #fff; }
.fo-toggle:not(.is-dark) .fo-toggle__ico--moon { color: rgb(var(--ink-rgb) / .34); }
.fo-toggle.is-dark .fo-toggle__ico--moon { color: #fff; }
.fo-toggle__knob {
  position: absolute; z-index: 1; top: 3px; left: 3px;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--brand);
  box-shadow: 0 4px 12px -5px rgba(23,23,28,.55);
  transition: transform .34s cubic-bezier(.4,1.3,.5,1);
}
.fo-toggle.is-dark .fo-toggle__knob { transform: translateX(28px); }
@media (prefers-reduced-motion: reduce) { .fo-toggle__knob { transition: none; } }

/* ── project switcher as a bottom dock ────────────────────────────
   Was a static bar under the nav, in flow, and hidden below 1000px.
   Fixed to the bottom it stays reachable the whole way down a study,
   and it can finally exist on mobile, where it never used to.
   The pill indicator still measures offsetLeft/offsetWidth against
   .fo-seg, which stays the offsetParent, so that maths is untouched. */
.fo-seg__wrap {
  position: fixed; z-index: 640;
  left: 50%; bottom: clamp(14px, 2.2vh, 24px);
  transform: translateX(-50%);
  width: max-content; max-width: calc(100vw - 24px);
  pointer-events: none;
}
.fo-seg {
  display: inline-flex !important;             /* beats the <1000px hide */
  margin: 0; pointer-events: auto; max-width: 100%;
  background: rgb(var(--paper-rgb) / .82);
  backdrop-filter: blur(24px) saturate(1.6);
  -webkit-backdrop-filter: blur(24px) saturate(1.6);
  border-color: var(--line-2);
  box-shadow: 0 20px 46px -24px rgba(13,13,16,.55), 0 1px 3px rgba(13,13,16,.07);
}
/* Below this the labels would run into the back/next controls parked at
   bottom-right, so the dock drops to logos only. */
@media (max-width: 1180px) {
  .fo-seg__b span { display: none; }
  .fo-seg__b { padding: 9px 12px; }
  .fo-seg__b img { width: 20px; height: 20px; }
}
@media (max-width: 480px) {
  .fo-seg { padding: 3px; border-radius: 16px; }
  .fo-seg__b { padding: 8px 10px; }
}

/* The dock floats over content, so it has to actually occlude it — .82 let
   headings read straight through on small screens where the page scrolls
   under it. Also reserve room so the last of the content can clear it. */
.fo-seg {
  background: rgb(var(--paper-rgb) / .93);
  box-shadow: 0 20px 46px -22px rgba(13,13,16,.6),
              0 0 0 1px rgb(var(--ink-rgb) / .05);
}
@supports not (backdrop-filter: blur(1px)) {
  .fo-seg { background: rgb(var(--paper-rgb) / .99); }
}
@media (max-width: 1000px) {
  body.fo-inner .fo-page { padding-bottom: 96px; }
}

/* Screens were taking the full panel width (~1060px at 1280) while the body
   copy sits at 64ch (~686px), so every image shouted over the text around it.
   Capped a little wider than the measure, which keeps them dominant without
   breaking the column. */
.fo-ac__shot, .fo-proto { max-width: 760px; }
.fo-ac__shot img { width: 100%; height: auto; }
@media (min-width: 1500px) {
  .fo-ac__shot, .fo-proto { max-width: 820px; }
}

/* Centre the reading column on wide screens.
   The study cell is ~1007px but its contents were capped at 686 (text) and
   760 (screens) and left-aligned, so every bit of slack collected on the
   right. Cap the column itself and centre it, then let text and screens
   share that one measure so they align to the same edges. */
.fo-ac__study { max-width: 760px; margin-inline: auto; }
.fo-ac__study .fo-ac__body,
.fo-ac__study .fo-ac__list { max-width: none; }
.fo-ac__study .fo-ac__shot,
.fo-ac__study .fo-proto { max-width: 100%; }
@media (min-width: 1500px) {
  .fo-ac__study { max-width: 820px; }
}

/* The nav Contact pill kept the global .fo-btn size (42px tall, 14px text) in
   a 54px capsule, so it towered over the 32px switch and the 12.5px links.
   Scoped down to sit level with them. */
.fo-nav .fo-btn { height: 32px; padding: 0 15px; font-size: 12.5px; gap: 6px; }

/* Links pill down to 32px so it sits level with the switch and Contact.
   The sliding indicator is pinned to the container's padding, so it has to
   come in with it or it overhangs the new height. */
.fo-nav .fo-nav__links { padding: 2px; }
.fo-nav .fo-nav__links a { padding: 3px 13px; }
.fo-nav .fo-nav__ind { top: 2px; bottom: 2px; }

/* The stage started 14px from the top while the fixed nav runs to ~66px, so
   the project header and the closed columns' spine logos sat behind it.
   Derive the offset from the nav's own geometry (its top clamp + its 46px
   height + a gap) and take the same amount off the height, so the bottom
   edge — and the room the dock needs below it — is unchanged. */
@media (min-width: 1001px) {
  .fo-ac {
    --ac-top: calc(clamp(14px, 2.2vh, 22px) + 46px + 26px);
    margin-top: var(--ac-top);
    height: calc(100vh - var(--ac-top) - 114px);
  }
}

/* Same clearance on the stacked layout. The nav is taller here (the burger
   keeps it at ~54px), so 84px left only 13px of air under it. Height is
   auto below 1000px, so nothing needs compensating at the bottom. */
@media (max-width: 1000px) {
  .fo-ac { margin-top: calc(clamp(14px, 2.2vh, 22px) + 54px + 26px); }
}

/* Mobile accordion: the spine is a rotated vertical rail on desktop, but it
   stacks into a horizontal row here — directly above the panel's own header.
   That made the open project announce its logo and name twice in a row.
   Hide the spine on the open one; its header (with the close control) is the
   identity. Closed projects keep their row, which is what you tap. */
@media (max-width: 1000px) {
  .fo-ac__col.is-open > .fo-ac__spine { display: none; }
  .fo-ac__col.is-open { border-bottom: 1px solid var(--line-2); }
  .fo-ac__col:not(.is-open) > .fo-ac__spine { cursor: pointer; }
}

@media (max-width: 1000px) {
  /* Pin the open project's header so its name and the close control stay
     reachable through a long study — .fo-ac__col is overflow:hidden, so it
     becomes the containing block and the header releases at that project's
     end rather than riding over the next one. */
  .fo-ac__col.is-open .fo-ac__head {
    position: sticky;
    top: calc(clamp(14px, 2.2vh, 22px) + 54px + 6px);
    z-index: 20;
    padding-top: 10px; padding-bottom: 12px;
    background: rgb(var(--paper-rgb) / .95);
    backdrop-filter: blur(18px) saturate(1.5);
    -webkit-backdrop-filter: blur(18px) saturate(1.5);
  }
  /* Contact already sits in the menu sheet here, so the nav copy is a
     duplicate taking room in a cramped bar. */
  .fo-nav .fo-btn { display: none; }
}

@media (max-width: 1000px) {
  /* overflow:hidden makes .fo-ac__col a scroll container that never scrolls,
     so a sticky child sticks to it instead of the page and never engages.
     The clipping is only needed for the desktop accordion. */
  .fo-ac__col { overflow: visible; }
}

/* Some sources are genuinely small (marketing-site UI fragments). Cap them at
   their own size rather than blowing them up to the column width. */
.fo-ac__study .fo-ac__shot--sm { max-width: 430px; margin-inline: auto; }

/* ── product tabs inside one case study ───────────────────────────
   Aether was four separate products, so the study is four studies and
   only one is on screen at a time. The bar sticks to the top of the
   study's own scroller so you can switch without scrolling back. */
.fo-tabs {
  position: sticky; top: 0; z-index: 12;
  display: flex; flex-wrap: wrap; gap: 2px;
  margin: 20px 0 4px; padding: 5px;
  border: 1px solid var(--line-2); border-radius: 999px;
  background: rgb(var(--paper-rgb) / .92);
  backdrop-filter: blur(18px) saturate(1.5);
  -webkit-backdrop-filter: blur(18px) saturate(1.5);
}
.fo-tabs__b {
  flex: 1 1 auto; display: inline-flex; align-items: baseline; justify-content: center; gap: 7px;
  padding: 8px 14px; border: 0; border-radius: 999px; cursor: pointer;
  background: none; font: inherit; font-size: 13px; color: rgb(var(--ink-rgb) / .55);
  white-space: nowrap; transition: background .18s ease, color .18s ease;
}
.fo-tabs__b i { font-style: normal; font-size: 10px; letter-spacing: .1em; opacity: .75; }
.fo-tabs__b:hover { color: rgb(var(--ink-rgb) / .85); background: rgb(var(--ink-rgb) / .05); }
.fo-tabs__b.is-on { color: var(--ink); font-weight: 600; background: rgb(var(--ink-rgb) / .08); }
.fo-tabs__b.is-on i { color: var(--vc); opacity: 1; }

.fo-prod[hidden] { display: none; }
.fo-prod__head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  margin: 26px 0 18px; padding-top: 20px; border-top: 2px solid var(--vc); }
.fo-prod__head i { font-style: normal; font-size: 12px; letter-spacing: .12em; color: var(--vc); }
.fo-prod__head h4 { margin: 0; font-family: var(--font-display); font-weight: 800;
  font-size: clamp(21px, 2vw, 30px); letter-spacing: -.03em; color: var(--ink); }
.fo-prod__head p { margin: 0; font-size: 14px; color: rgb(var(--ink-rgb) / .6); }
@media (max-width: 640px) {
  /* On a phone, wrapping squashed five tabs into a two-column block. Run them
     as one horizontal scroller instead — smaller type, no wrap, no scrollbar. */
  .fo-tabs {
    flex-wrap: nowrap; min-width: 0;
    overflow-x: auto; overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity; scroll-padding-inline: 6px;
    scrollbar-width: none; -ms-overflow-style: none;
  }
  .fo-tabs::-webkit-scrollbar { width: 0; height: 0; display: none; }
  .fo-tabs__b {
    flex: 0 0 auto; scroll-snap-align: start;
    font-size: 11.5px; padding: 7px 12px; gap: 5px;
  }
  .fo-tabs__b i { font-size: 9px; }
  /* the study is a grid item; grid items default to min-width:auto, so the
     no-wrap tab row pushed the whole column past the track and gave the page
     a horizontal scrollbar. Let it shrink so overflow-x on .fo-tabs applies. */
  /* the study carries max-width:760px globally; on a phone that let the
     no-wrap tab row push it past its grid track. Clamp it to the track. */
  .fo-ac__study { min-width: 0; max-width: 100%; }
}


/* The burger kept its original 40px while everything else in the capsule came
   down to 32px, so on mobile it sat taller than the switch beside it. */
.fo-nav .fo-burger { width: 32px; height: 32px; }
.fo-nav .fo-burger i { width: 14px; }
.fo-nav .fo-burger i:nth-child(1) { transform: translate(-50%, calc(-50% - 4px)); }
.fo-nav .fo-burger i:nth-child(2) { transform: translate(-50%, calc(-50% + 4px)); }
body.is-menu .fo-nav .fo-burger i:nth-child(1) { transform: translate(-50%, -50%) rotate(45deg); }
body.is-menu .fo-nav .fo-burger i:nth-child(2) { transform: translate(-50%, -50%) rotate(-45deg); }

/* Last project: desktop must keep a column open so it wraps to the first;
   mobile can genuinely close, so it gets a different card. Only one shows. */
.fo-ac__next--end { display: none; }
@media (max-width: 1000px) {
  .fo-ac__next--wrap { display: none; }
  .fo-ac__next--end { display: block; }
}


/* ── about hero fixes ──────────────────────────────────────────────
   1. The outline surname sat at .34 alpha, which reads as a rendering
      fault rather than a deliberate outline. The gradient only fills on
      hover, so on touch it never resolves at all — give it a floor. */
.fo-phead__last { -webkit-text-stroke-width: 2px; -webkit-text-stroke-color: rgb(var(--ink-rgb) / .55); }
@media (hover: none) {
  .fo-phead__last { background-size: 100% 100%; -webkit-text-stroke-color: transparent; }
}
/* 2. The name spans the full 1180px while the copy under it sat at 640px,
      leaving ~600px of dead space to its right. Put the roles and the
      paragraph side by side so the block fills the width it declares. */
@media (min-width: 1000px) {
  .fo-phead .fo-wrap {
    display: grid;
    grid-template-columns: minmax(0, 40ch) minmax(0, 1fr);
    column-gap: clamp(32px, 4vw, 72px);
    align-items: start;
  }
  .fo-phead .fo-presence, .fo-phead__h { grid-column: 1 / -1; }
  .fo-roles { grid-column: 1; max-width: none; margin-top: 34px; }
  .fo-phead__sub { grid-column: 2; max-width: 54ch; margin-top: 34px; }
}
/* 3. The status line is the only moving part up there; at .62 on near-black
      it disappeared next to a solid coral pill. */
.fo-presence__status { color: rgb(var(--ink-rgb) / .78); }

/* ── about hero: the portrait is the hero ──────────────────────────
   Centred, full-height, with the name set over the picture rather than
   beside it. Replaces the left-aligned name + paragraph arrangement. */
.fo-phead--portrait {
  position: relative; overflow: hidden;
  min-height: min(94vh, 940px);
  display: grid; align-content: center;
  text-align: center;
  padding: clamp(120px, 15vh, 190px) 0 clamp(46px, 6vw, 78px);
}
.fo-phead__bg {
  position: absolute; left: 50%; top: 46%;
  transform: translate(-50%, -50%);
  width: min(50vw, 540px); aspect-ratio: 1297 / 1800;
  background: url("/assets/img/esther.jpg") center 14% / cover no-repeat;
  /* was grayscale(1) at .42 — she was effectively invisible, and this is now
     the only photo on the page. Keep a light desaturation so the name still
     reads over the shoulders, but let the face be a face. */
  filter: saturate(1) contrast(1.04);
  opacity: .92;
  -webkit-mask-image: radial-gradient(ellipse 66% 58% at 50% 34%, #000 62%, transparent 88%);
  mask-image: radial-gradient(ellipse 66% 58% at 50% 34%, #000 62%, transparent 88%);
  pointer-events: none;
}
.fo-phead--portrait .fo-wrap { position: relative; z-index: 1; }
.fo-phead--portrait .fo-phead__h { margin: clamp(150px, 24vh, 260px) 0 0; }
.fo-phead--portrait .fo-phead__h span { display: block; }
/* the solid given name sits over the face; the outlined surname crosses it */
.fo-phead--portrait .fo-phead__last { -webkit-text-stroke-color: rgb(var(--ink-rgb) / .68); }
.fo-phead--portrait .fo-roles {
  justify-content: center; max-width: none;
  margin: 30px auto 0; color: rgb(var(--ink-rgb) / .72);
}
/* the two-column roles/sub split is moot now the paragraph is gone */
@media (min-width: 1000px) {
  .fo-phead--portrait .fo-wrap { display: block; }
}
@media (max-width: 700px) {
  .fo-phead__bg { width: min(78vw, 400px); }   /* keep desktop's .92 — .34 washed the face out */
  .fo-phead--portrait { min-height: 84vh; }
}

/* ── about: one centred column, set in Fraunces ────────────────────
   The portrait moved up into the hero, so the second copy of it below
   was a repeat. With the art gone the two-column grid has nothing to
   balance, so the prose becomes a single centred measure. */
.fo-ab { display: block; }
.fo-ab__body { max-width: 60ch; margin-inline: auto; text-align: center; }
.fo-ab__lead {
  font-family: var(--font-serif);
  font-weight: 300;
  font-size: clamp(18px, 1.9vw, 24px);
  line-height: 1.62;
  letter-spacing: -.006em;
  max-width: none;
  margin: 0 0 1.1em;
  color: rgb(var(--ink-rgb) / .78);
  font-variation-settings: "SOFT" 40, "WONK" 1;
}
.fo-ab__lead:first-child { font-size: clamp(21px, 2.3vw, 30px); color: var(--ink); }
.fo-ab__lead:last-child { margin-bottom: 0; }
.fo-ab__lead b { font-weight: 600; color: var(--ink); }
.fo-ab__lead em { font-style: italic; color: var(--ink); }
@media (max-width: 700px) {
  .fo-ab__body { text-align: left; }
}

/* link inside the about prose */
.fo-ab__link { color: var(--ink); text-decoration: none; box-shadow: inset 0 -1px 0 rgb(var(--ink-rgb) / .32); transition: box-shadow .2s ease, color .2s ease; }
.fo-ab__link:hover { box-shadow: inset 0 -1px 0 var(--coral); color: var(--coral); }
.fo-ab__link i { font-style: normal; font-size: .82em; }

/* ── timeline: the visual carries the year, not the paragraph ──────
   The cards now carry the roles themselves, so the old one-word visual
   block is gone; what's left is the type sizing. */
.fo-tl__title { font-size: 17px; margin-bottom: 12px; }
.fo-tl__card p { font-size: 13px; line-height: 1.5; }

/* Visually hidden, still read by assistive tech and search engines. */
.fo-vh {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* About hero legibility.
   The given name sits directly over her white shirt, so in dark mode it was
   white-on-white. A glow in the *paper* colour separates it either way:
   near-white behind dark text in light mode, near-black behind light text in
   dark mode. The surname also overran 390px at its old minimum size. */
.fo-phead--portrait .fo-phead__h span {
  /* one wide, soft glow only. A tight second shadow hugged the glyphs and
     dulled light text against a dark page. */
  text-shadow: 0 2px 30px rgb(var(--paper-rgb) / .55);
}
.fo-phead--portrait .fo-phead__last { text-shadow: none; }

/* ══ CURSOR ══════════════════════════════════════════════════════
   One object, three states.
   · at rest   — a 6px dot
   · scrolling — a ring reporting scroll depth, and the section names itself
   · hovering  — hands over to a box that takes the target's shape,
                 with the action tagged on its corner
   Nothing loops, nothing is on screen permanently, and it disappears
   entirely on touch and under prefers-reduced-motion. */
.fo-cur { position: fixed; inset: 0 auto auto 0; z-index: 9000; pointer-events: none;
  opacity: 0; transition: opacity .25s ease; }
body.cur-live .fo-cur { opacity: 1; }
/* The native arrow stays. Hiding it made every follower frame of lag read
   as the pointer itself lagging; with the real arrow visible the ring is
   an overlay and can sit a fraction behind without anyone minding. */
body.cur-live .fo-cur__core { display: none; }   /* the arrow is the point now */
.fo-cur > * { position: absolute; top: 0; left: 0; will-change: transform; }

.fo-cur__free { width: 36px; height: 36px; margin: -18px 0 0 -18px; display: grid; place-items: center;
  transition: opacity .2s ease, transform .3s cubic-bezier(.22,1,.28,1); }
body.cur-hot .fo-cur__free { opacity: 0; transform: scale(.6); }
.fo-cur__core { width: 6px; height: 6px; border-radius: 50%; background: rgb(var(--ink-rgb));
  transition: transform .3s cubic-bezier(.16,1.2,.3,1); }
body.cur-scrolling .fo-cur__core { transform: scale(.5); }

/* ring: only while scrolling */
.fo-cur__ring { position: absolute; inset: 0; transform: rotate(-90deg);
  opacity: 0; transition: opacity .3s ease; }
body.cur-scrolling .fo-cur__ring { opacity: 1; }
.fo-cur__ring circle { fill: none; stroke-width: 1.5; }
.fo-cur__track { stroke: rgb(var(--ink-rgb) / .28); }
.fo-cur__fill { stroke: var(--coral); stroke-linecap: round;
  transition: stroke-dashoffset .12s linear; }

.fo-cur__sect { position: absolute; left: 50%; top: calc(100% + 9px);
  transform: translateX(-50%) translateY(5px);
  background: rgb(var(--ink-rgb)); color: rgb(var(--paper-rgb));
  font-size: 11px; font-weight: 650; letter-spacing: .02em; padding: 4px 11px;
  border-radius: 999px; white-space: nowrap; opacity: 0;
  transition: opacity .2s ease, transform .3s cubic-bezier(.16,1.2,.3,1); }
body.cur-scrolling .fo-cur__sect { opacity: 1; transform: translateX(-50%) translateY(0); }

.fo-cur__box { opacity: 0; will-change: transform, width, height;
  transition: opacity .2s ease, border-radius .3s cubic-bezier(.22,1,.28,1); }
body.cur-hot .fo-cur__box { opacity: 1; }
.fo-cur__edge { position: absolute; inset: 0; border-radius: inherit;
  border: 1.5px solid rgb(var(--ink-rgb) / .62); }
.fo-cur__tag { position: absolute; right: -6px; bottom: -13px; background: var(--coral); color: #0b0b0f;
  font-size: 11.5px; font-weight: 650; padding: 5px 12px; border-radius: 999px; white-space: nowrap;
  opacity: 0; transform: translateY(5px) rotate(0);
  transition: opacity .22s ease .04s, transform .34s cubic-bezier(.16,1.2,.3,1) .04s; }
body.cur-hot .fo-cur__tag { opacity: 1; transform: translateY(0) rotate(-2.5deg); }

@media (hover: none), (pointer: coarse) {
  .fo-cur { display: none !important; }
  body, body a, body button { cursor: auto !important; }
}
@media (prefers-reduced-motion: reduce) {
  .fo-cur { display: none !important; }
  body, body a, body button, body [data-cursor] { cursor: auto !important; }
}

/* About hero: the given name carries the page; the name she goes by sits
   under it as a quiet line rather than a second display-size word. */
.fo-phead--portrait .fo-phead__h .fo-phead__aka {
  display: block;
  margin-top: clamp(10px, 1.6vh, 18px);
  font-family: var(--font-body);
  font-size: clamp(13px, 1.15vw, 16px);
  font-weight: 400;
  letter-spacing: .04em;
  line-height: 1.4;
  color: rgb(var(--ink-rgb) / .62);
  text-transform: none;
}


/* the lead-in sits above the name, so its spacing mirrors the line below */
.fo-phead--portrait .fo-phead__h .fo-phead__aka--lead {
  margin-top: 0;
  margin-bottom: clamp(4px, 0.8vh, 10px);
}

/* Connectors hug the name they introduce, so the block reads as one sentence
   rather than four stacked lines. */
.fo-phead--portrait .fo-phead__h .fo-phead__aka {
  margin-top: clamp(8px, 1.2vh, 14px);
  margin-bottom: clamp(2px, 0.4vh, 6px);
}
.fo-phead--portrait .fo-phead__h .fo-phead__aka--lead { margin-top: 0; }

/* ── About hero: two names as one mark ─────────────────────────────
   The given name and the one she goes by are set at the same display
   size and pulled tight, so they read as a single lockup. The phrase
   between them sits in a gap in a hairline rule — an editorial device
   rather than another stacked line of text. */
.fo-phead--portrait .fo-phead__h .fo-phead__hi {
  display: block; margin: 0 0 2px;
  font-family: var(--font-body); font-weight: 400;
  font-size: clamp(12px, 1vw, 14px); letter-spacing: .16em;
  text-transform: uppercase; color: rgb(var(--ink-rgb) / .5);
}
.fo-phead--portrait .fo-phead__h .fo-phead__given { display: block; }
.fo-phead--portrait .fo-phead__h .fo-phead__rule {
  display: flex; align-items: center; gap: 14px;
  max-width: 34ch; margin: clamp(6px, 1vh, 12px) auto;
}
.fo-phead--portrait .fo-phead__h .fo-phead__rule::before,
.fo-phead--portrait .fo-phead__h .fo-phead__rule::after {
  content: ""; flex: 1 1 auto; height: 1px;
  background: rgb(var(--ink-rgb) / .28);
}
.fo-phead--portrait .fo-phead__h .fo-phead__rule i {
  flex: none; font-style: normal;
  font-family: var(--font-body); font-weight: 400;
  font-size: clamp(11px, .95vw, 13px); letter-spacing: .14em;
  text-transform: uppercase; color: rgb(var(--ink-rgb) / .55);
  white-space: nowrap;
}

/* The connector sits over the photograph, so it needs the same soft
   halo the display names get — and the rule has to be measured in px,
   not ch, which inherits the 46px display font and runs 750px wide. */
.fo-phead--portrait .fo-phead__h .fo-phead__rule {
  max-width: min(420px, 82%);
}
.fo-phead--portrait .fo-phead__h .fo-phead__rule::before,
.fo-phead--portrait .fo-phead__h .fo-phead__rule::after {
  background: rgb(var(--ink-rgb) / .34);
}
.fo-phead--portrait .fo-phead__h .fo-phead__hi,
.fo-phead--portrait .fo-phead__h .fo-phead__rule i {
  color: rgb(var(--ink-rgb) / .74);
  text-shadow: 0 2px 26px rgb(var(--paper-rgb) / .8);
}

/* White type on a white shirt is invisible whatever the opacity, so the
   label rides a small blurred chip on the rule. Built from --paper-rgb,
   so it stays readable when the theme flips. */
.fo-phead--portrait .fo-phead__h .fo-phead__rule i {
  padding: 4px 12px 5px; border-radius: 999px;
  background: rgb(var(--paper-rgb) / .62);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  color: rgb(var(--ink-rgb) / .82); text-shadow: none;
}

/* Real screens inside the showcase card treatments (wipe, fan, loop, shot).
   Keeps the .fo-scr shell so each treatment's own sizing and transforms still
   apply — only the fake body is replaced. */
.fo-proj__media .fo-scr > img {
  display: block; flex: 1 1 auto; min-height: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
}

/* "Hi, I'm" lands on the shirt at mobile widths. A 26px halo is too
   diffuse to separate 12px caps, so pair it with a tight one. Safe here
   because these are small caps, not the display glyphs a tight shadow
   would dull. */
.fo-phead--portrait .fo-phead__h .fo-phead__hi {
  color: rgb(var(--ink-rgb) / .88);
  text-shadow: 0 1px 3px rgb(var(--paper-rgb) / .92),
               0 2px 24px rgb(var(--paper-rgb) / .8);
}

/* ---- case-study figures ---------------------------------------- */
.fo-ac__stats {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px;
  margin: 34px 0 38px; padding: 0;
  background: var(--line); border: 1px solid var(--line); border-radius: 14px;
  overflow: hidden;
}
.fo-ac__stat {
  background: var(--panel); padding: 22px 18px 20px;
}
.fo-ac__stat dt {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(24px, 3.4vw, 34px); line-height: 1;
  letter-spacing: -.03em; color: var(--ink);
}
.fo-ac__stat dd {
  margin: 9px 0 0; font-size: 12.5px; line-height: 1.45; color: var(--faint);
  max-width: 22ch;
}
.fo-ac__stat--tbc dt::after {
  content: "?"; margin-left: .18em; vertical-align: super;
  font-size: .42em; font-weight: 500; color: var(--coral);
}
@media (max-width: 780px) {
  .fo-ac__stats { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 420px) {
  .fo-ac__stats { grid-template-columns: 1fr; }
  .fo-ac__stat { padding: 18px 16px 16px; }
  .fo-ac__stat dd { max-width: none; }
}

/* ── How I got here: notes between the roles ───────────────────────
   The horizontal timeline told the same story as the CV twice over,
   so it's gone. What it was actually good for — the years before the
   first job, and the line about now — survives here as plain rows on
   the same 92px year column the roles use, so one list carries the
   whole arc. Not buttons: there is nothing to open. */
.fo-roles-list .fo-mark {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr);
  gap: 16px; align-items: baseline;
  padding: 17px 4px 17px 0;
  border-bottom: 1px solid var(--line-2);
}
.fo-roles-list .fo-mark__yr {
  font-size: 12.5px; color: var(--faint);
  font-variant-numeric: tabular-nums; letter-spacing: .04em;
}
.fo-roles-list .fo-mark__t {
  margin: 0; font-size: 14.5px; line-height: 1.62; color: var(--muted);
}
.fo-roles-list .fo-mark__t b { color: var(--ink); font-weight: 600; }
.fo-roles-list .fo-mark__t a {
  color: var(--coral); text-decoration: none;
  border-bottom: 1px solid rgb(var(--ink-rgb) / .18);
  white-space: nowrap; transition: border-color .25s ease;
}
.fo-roles-list .fo-mark__t a:hover { border-bottom-color: var(--coral); }

/* the top row is the one thing a visitor most needs to know */
.fo-roles-list .fo-mark--now { padding: 22px 4px 22px 0; }
.fo-roles-list .fo-mark--now .fo-mark__t {
  font-size: clamp(15px, 1.5vw, 16.5px); color: rgb(var(--ink-rgb) / .8);
}

/* a quiet divider, not another entry */
.fo-roles-list .fo-mark--head { border-bottom: 0; padding: 40px 4px 4px 0; }
.fo-roles-list .fo-mark--head .fo-mark__t {
  font-family: var(--font-display); font-weight: 700;
  letter-spacing: -.02em; font-size: 15px; color: var(--faint);
}
.fo-roles-list .fo-mark--last { border-bottom: 0; }

@media (max-width: 820px) {
  .fo-roles-list .fo-mark { grid-template-columns: 72px minmax(0, 1fr); }
}

/* The intro paragraph inside an open role was capped at 62ch while its
   own bullets ran the full width, so it ragged short against them and
   started 16px further left. Align it to the bullet text instead —
   the bullets are left as they were. */
.fo-role__body p { padding-left: 32px; max-width: none; }

/* ── showcase: one card geometry for every treatment ───────────────
   Each treatment had grown its own box (55%/68% wipe+loop, 47%/62%
   fan, a clamp() for the strip, and a duplicated .fo-shot rule that
   put Healthcare at inset 10%/8%). They now share one frame, so the
   card stays the same size and place as you scroll between projects. */
@media (min-width: 1181px) {
  .fo-proj--wipe .fo-pair,
  .fo-proj--loop .fo-frame,
  .fo-proj--fan  .fo-deck,
  .fo-proj--nda  .fo-shot {
    /* Bound the bottom edge, don't fix the height. .fo-proj__body is pinned to the
       panel's bottom and is 163-217px tall depending on how the title wraps, so a
       fixed 62% height put the art's bottom at 74% while the body's top sat at
       68-77% — the art and the copy overlapped. */
    inset: auto; top: 12%; left: 40%; width: 55%;
    /* Reserve for the tallest body, not the average one. A six-line blurb
       measures ~188px and was colliding with the art at 1280x800. */
    height: auto; bottom: clamp(238px, 37%, 292px);
  }
}
/* the filmstrip pans, so its cards are laid out in a rail — but they
   match the single-card treatments in size */
@media (min-width: 1181px) {
  .fo-proj--strip .fo-rail { top: 12%; height: auto; bottom: clamp(238px, 37%, 292px); }
}
.fo-proj--strip .fo-rail .fo-mock {
  /* the other treatments are 55% of a media box that is ~73.6vw wide,
     so 55% x 73.6vw = 40.5vw. Matching it keeps every card identical. */
  width: clamp(320px, 40.5vw, 583px); height: 100%; align-self: stretch;
}
.fo-proj--strip .fo-rail .fo-mock > img {
  flex: 1 1 auto; min-height: 0; height: auto; aspect-ratio: auto;
}
/* Healthcare is no longer under NDA: the veil that greyed the screen
   out, and the lock badge, are both obsolete. */
.fo-proj--nda .fo-veil,
.fo-proj--nda .fo-lock { display: none; }

/* .fo-shot never had a sizing rule of its own — the other treatments get
   theirs from .fo-pair/.fo-deck (inset:0) or .fo-frame (height:100%), so
   this card collapsed to just its chrome bar. */
.fo-proj--nda .fo-shot .fo-scr { position: absolute; inset: 0; }

/* .fo-mock is a <figure>, i.e. display:block — so flex sizing on its image
   did nothing once the aspect-ratio was removed. Make it a column and let
   the image take the remaining height under the chrome. */
.fo-proj--strip .fo-rail .fo-mock { display: flex; flex-direction: column; }
.fo-proj--strip .fo-rail .fo-mock > img {
  flex: 1 1 auto; min-height: 0; width: 100%; height: auto; object-fit: cover;
}

/* ── How I got here: the timeline IS the work history ──────────────
   The scrubbing track now carries the roles themselves, so the cards
   have to hold a role line and its bullets, not one line of vibe.
   Wider, and the fake gradient box is replaced by a plate showing the
   year — with the real company logo where one exists. */
.fo-tl__item { flex: 0 0 clamp(280px, 30vw, 380px); }
.fo-tl__card { padding: 16px; gap: 13px; }


.fo-tl__pts { margin: 0; padding: 0 0 0 17px; }
.fo-tl__pts li {
  font-size: 12.8px; line-height: 1.5; color: var(--on-dark-2);
  padding: 2px 0;
}
.fo-tl__pts li::marker { color: var(--coral); }

/* the years before the first job carry a sentence, not a job */
.fo-tl__item--note .fo-tl__card { background: none; border-style: dashed; }

.fo-tl__say {
  color: var(--coral); text-decoration: none;
  border-bottom: 1px solid rgba(244,244,246,.24);
  white-space: nowrap;
}
.fo-tl__say:hover { border-bottom-color: var(--coral); }

@media (max-width: 700px) {
  .fo-tl__item { flex: 0 0 min(78vw, 320px); }
    }

/* The plate showed the year the giant ghost was already showing, so it's
   gone. Colour rhythm now comes from a strip keyed to the same --vc, and
   the logo — a real asset, where one exists — sits with the name. */
.fo-tl__card {
  position: relative; overflow: hidden;
  padding-top: 20px;
}
.fo-tl__card::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 5px;
  background: linear-gradient(90deg, var(--vc), transparent 88%);
}
.fo-tl__title {
  display: flex; align-items: center; justify-content: center; gap: 8px;
}
.fo-tl__logo {
  width: 22px; height: 22px; border-radius: 6px; object-fit: contain;
  background: rgba(244,244,246,.06); padding: 3px; flex: none;
}
/* the years before the first job are a sentence, not a job */
.fo-tl__item--note .fo-tl__card { background: none; border-style: dashed; }
/* where she is now — a statement, so it gets the most presence */
.fo-tl__item--now .fo-tl__card {
  background: rgba(244,244,246,.07);
  border-color: rgba(244,244,246,.18);
}
.fo-tl__item--now .fo-tl__card p { color: var(--on-dark); font-size: 14px; }

/* ---- case-study video ------------------------------------------- */
.fo-ac__vid { margin: 26px 0 30px; }
.fo-ac__vid video {
  display: block; width: 100%; height: auto;
  border-radius: 12px; border: 1px solid var(--line);
  background: rgb(var(--ink-rgb) / .04);
}
.fo-ac__vid figcaption {
  margin-top: 10px; font-size: 12.5px; line-height: 1.5; color: var(--faint);
}
.fo-ac__vid--amb video { pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  .fo-ac__vid--amb video { animation: none; }
}

/* the illustration on each card — line art, so it inherits the card's
   ink and the year's --vc accent rather than shipping a flat image */
.fo-tl__scene {
  border-radius: 10px; overflow: hidden;
  background: linear-gradient(160deg, rgb(from var(--vc) r g b / .1), rgba(244,244,246,.03));
  color: rgba(244,244,246,.5);
  padding: 6px 2px;
}
@supports not (color: rgb(from red r g b / .1)) {
  .fo-tl__scene { background: rgba(244,244,246,.05); }
}
.fo-tl__art { display: block; width: 100%; height: auto; }

/* Aether — the founding role, so it carries more weight than its neighbours */
.fo-tl__item--key .fo-tl__card {
  background: rgba(244,244,246,.07);
  border-color: rgba(244,244,246,.2);
}

/* ── About: her bio ───────────────────────────────────────────────
   Her text runs long, so the opening and closing lines get weight and
   the middle stays even. The four questions in the second paragraph
   are hers, set in italic so they read as asked rather than stated. */
.fo-ab__body .fo-ab__lead--open {
  font-size: clamp(21px, 2.5vw, 30px); line-height: 1.42;
  color: var(--ink); margin-top: 0;
}
.fo-ab__body .fo-ab__lead--close {
  color: var(--ink);
}
.fo-ab__body .fo-ab__lead i {
  font-style: italic; color: rgb(var(--ink-rgb) / .82);
}

/* The portrait above it is centred, so the column stays centred too —
   .fo-ab__body already sets that, and this block used to override it. */

/* ── Healthcare's title is long enough to wrap the bottom row ──────
   "Internal Healthcare System" is ~795px at the 66px display size, so
   h3 + the 40ch side column can't sit on one line. The body block wraps
   to two rows, doubling its height (116px -> 212px), and because it is
   anchored to the bottom it grows upward into the shared media box,
   which runs to 80%. The other four titles are short, fit on one row,
   and never reach it. Lift this card's screen so it clears the taller
   block at any width, rather than capping her title. */
@media (min-width: 1181px) {
  .fo-proj--nda .fo-shot { top: 6%; left: 44%; width: 52%; height: 58%; }
}
/* Lifting the screen alone wasn't enough: the media box is sized in
   percentages of the viewport, while the title block is a fixed 66px type
   size, so a shorter viewport (1280x800) closed the gap again. Cap the
   title instead, so the bottom row stays one row on every card and the
   block keeps the same height the other four have. */
@media (min-width: 1181px) {
  .fo-proj__body h3 { max-width: 19ch; }
}

/* The size was width-only, so a short viewport (1280x800) left the title
   at full 66px with far less vertical room. Bound it by height too. */
.fo-proj h3 { font-size: clamp(32px, min(5.4vw, 9vh), 66px); }

/* The body column is ~984px wide whatever the viewport (the media box is
   capped), and the 40ch side column takes ~300 of it, so the title only
   ever has ~650px. At 66px this one runs to 778px and pushes the side
   column onto a second row, which is what collided with the screen.
   Shrink this title alone; the other four are short enough to stay full
   size. Two classes because the generic .fo-proj h3 size rule is declared
   later and would otherwise win the tie. */
@media (min-width: 1181px) {
  /* keyed to the title's length, not the old NDA treatment — every card
     is a filmstrip now, so --nda no longer exists to hang this on. */
  .fo-proj.fo-proj--longtitle .fo-proj__body h3 {
    font-size: clamp(28px, min(4.2vw, 7vh), 44px);
  }
}

/* ── Timeline cards: tabs for a year that held more than one role ──── */
.fo-tl__tabs {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding-top: 2px;
}
.fo-tl__tab {
  font-family: inherit; font-size: 11.5px; letter-spacing: .01em;
  padding: 6px 11px; border-radius: var(--r-pill); cursor: pointer;
  background: none; color: var(--on-dark-3);
  border: 1px solid rgba(244,244,246,.16);
  transition: color .2s ease, background .2s ease, border-color .2s ease;
}
.fo-tl__tab:hover { color: var(--on-dark); border-color: rgba(244,244,246,.34); }
.fo-tl__tab.is-on {
  color: var(--black); background: var(--vc); border-color: transparent;
  font-weight: 600;
}
.fo-tl__tab:focus-visible { outline: 2px solid var(--periwinkle); outline-offset: 2px; }
.fo-tl__pane { display: flex; flex-direction: column; gap: 10px; }
.fo-tl__pane[hidden] { display: none; }
.fo-tl__pane .fo-tl__pts { padding-left: 17px; }

/* Her one-line introduction now sits under the name, so this row is a
   sentence rather than a list — the comma/period pseudo-elements and the
   per-item hover that suited three words would both be wrong on it. */
.fo-roles--line { max-width: 46ch; }
.fo-roles--line span::after,
.fo-roles--line::after { content: none; }
.fo-roles--line span:hover { color: inherit; }

/* a merged entry covers two companies, so each keeps its own heading */
.fo-role__body .fo-role__sub {
  margin: 14px 0 2px; padding-left: 32px;
  font-size: 12px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--faint);
}
.fo-role__body .fo-role__sub:first-of-type { margin-top: 8px; }
/* a flex row of chips is the wrong box for one sentence — it becomes a
   single anonymous flex item sized to max-content */
.fo-phead--portrait .fo-roles--line {
  display: block; text-align: center;
  max-width: 42ch; margin-inline: auto;
}
/* a bullet that leads with a product name reads better if the name is ink */
.fo-role__body li b { color: var(--ink); font-weight: 600; }
/* the pre-career row runs to two paragraphs now, so they need a wrapper —
   otherwise the second one lands in the year column on a new grid row */
.fo-roles-list .fo-mark__body { display: flex; flex-direction: column; gap: 11px; }
.fo-roles-list .fo-mark__body .fo-mark__t { margin: 0; }
.fo-roles-list .fo-mark__t a i { font-style: normal; font-size: .85em; }
/* an entry that ends in prose rather than a bullet list has no <ul> to
   supply the closing space */
.fo-role__body > div > p:last-child { padding-bottom: 24px; }
.fo-role__body a {
  color: var(--coral); text-decoration: none;
  border-bottom: 1px solid rgb(var(--ink-rgb) / .2);
  transition: border-color .25s ease;
}
.fo-role__body a:hover { border-bottom-color: var(--coral); }
.fo-role__body a i { font-style: normal; font-size: .85em; }

/* ── Off the clock: a strip that runs on its own ───────────────────
   It used to be a hand-scrolled, drag-to-pan rail. Now it loops by
   itself: the JS appends one copy of the photos, and translating the
   whole strip by exactly its own first half lands back at the start. */
.fo-reel__track.is-running {
  overflow: visible;
  cursor: default;
  scroll-snap-type: none;
  width: max-content;
  animation: fo-reel-run var(--reel-time, 60s) linear infinite;
  will-change: transform;
}
@keyframes fo-reel-run {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(var(--reel-w, 2000px) * -1), 0, 0); }
}
/* stop it so a photo can actually be clicked, and for keyboard users */
.fo-reel__track.is-running:hover,
.fo-reel__track.is-running:focus-within { animation-play-state: paused; }

/* the strip overflows the section on purpose; keep the page from scrolling */
.fo-reel { overflow: hidden; }

/* the dim-the-others effect needs the pointer on a photo, not the strip */
.fo-reel__track.is-running:hover .fo-reel__ph { opacity: .5; }
.fo-reel__track.is-running .fo-reel__ph.is-clone { pointer-events: auto; }

@media (prefers-reduced-motion: reduce) {
  .fo-reel__track { animation: none; }
}

/* ── "Esther" → the alias hangs off it ────────────────────────────
   An inline reveal pushed the rest of the sentence sideways every time
   the pointer crossed the name. This one is absolutely positioned, so
   it costs no layout: the tag swings out above the word and points
   back down at it. */
.fo-aka {
  display: inline-block; position: relative;
  outline: none; cursor: help;
}
.fo-aka b {
  font-weight: 600; color: var(--ink); opacity: .9;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 100% 1px; background-position: 0 100%;
  background-repeat: repeat-x; padding-bottom: 1px;
  transition: color .3s ease, opacity .3s ease;
}
.fo-aka__tag {
  position: absolute; left: 50%; bottom: calc(100% + 11px);
  z-index: 6; pointer-events: none; white-space: nowrap;
  font-family: var(--font-body); font-size: 12px; font-weight: 500;
  letter-spacing: .02em; line-height: 1;
  padding: 7px 12px 8px; border-radius: var(--r-pill);
  background: var(--coral); color: #fff;
  box-shadow: 0 10px 26px rgb(0 0 0 / .3);
  opacity: 0;
  transform: translate(-50%, 8px) rotate(-4deg) scale(.9);
  transform-origin: 50% 120%;
  transition: opacity .24s ease, transform .5s cubic-bezier(.34, 1.4, .64, 1);
}
/* the little nib that ties the tag back to the name */
.fo-aka__tag::after {
  content: ""; position: absolute; top: 100%; left: 50%;
  width: 8px; height: 8px; margin-left: -4px; margin-top: -3px;
  background: var(--coral); border-radius: 1px;
  transform: rotate(45deg);
}
.fo-aka:hover .fo-aka__tag,
.fo-aka:focus .fo-aka__tag,
.fo-aka:focus-visible .fo-aka__tag,
.fo-aka.is-open .fo-aka__tag {
  opacity: 1;
  transform: translate(-50%, 0) rotate(-4deg) scale(1);
}
.fo-aka:hover b, .fo-aka:focus b, .fo-aka.is-open b { opacity: 1; color: var(--coral); }
.fo-aka:focus-visible { outline: 2px solid var(--periwinkle); outline-offset: 3px; border-radius: 3px; }

@media (prefers-reduced-motion: reduce) {
  .fo-aka__tag { transition: opacity .2s ease; transform: translate(-50%, 0) rotate(-4deg); }
}
/* The four spans are chosen line breaks for a wide screen. At phone
   widths they are longer than the column, so each one wraps again and
   leaves orphans — better to let the sentence flow as one block. */
@media (max-width: 700px) {
  .fo-claim--long { max-width: 22ch; }
  .fo-claim--long span { display: inline; }
  .fo-claim--long span::after { content: " "; }
  .fo-claim--long span:last-child::after { content: none; }
}

/* ── sign-off spacing ──────────────────────────────────────────────
   The block sat 24px under the work CTA and 230px above the footer
   band — jammed against one and adrift from the other. The inline
   padding-top:0 on the section was the cause; balance both sides
   against the padding its neighbours already contribute (the CTA
   adds 24 below, the footer 90 above). */
.fo-post-block { padding-block: clamp(56px, 8vw, 110px) 0; }
.fo-bubbles { display: flex; flex-direction: column; align-items: flex-start; }
.fo-bubbles .fo-msg--out { align-self: flex-end; margin-top: 12px; }

/* ── Skills & Expertise: heading out of the card ───────────────────
   Its sibling Education heads its column with a plain .fo-cvhead, so
   that heading sat on the page spine while this one sat inside the
   card, inset by the card's own 34px padding. Both columns now open
   with a heading on the same line. */
#fo-skills { min-height: 0; }
#fo-skills .fo-bcard__sub { margin-top: 0; }



/* ── Skills + Education on one panel ───────────────────────────────
   The dark card made Skills read as a separate object from Education
   beside it. Both columns now sit on a single panel so the section
   reads as one block.

   This was built fixed-light, which left it white on a dark page.
   It follows the theme now: every colour comes from the channel
   tokens, so the panel inverts with everything else. */
.fo-cvpanel {
  --p-ink:   var(--ink);
  --p-ink-2: var(--muted);
  --p-line:  var(--line-2);
  background: var(--bg-raise); color: var(--p-ink);
  border: 1px solid var(--p-line);
  border-radius: var(--r-md);
  padding: clamp(24px, 3.2vw, 46px);
}
.fo-cvpanel h2,
.fo-cvpanel .fo-ruled b { color: var(--p-ink); }
.fo-cvpanel .fo-bcard__sub,
.fo-cvpanel .fo-bcard__label,
.fo-cvpanel .fo-cvhead__hint,
.fo-cvpanel .fo-ruled span { color: var(--p-ink-2); }
.fo-cvpanel .fo-ruled > div { border-color: var(--p-line); }

/* Skills is no longer a card of its own — it's a column of the panel. */
.fo-cvpanel #fo-skills {
  background: none; border: 0; padding: 0; min-height: 0;
  color: var(--p-ink);
}
.fo-cvpanel #fo-skills::before { display: none; }
.fo-cvpanel .fo-marq { margin: 0; }
/* the rows scroll, so they get cut at the column edge. On the dark card
   that clip read as the card's own edge; on the panel it reads as a bug,
   so fade the last stretch instead. */
.fo-cvpanel .fo-marq {
  -webkit-mask-image: linear-gradient(to right, #000 76%, transparent 99%);
          mask-image: linear-gradient(to right, #000 76%, transparent 99%);
}
@media (prefers-reduced-motion: reduce) {
  /* rows don't animate, so nothing is being cut off — drop the fade */
  .fo-cvpanel .fo-marq { -webkit-mask-image: none; mask-image: none; }
}

/* neutral pills, no accents */
.fo-cvpanel .fo-marq__row span {
  color: var(--p-ink);
  background: rgb(var(--ink-rgb) / .045);
  border: 1px solid var(--p-line);
}
.fo-cvpanel .fo-marq__row span:hover,
.fo-cvpanel .fo-marq__row span:focus-visible {
  background: rgb(var(--ink-rgb) / .09);
  border-color: rgb(var(--ink-rgb) / .26);
  color: var(--p-ink);
}

/* ── Skills marquee: stop it widening the page ─────────────────────
   .fo-marq__row is width:max-content and the script doubles it until it
   can loop, so it runs to several thousand pixels. .fo-marq clips it,
   but a grid item defaults to min-width:auto, so that huge min-content
   width still propagated up and gave the whole page a horizontal
   scrollbar. Not introduced here — it was masked because the earlier
   overflow checks excluded .fo-marq by name. */
.fo-cvsplit > * { min-width: 0; }
.fo-bcard { min-width: 0; }
.fo-marq { min-width: 0; }

/* ── Healthcare: hover blur + work-in-progress gate ────────────────
   The study is not ready to read, so its spine on the work page says
   so before the click rather than after it. */
.fo-ac__col--wip .fo-ac__spine__logo,
.fo-ac__col--wip .fo-ac__spine__name,
.fo-ac__col--wip .fo-ac__spine__n,
.fo-ac__col--wip .fo-ac__spine__chp {
  transition: filter .45s cubic-bezier(.16,1,.3,1), opacity .4s ease;
}
.fo-ac__col--wip .fo-ac__spine:hover .fo-ac__spine__logo,
.fo-ac__col--wip .fo-ac__spine:hover .fo-ac__spine__name,
.fo-ac__col--wip .fo-ac__spine:hover .fo-ac__spine__n,
.fo-ac__col--wip .fo-ac__spine:hover .fo-ac__spine__chp,
.fo-ac__col--wip .fo-ac__spine:focus-visible .fo-ac__spine__logo,
.fo-ac__col--wip .fo-ac__spine:focus-visible .fo-ac__spine__name,
.fo-ac__col--wip .fo-ac__spine:focus-visible .fo-ac__spine__n,
.fo-ac__col--wip .fo-ac__spine:focus-visible .fo-ac__spine__chp {
  filter: blur(4px); opacity: .5;
}
.fo-ac__spine__wip {
  position: absolute; z-index: 4; left: 50%; top: 50%;
  transform: translate(-50%, -50%) scale(.96);
  display: inline-flex; align-items: center; white-space: nowrap;
  padding: 9px 16px; border-radius: var(--r-pill);
  font-family: var(--font-body); font-size: 12.5px; color: var(--ink);
  background: rgb(var(--paper-rgb) / .86); border: 1px solid var(--line-2);
  backdrop-filter: blur(10px) saturate(1.4);
  -webkit-backdrop-filter: blur(10px) saturate(1.4);
  opacity: 0; pointer-events: none;
  transition: opacity .35s ease, transform .45s cubic-bezier(.16,1,.3,1);
}
.fo-ac__col--wip .fo-ac__spine:hover .fo-ac__spine__wip,
.fo-ac__col--wip .fo-ac__spine:focus-visible .fo-ac__spine__wip {
  opacity: 1; transform: translate(-50%, -50%) scale(1);
}
/* the spine is a vertical rail on desktop, so the chip rides with it */
@media (min-width: 1001px) {
  .fo-ac__spine__wip { writing-mode: vertical-rl; padding: 16px 9px; }
}

/* ── in-progress cover, inside the panel ───────────────────────────
   The lede and the product tabs stay readable; from the first product
   panel down the content is blurred and covered by the card, so the
   shape of what is coming is visible without pretending it is ready. */
.fo-wipwrap { position: relative; margin-top: 8px; }
.fo-wipwrap__under {
  filter: blur(7px) saturate(.72); opacity: .5;
  pointer-events: none; user-select: none;
  max-height: 560px; overflow: hidden;
  /* fade the bottom so the clip does not read as a hard cut */
  -webkit-mask-image: linear-gradient(#000 58%, transparent 97%);
          mask-image: linear-gradient(#000 58%, transparent 97%);
}
.fo-wip {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; text-align: center;
  padding: clamp(20px, 3vw, 34px);
}
.fo-wip__art { display: block; width: 92px; height: auto; margin: 0 auto 18px; }
.fo-wip__wood   { fill: url(#wipWood); }
.fo-wip__bulb   { fill: rgb(var(--paper-rgb) / .5); stroke: rgb(var(--ink-rgb) / .22); stroke-width: 1.4; }
.fo-wip__gloss  { fill: url(#wipGlass); stroke: none; }
.fo-wip__shadow { fill: rgb(var(--ink-rgb) / .16); }
.fo-wip__mound  { opacity: .95; }
.fo-wip__stream { stroke: #e6a862; stroke-width: 2.4; stroke-linecap: round;
  stroke-dasharray: 3 7; animation: wip-stream 1.1s linear infinite; }
.fo-wip__grain  { fill: #e6a862; }
.fo-wip__grain--a { animation: wip-grain 1.5s linear infinite; }
.fo-wip__grain--b { animation: wip-grain 1.5s linear .75s infinite; }
/* A real hourglass does not empty while you look at it: the stream runs
   but the level barely moves. 10 minutes per turn, near-linear. */
.fo-wip__sandtop { animation: wip-drain 600s linear infinite; }
.fo-wip__sandbot, .fo-wip__mound { animation: wip-fill 600s linear infinite; }
@keyframes wip-stream { to { stroke-dashoffset: -10; } }
@keyframes wip-grain  { 0% { transform: translateY(-12px); opacity: 0; }
                        20%,80% { opacity: 1; }
                        100% { transform: translateY(44px); opacity: 0; } }
@keyframes wip-drain  { 0% { transform: translateY(0); } 97%,100% { transform: translateY(66px); } }
@keyframes wip-fill   { 0% { transform: translateY(0); } 97%,100% { transform: translateY(-44px); } }
.fo-wip__t {
  margin: 0 0 10px; font-family: var(--font-display); font-weight: 700;
  font-size: clamp(19px, 2.3vw, 23px); letter-spacing: -.02em; color: var(--ink);
}
.fo-wip__p { margin: 0; max-width: 34ch; font-size: 14.5px; line-height: 1.6; color: var(--muted); }
@media (prefers-reduced-motion: reduce) {
  .fo-ac__spine__wip { transition: none; }
  .fo-wip__stream, .fo-wip__sandtop, .fo-wip__sandbot,
  .fo-wip__mound, .fo-wip__grain { animation: none; }
  .fo-wip__sandtop { transform: translateY(33px); }
  .fo-wip__sandbot, .fo-wip__mound { transform: translateY(-22px); }
  .fo-wip__grain { opacity: 0; }
}

/* ── Hero height ───────────────────────────────────────────────────
   .fo-hero was 115vh with a sticky 100vh stage — built for a display
   headline that has since been removed. What is left is a 287px thread
   floating in an 858px box: a third full, with equal dead space above
   and below. The stage now sizes to its content.
   The nav's reveal threshold reads hero.offsetHeight and still works. */
.fo-hero { height: auto; }
.fo-hero__stage {
  position: static;
  height: auto;
  min-height: 0;
  padding-top: clamp(104px, 15vh, 168px);
  padding-bottom: clamp(64px, 10vh, 128px);
}


/* ── Hero: pinned post ─────────────────────────────────────────────
   Built to the korty.tv pattern, measured off the live site rather
   than eyeballed: bubbles at 64px radius with 64px padding, wrapped in
   a card whose footer strip carries the avatar, the name, a "Pinned"
   marker and the call to action on the right. The proportions are the
   idea — very round, very generously padded — not the colours, which
   stay ours. */

/* the strip that closes the card — byline left, action right */


/* ── Filmstrip screens: keep their own proportions ─────────────────
   Two things were fighting the image. The rule above sized it to "the
   remaining height under the chrome" — written when the mock had a
   browser bar — and .fo-mock is a flex column, so the default
   align-items:stretch pinned the image to the full frame width no
   matter what width:auto said. Result: a landscape screen cropped
   20–43% to fill a portrait box. The frame is a plain block now and
   the image is sized by height, so width follows the real ratio. */
.fo-proj--strip .fo-rail .fo-mock {
  display: block;
  width: auto;
  max-width: none;
  height: 100%;
  align-self: stretch;
  background: none;
}
.fo-proj--strip .fo-rail .fo-mock > img {
  display: block;
  width: auto;
  height: 100%;
  max-width: none;
  aspect-ratio: auto;
  object-fit: fill;
}

/* ── Fan / loop / shot screens: proportions too ────────────────────
   These frames are positioned by each treatment with fixed insets, so
   their shape has nothing to do with the screenshot inside them, and
   object-fit:cover was cropping up to 47% off. Contain keeps the whole
   screen at its real ratio; the frame's own fill and border come off so
   the leftover space reads as spacing, not as letterboxing. */
.fo-proj__media .fo-scr:has(> img) {
  background: none;
  border: 0;
  box-shadow: none;
}
.fo-proj__media .fo-scr > img {
  width: 100%; height: 100%;
  object-fit: contain;
  object-position: center;
}

@media (max-width: 620px) {
  .fo-worktocs__go { flex-direction: column; align-items: flex-start; gap: 18px; }
  .fo-worktocs__chip { align-self: flex-end; }
}

/* ── filmstrip: one frame, whatever the screenshot ─────────────────
   The mocks were sized by each image's own ratio at the rail's fixed
   height, so a portrait capture came out 398px wide next to landscape
   ones at ~900px — the dashboard read as a long narrow sliver. Give
   every frame the same aspect and let the image cover it. Anchored to
   the top, which is where a dashboard keeps its header and figures. */
@media (min-width: 1181px) {
  .fo-proj--strip .fo-rail .fo-mock {
    width: auto; aspect-ratio: 1.4 / 1; flex: none;
  }
}
.fo-proj--strip .fo-rail .fo-mock > img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
}

/* ── hero thread: the conversation plays in ────────────────────────
   .is-waiting hides a bubble before its turn; .is-typing shows the
   indicator in its place; .is-on is the bubble carrying typed text. */
.fo-hero .fo-thread .fo-msg.is-waiting {
  opacity: 0; transform: translateY(8px) scale(.98);
  pointer-events: none;
}
.fo-hero .fo-thread .fo-msg.is-typing,
.fo-hero .fo-thread .fo-msg.is-on {
  opacity: 1; transform: none;
  transition: opacity .34s ease, transform .44s cubic-bezier(.16,1,.3,1);
}
/* the indicator sits where the text will be, at the bubble's own size */
.fo-hero .fo-thread .fo-msg.is-typing .fo-type::before {
  content: ""; display: inline-block;
  width: 46px; height: 1em; vertical-align: middle;
  background:
    radial-gradient(circle 4px at 8px 50%,  currentColor 96%, transparent 0),
    radial-gradient(circle 4px at 23px 50%, currentColor 96%, transparent 0),
    radial-gradient(circle 4px at 38px 50%, currentColor 96%, transparent 0);
  opacity: .38;
  animation: fo-dots 1.25s ease-in-out infinite;
}
@keyframes fo-dots {
  0%, 100% { opacity: .22; }
  50%      { opacity: .62; }
}
/* the caret only exists while something is being written */
.fo-hero .fo-thread .fo-msg.is-on .fo-type::after {
  content: ""; display: inline-block;
  width: 2px; height: .95em; margin-left: 2px; vertical-align: -0.12em;
  background: var(--coral);
  animation: fo-caret .9s steps(1) infinite;
}
.fo-hero .fo-thread .fo-msg.is-done .fo-type::after { display: none; }
@keyframes fo-caret { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* her own reply is sent, not typed */
.fo-hero .fo-thread .fo-msg--out.is-waiting { opacity: 0; transform: translateY(10px) scale(.96); }
.fo-hero .fo-thread .fo-msg--out.is-sent {
  opacity: 1; transform: none;
  transition: opacity .32s ease, transform .5s cubic-bezier(.2,1.2,.3,1);
}



/* ── hero as a pinned post ─────────────────────────────────────────
   The message area carries NO fill — the bubbles keep their own, so
   they hold their edges against the page (1.14:1) instead of
   dissolving into a panel, which is what a full-fill card did. The
   only filled surface is the footer strip; the rounded top of the
   message area and the rounded bottom of the footer make one object. */
.fo-hero .fo-thread {
  max-width: 660px;
  background: none; border: 0; padding: 0;
  display: block;
}
.fo-hero .fo-thread__main {
  padding: clamp(14px, 1.6vw, 22px) clamp(14px, 1.6vw, 22px) clamp(18px, 2vw, 26px);
  border-radius: clamp(22px, 2.4vw, 30px) clamp(22px, 2.4vw, 30px) 0 0;
}
.fo-hero .fo-thread .fo-msgs { gap: 10px; }

.fo-hero .fo-thread__foot {
  display: flex; align-items: center; gap: 12px;
  padding: 14px clamp(14px, 1.6vw, 20px);
  background: var(--bg-white);
  border-radius: 0 0 clamp(22px, 2.4vw, 30px) clamp(22px, 2.4vw, 30px);
  box-shadow: 0 20px 50px -44px rgb(var(--ink-rgb) / .55);
}
.fo-hero .fo-thread__pic {
  width: 42px; height: 42px; margin: 0; flex: none; border-radius: 50%;
  background-size: cover; background-position: center;
}
.fo-hero .fo-thread__by {
  display: flex; flex-direction: column; gap: 2px;
  line-height: 1.3; margin-right: auto; min-width: 0;
}
.fo-hero .fo-thread__by i {
  font-style: normal; font-size: 12px; color: var(--faint); letter-spacing: .01em;
}
.fo-hero .fo-thread__by b { font-size: 14.5px; font-weight: 600; color: var(--ink); }
.fo-hero .fo-thread__cta {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 11px 20px; border-radius: var(--r-pill);
  border: 1px solid var(--line-2); text-decoration: none;
  font-size: 13.5px; font-weight: 550; color: var(--ink); white-space: nowrap;
  transition: background-color .3s ease, border-color .3s ease, color .3s ease;
}
.fo-hero .fo-thread__cta i { font-style: normal; transition: transform .32s cubic-bezier(.22,1,.28,1); }
.fo-hero .fo-thread__cta:hover { background: var(--brand); border-color: transparent; color: #fff; }
.fo-hero .fo-thread__cta:hover i { transform: translateX(3px); }
/* it arrives once the messages have landed */
.fo-hero .fo-thread__foot.is-waiting { opacity: 0; transform: translateY(10px); }
.fo-hero .fo-thread__foot.is-sent {
  opacity: 1; transform: none;
  transition: opacity .34s ease, transform .5s cubic-bezier(.2,1.1,.3,1);
}
@media (max-width: 560px) {
  .fo-hero .fo-thread__foot { flex-wrap: wrap; }
  .fo-hero .fo-thread__cta { width: 100%; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .fo-hero .fo-thread__foot, .fo-hero .fo-thread__cta { transition: none; }
}

/* ── filmstrip on small screens ────────────────────────────────────
   The frame's aspect-ratio is desktop-only, so below 941px the mock had
   no definite width — and the image's width:100% resolved against it,
   collapsing both to 0. Give the mock a real width here; the image
   still covers it. */
@media (max-width: 1180px) {
  /* inset the strip inside the white card and let the frame fill its
     height — flush to the left edge with dead space underneath was the
     "doesn't sit well" part. The next frame peeks, which is the cue
     that the strip pans. */
  .fo-proj--strip .fo-rail {
    inset: 0 !important;
    height: 100% !important;
    padding: clamp(14px, 4vw, 22px);
    gap: clamp(10px, 3vw, 16px);
    align-items: center;
  }
  .fo-proj--strip .fo-rail .fo-mock {
    flex: none;
    height: 100%;
    width: auto;
    aspect-ratio: 1.4 / 1;
  }
}

/* ── vertical rhythm around "Selected work" ────────────────────────
   The heading had ~124px above it and 12px below, so it read as
   belonging to the hero rather than to the cards it introduces.
   Balance the two sides and give the first card room to start. */
.fo-showcase__head {
  padding-block: clamp(10px, 2vw, 26px) clamp(30px, 4.5vw, 52px);
}
/* the hero no longer needs to hold open a full screen once the thread
   has landed — that trailing space was most of the imbalance */
@media (max-width: 1180px) {
  .fo-hero { min-height: auto; padding-bottom: clamp(20px, 6vw, 40px); }
  /* The 76px hole here was never a margin problem. The body is a
     space-between column and .fo-proj__lead carries flex-basis 300px —
     right for the fixed-height overlay on desktop, wrong once the card
     stacks: the lead held 68px of content in a 300px box and pushed the
     paragraph to the floor. Pulling the body up with a negative margin
     hid that, and dragged the title over the meta line to do it. */
  .fo-proj__body {
    margin-top: 0;
    height: auto;
    justify-content: flex-start;
  }
  .fo-proj__lead { flex: 0 0 auto; height: auto; }
}

/* ── A full document, scrolled in place ───────────────────────────
   The customer-facing proposal is 1600x11139 — roughly 1:7. Dropped inline
   it is a screen and a half of scrolling before the next paragraph, so it
   sits in its own frame and scrolls there instead.
   NB: this is `.fo-doc`, NOT `.fo-ac__scroll` — that class is already the
   scrolling body of every open case study and must not be touched. */
.fo-doc__frame { position: relative; }
.fo-doc__box {
  max-height: clamp(420px, 68vh, 720px);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--panel-2);
  -webkit-overflow-scrolling: touch;
}
.fo-doc__box img { display: block; width: 100%; height: auto; }
.fo-doc__box:focus-visible { outline: 2px solid var(--periwinkle); outline-offset: -2px; }
.fo-doc__fade {
  position: absolute; left: 0; right: 0; bottom: 0; height: 64px;
  background: linear-gradient(rgb(var(--paper-rgb) / 0), rgb(var(--paper-rgb) / .62));
  pointer-events: none;
}

/* ── the year leads the pill row ───────────────────────────────────
   Three cards carried a year in the meta line and two carried none at
   all. It is a pill on every card now, first in the row, and stated
   once — the meta line no longer repeats it. Full-ink against the
   muted scope tags so it reads as the fact, not another label. */
.fo-proj__tags__yr {
  color: var(--ink) !important;
  background: rgb(var(--ink-rgb) / .07) !important;
  font-weight: 600;
}

/* ── Screen sets ───────────────────────────────────────────────────
   Same machinery as the click-through, different job: a `set` groups
   related screens so a run of them reads as one frame instead of a
   long scroll. No step numbers — they are alternatives, not a sequence. */
.fo-proto--set .fo-proto__step i { display: none; }
.fo-proto--set .fo-proto__step { padding-inline: 12px; }

/* the reply keeps the sent-bubble look — gradient and tail — but rides in
   the poster strip, which was otherwise carrying only a name. Smaller,
   because at full message size it dwarfs the avatar beside it. */
.fo-hero .fo-thread__main { display: flex; flex-direction: column; align-items: stretch; }
.fo-hero .fo-thread__foot .fo-msg--out { margin: 0 0 0 auto; flex: none; align-self: center; }
.fo-msg--out-sm {
  padding: 9px 16px; font-size: 13.5px; gap: 7px;
  border-radius: 999px 999px 8px 999px;
  box-shadow: 0 8px 20px -12px rgba(123,128,228,.9);
}
.fo-msg--out-sm i { font-size: 13px; }
.fo-hero .fo-thread .fo-msg--out.is-waiting { opacity: 0; transform: translateY(10px) scale(.96); }
.fo-hero .fo-thread .fo-msg--out.is-sent {
  opacity: 1; transform: none;
  transition: opacity .32s ease, transform .5s cubic-bezier(.2,1.2,.3,1);
}

/* Below 1000px the page scrolls, not the study, so the product tab bar sticks to
   the viewport — and top:0 parked it under the fixed nav. Clear the nav from its
   own geometry (top clamp + ~54px with the burger + a gap). Must sit AFTER every
   other .fo-tabs rule: same specificity, so source order decides. */
@media (max-width: 1000px) {
  /* The study header is sticky here too, at nav-clearance, with z-index 20.
     Parking the tabs at the same offset stuck them *underneath* it — correctly
     stuck, completely invisible. Sit below the header instead. Its height
     depends on how the project name wraps, so folio.js measures it and
     publishes --ac-head-h on the column. */
  .fo-tabs {
    top: calc(clamp(14px, 2.2vh, 22px) + 54px + 6px + var(--ac-head-h, 112px) + 26px);
  }
}

/* ── sound toggle ──────────────────────────────────────────────────
   Four bars that stand up when sound is on and flatten when it is
   off, so the state reads without a label. */
.fo-sound {
  /* the dock positions it now */
  position: static;
  width: 36px; height: 36px; flex: none;
  display: grid; place-items: center; cursor: pointer;
  border: 1px solid var(--line-2); border-radius: 50%;
  padding: 0;
  background: rgb(var(--paper-rgb) / .82);
  backdrop-filter: blur(12px) saturate(1.4);
  -webkit-backdrop-filter: blur(12px) saturate(1.4);
  transition: border-color .3s ease, background-color .3s ease, transform .3s ease;
}
.fo-sound:hover { border-color: var(--line); transform: translateY(-2px); }
.fo-sound:focus-visible { outline: 2px solid var(--periwinkle); outline-offset: 2px; }
.fo-sound__ico { display: flex; align-items: center; gap: 2px; height: 14px; }
.fo-sound__ico i {
  display: block; width: 2px; border-radius: 2px;
  background: var(--faint); height: 3px;
  transition: height .32s cubic-bezier(.16,1,.3,1), background-color .3s ease;
}
.fo-sound.is-on .fo-sound__ico i { background: var(--ink); }
.fo-sound.is-on .fo-sound__ico i:nth-child(1) { height: 6px; }
.fo-sound.is-on .fo-sound__ico i:nth-child(2) { height: 13px; }
.fo-sound.is-on .fo-sound__ico i:nth-child(3) { height: 9px; }
.fo-sound.is-on .fo-sound__ico i:nth-child(4) { height: 4px; }
@media (prefers-reduced-motion: reduce) {
  .fo-sound, .fo-sound__ico i { transition: none; }
}

/* the one actionable phrase in the in-progress cover */
.fo-wip__ask {
  color: var(--ink); text-decoration: underline;
  text-underline-offset: 3px; text-decoration-thickness: 1px;
  text-decoration-color: rgb(var(--ink-rgb) / .35);
  transition: text-decoration-color .3s ease;
}
.fo-wip__ask:hover { text-decoration-color: var(--coral); }

/* ── drawn explanations inside a study ─────────────────────────────
   For the sections where no product screen tells the story. Inline
   SVG so it inherits ink and the accents, and flips with the theme. */
.fo-ac__dia {
  margin: 26px 0 30px; padding: clamp(20px, 3vw, 34px);
  border: 1px solid var(--line-2); border-radius: var(--r-md);
  background: var(--bg-raise);
}
.fo-ac__dia svg { display: block; width: 100%; height: auto; }
.fo-ac__dia figcaption {
  margin-top: 14px; font-size: 12.5px; line-height: 1.5; color: var(--muted);
}
/* a diagram that explains itself carries no caption — do not leave its
   margin behind */
.fo-ac__dia figcaption:empty { display: none; }
.fo-dia__box { fill: var(--bg-white); stroke: var(--line); stroke-width: 1.2; }
.fo-dia__t { fill: var(--ink); font-family: var(--font-body); font-size: 12px; font-weight: 600; }
.fo-dia__s { fill: var(--muted); font-family: var(--font-body); font-size: 10.5px; }
.fo-dia__line { stroke: var(--line-2); stroke-width: 1.4; fill: none; }
.fo-dia__flow { stroke: var(--periwinkle); stroke-width: 1.6; fill: none; }
.fo-dia__dot { fill: var(--coral); }
.fo-dia__box--soft { fill: rgb(123 128 228 / .10); stroke: rgb(123 128 228 / .34); }

/* ── a wall of whole pages ─────────────────────────────────────────
   For a run of pages worth seeing AS pages rather than as sections.
   Each one runs from its header down and trails off into the panel,
   so the set reads as "and here is the rest of the site". */
.fo-wall {
  margin: 26px 0 30px; padding: clamp(18px, 3vw, 30px);
  border: 1px solid var(--line-2); border-radius: var(--r-md);
  background: var(--bg-raise);
}
.fo-wall__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: clamp(12px, 2vw, 22px); align-items: start;
}
.fo-wall__page { min-width: 0; }
.fo-wall__box {
  position: relative; aspect-ratio: 1 / 2.35; overflow: hidden;
  border-radius: 10px; background: var(--bg-white);
  box-shadow: 0 1px 2px rgb(var(--ink-rgb) / .09),
              0 16px 34px -20px rgb(var(--ink-rgb) / .5);
}
.fo-wall__box img { display: block; width: 100%; height: auto; }
.fo-wall__box::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 24%;
  background: linear-gradient(to bottom,
              rgb(var(--paper-rgb) / 0), var(--bg-raise) 92%);
  pointer-events: none;
}
.fo-wall__lab {
  display: block; margin-top: 11px;
  font-size: 12px; line-height: 1.4; color: var(--muted);
}
.fo-wall figcaption {
  margin-top: 16px; font-size: 12.5px; line-height: 1.5; color: var(--muted);
}

/* ── a page spread ─────────────────────────────────────────────────
   One carousel slide holding a whole page cut into columns and laid
   side by side, so a long page can be seen at once instead of being
   scrolled past. Reuses the walkthrough component; only the slide
   changes from an <img> to a row of them. */
.fo-proto__stage .fo-proto__shot.fo-proto__spread.is-on {
  display: flex; gap: clamp(8px, 1.4vw, 14px); align-items: flex-start;
}
.fo-proto__stage .fo-proto__spread img {
  flex: 1 1 0; min-width: 0; width: 100%; height: auto; display: block;
  border-radius: 6px;
  box-shadow: 0 1px 2px rgb(var(--ink-rgb) / .08),
              0 14px 30px -22px rgb(var(--ink-rgb) / .5);
}

/* ── flat-lay ──────────────────────────────────────────────────────
   Page sections tilted, overlapping and bleeding off the stage, the
   way a template set is presented. For a run of pages where the set
   is the point and no single card needs to be read. */
.fo-lay { margin: 26px 0 30px; }
.fo-lay__stage {
  position: relative; height: clamp(250px, 34vw, 345px);
  display: flex; justify-content: center; align-items: flex-start;
  padding-top: 52px; overflow: hidden;
  border: 1px solid var(--line-2); border-radius: var(--r-md);
  background: var(--bg-raise);
}
.fo-lay__card {
  flex: 0 0 22%; margin-inline: -3.6%;
  border-radius: 8px; overflow: hidden; background: var(--bg-white);
  box-shadow: 0 2px 5px rgb(var(--ink-rgb) / .13),
              0 34px 60px -34px rgb(var(--ink-rgb) / .7);
  transform: rotate(-9deg) translateY(calc(var(--i) * 11px));
  transform-origin: 50% 20%;
  z-index: var(--i);
}
.fo-lay__stage img { display: block; width: 100%; height: auto; }
.fo-lay figcaption {
  margin-top: 14px; font-size: 12.5px; line-height: 1.5; color: var(--muted);
}
@media (max-width: 640px) {
  .fo-lay__stage { padding-top: 34px; }
  .fo-lay__card { flex-basis: 34%; margin-inline: -5%; }
  .fo-lay__card:nth-child(n+6) { display: none; }
}

/* ── a row of screens ──────────────────────────────────────────────
   Phone layouts standing side by side. A 393px design blown up to the
   full column reads as a mistake; three of them across it do not. */
.fo-row { margin: 26px 0 30px; }
.fo-row__set { display: flex; gap: clamp(10px, 1.6vw, 18px); align-items: flex-start; }
.fo-row .fo-row__set img {
  flex: 1 1 0; min-width: 0; width: 100%; height: auto; display: block;
  border-radius: 10px;
  box-shadow: 0 1px 2px rgb(var(--ink-rgb) / .09),
              0 16px 34px -22px rgb(var(--ink-rgb) / .55);
}
.fo-row figcaption {
  margin-top: 14px; font-size: 12.5px; line-height: 1.5; color: var(--muted);
}

/* ── the dock: sound + theme, bottom-left ──────────────────────────
   Both were spending a permanent slot in the nav on settings most
   people touch once. They live together down here, opposite the
   project dock on the work page. */
.fo-dock {
  position: fixed; z-index: 620;
  left: clamp(14px, 2.2vw, 24px); bottom: clamp(14px, 2.2vh, 24px);
  display: flex; align-items: center; gap: 8px;
}
.fo-dock .fo-toggle {
  background: rgb(var(--paper-rgb) / .82);
  backdrop-filter: blur(12px) saturate(1.4);
  -webkit-backdrop-filter: blur(12px) saturate(1.4);
  border-radius: var(--r-pill);
}



/* ── footer navigation ─────────────────────────────────────────────
   Case studies, pages and the résumé, divided by rules rather than by
   gaps: one above the grid, one down each column boundary, and a
   hairline under every row so the lists read as a ledger. */
/* the social plates sit in the third column now */

/* ── footer index: the studies as full-width rows ──────────────────
   Three tidy columns read as fine print. These are the same links at
   display scale — each row is a rule, and hovering floods it with
   that project's own colour, the one its card and column already use. */
/* the colour wipes in from the left rather than just appearing */

/* the utility row: pages, socials, résumé, on one line under the index */


/* ── footer navigation ─────────────────────────────────────────────
   The line work is the design here, so the rules do more than divide:
   the top rule runs full-bleed past the container, the column dividers
   stop short at both ends instead of boxing the columns in, crosshair
   ticks sit where rules would have crossed, and each row's underline is
   dashed until you hover it — then it draws solid in the accent. */
.fo-foot__grid {
  position: relative;
  display: grid;
  grid-template-columns: 1.35fr 1fr 1fr;
  gap: 0;
  margin-top: clamp(30px, 4vw, 54px);
  padding-top: clamp(22px, 2.6vw, 34px);
}
/* the top rule ignores the container and runs to the page edges */
.fo-foot__grid::before {
  content: ""; position: absolute; top: 0;
  left: calc(var(--edge) * -1); right: calc(var(--edge) * -1);
  height: 1px; background: var(--line-2);
}
.fo-foot__col { position: relative; padding: 2px clamp(18px, 2.2vw, 30px) 0; }
.fo-foot__col:first-child { padding-left: 0; }
/* divider: a hairline that stops short top and bottom */
.fo-foot__col + .fo-foot__col::before {
  content: ""; position: absolute; left: 0; top: 12px; bottom: 26px;
  width: 1px; background: var(--line-2);
}
/* and a crosshair where it meets the top rule */
.fo-foot__col + .fo-foot__col::after {
  content: ""; position: absolute; left: -4px; top: calc(clamp(22px, 2.6vw, 34px) * -1 - 4px);
  width: 9px; height: 9px;
  background:
    linear-gradient(var(--line) 0 0) center / 9px 1px no-repeat,
    linear-gradient(var(--line) 0 0) center / 1px 9px no-repeat;
}
.fo-foot__list { list-style: none; margin: 0; padding: 0; }
.fo-foot__list li { position: relative; }
/* dashed at rest */
.fo-foot__list li::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background-image: linear-gradient(90deg, var(--line-2) 0 4px, transparent 4px 8px);
  background-size: 8px 1px;
}
.fo-foot__list li:last-child::after { display: none; }
/* solid, coloured, drawn from the left on hover */
.fo-foot__list li::before {
  content: ""; position: absolute; left: 0; bottom: 0; height: 1px; width: 100%;
  background: var(--coral); transform: scaleX(0); transform-origin: left;
  transition: transform .45s cubic-bezier(.16,1,.3,1);
  z-index: 1;
}
.fo-foot__list li:hover::before { transform: scaleX(1); }
.fo-foot__list a {
  display: block; padding: 12px 0; text-decoration: none;
  color: var(--ink); font-size: 15px;
  transition: color .25s ease, padding-left .4s cubic-bezier(.16,1,.3,1);
}
.fo-foot__list li:hover a { color: var(--coral); padding-left: 8px; }
.fo-foot__grid .fo-social__grid { flex-direction: column; align-items: flex-start; gap: 8px; }

@media (max-width: 860px) {
  .fo-foot__grid { grid-template-columns: 1fr 1fr; }
  .fo-foot__col:nth-child(3) {
    grid-column: 1 / -1; padding-left: 0; margin-top: 26px; padding-top: 22px;
  }
  .fo-foot__col:nth-child(3)::before {
    left: 0; right: 0; top: 0; bottom: auto; width: auto; height: 1px;
  }
  .fo-foot__col:nth-child(3)::after { display: none; }
  .fo-foot__grid .fo-social__grid { flex-direction: row; flex-wrap: wrap; }
}
@media (max-width: 560px) {
  .fo-foot__grid { grid-template-columns: 1fr; }
  .fo-foot__col { padding-left: 0; margin-top: 24px; padding-top: 20px; }
  .fo-foot__col:first-child { margin-top: 0; padding-top: 0; }
  .fo-foot__col + .fo-foot__col::before {
    left: 0; right: 0; top: 0; bottom: auto; width: auto; height: 1px;
  }
  .fo-foot__col + .fo-foot__col::after { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .fo-foot__list a, .fo-foot__list li::before, }

/* the résumé is a row in the list now, not a pill parked beneath it —
   same rule, same hover, with the arrow marking it as a download */
.fo-foot__dl {
  font-style: normal; margin-left: 8px; font-size: 12px; color: var(--faint);
  transition: transform .32s cubic-bezier(.22,1,.28,1), color .25s ease;
  display: inline-block;
}
.fo-foot__list li:hover .fo-foot__dl { transform: translateY(3px); color: var(--coral); }
@media (prefers-reduced-motion: reduce) { .fo-foot__dl { transition: none; } }

/* the nav's contact button — hidden below 1000px by the existing rule,
   where Contact already sits in the menu sheet */
.fo-nav__cta i { font-style: normal; transition: transform .32s cubic-bezier(.22,1,.28,1); }
.fo-nav__cta:hover i { transform: translateX(3px); }
@media (prefers-reduced-motion: reduce) { .fo-nav__cta i { transition: none; } }

/* ── Phones on a stage ─────────────────────────────────────────────
   Mobile screens shown as phones rather than as flat rectangles. Two or
   three per group, staggered, on a tinted panel — the presentation is what
   makes a 393px screen read as a designed thing rather than a screenshot. */
.fo-phones { margin: 28px 0 32px; }
.fo-phones__stage {
  position: relative; isolation: isolate;
  display: flex; justify-content: center; align-items: flex-start;
  gap: clamp(12px, 2.6vw, 30px);
  padding: clamp(30px, 5vw, 58px) clamp(18px, 4vw, 44px) clamp(34px, 5vw, 60px);
  border-radius: 18px;
  /* The first build, the one she chose: five soft lights in her accents over a
     deep base. The cream app screens read against it; light stages washed out. */
  background:
    radial-gradient(58% 66% at 12% -4%, rgb(123 128 228 / .95), transparent 62%),
    radial-gradient(48% 58% at 92%  6%, rgb(185 138 194 / .80), transparent 64%),
    radial-gradient(66% 74% at 82% 104%, rgb(251 139 113 / .55), transparent 66%),
    radial-gradient(58% 66% at 16% 106%, rgb(123 128 228 / .70), transparent 64%),
    radial-gradient(70% 40% at 50% 34%, rgb(255 255 255 / .10), transparent 70%),
    linear-gradient(158deg, rgb(26 27 48), rgb(17 18 34) 55%, rgb(12 13 24));
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .10), 0 24px 60px -30px rgb(0 0 0 / .5);
}
/* fine grain, so the gradient does not band on a wide screen */
.fo-phones__stage::before {
  content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit;
  opacity: .16; mix-blend-mode: overlay; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
.fo-phones__unit { flex: 1 1 0; min-width: 0; max-width: 250px; }
/* whatever the column width, the handsets divide the row rather than spilling out */
.fo-phones__stage { overflow-x: clip; }
/* the stagger — a straight row of three reads as a filmstrip, not a layout */
.fo-phones__stage > :nth-child(2) { margin-top: clamp(20px, 4vw, 52px); }
.fo-phones__stage > :nth-child(3) { margin-top: clamp(8px, 1.6vw, 20px); }
.fo-phones__bezel {
  background: #0e1014; padding: 5px; border-radius: 26px;
  box-shadow: 0 26px 48px -18px rgb(0 0 0 / .55), 0 3px 10px rgb(0 0 0 / .22);
}
.fo-phones__bezel img {
  display: block; width: 100%; height: auto;
  border-radius: 21px;
  /* every phone the same shape whatever the source is — a 393x852 screen and a
     393x4996 scroll both read as one handset. The long ones show their top. */
  aspect-ratio: 9 / 19.3;
  object-fit: cover; object-position: top;
}
.fo-phones__cap {
  display: block; margin-top: 12px; text-align: center;
  font-family: var(--font-body); font-size: 11.5px; letter-spacing: .01em;
  color: rgb(255 255 255 / .62);
}
@media (max-width: 640px) {
  /* three phones side by side at 375px would be thumbnails — scroll instead */
  .fo-phones__stage {
    justify-content: flex-start; overflow-x: auto; scroll-snap-type: x mandatory;
    padding: 24px 18px 28px; gap: 16px;
  }
  .fo-phones__stage > * { margin-top: 0 !important; scroll-snap-align: center; }
  .fo-phones__unit { flex: 0 0 58%; }
}

/* ── filmstrip frames were showing 1.1 screens ─────────────────────
   .fo-mock was height:100% of the rail with aspect-ratio 1.4/1, so its
   width was driven by the card's height: 492px inside a ~563px window.
   One screen filled the frame and the next was sliced, which read as a
   single magnified fragment rather than a strip of screens. Sizing the
   frame to a share of the rail height puts ~1.7 frames in view and drops
   the on-screen UI to a normal size. Scoped to the desktop band — the
   stacked layout below 1181px sets its own frame size. */
@media (min-width: 1181px) {
  .fo-proj--strip .fo-rail { align-items: center; }
  .fo-proj--strip .fo-rail .fo-mock {
    height: 72%;
    width: auto;
    aspect-ratio: 1.4 / 1;
    flex: none;
    align-self: center;
  }
}


/* ── Stage variants ────────────────────────────────────────────────
   Same treatment, different weather. Each group gets its own arrangement
   and lead colour so no two stages on a page look alike. The base rule
   above stays as v1 (periwinkle-led). */
.fo-phones__stage--v2 {   /* mauve-led, lights from the right */
  background:
    radial-gradient(60% 70% at 88% -6%, rgb(185 138 194 / .95), transparent 62%),
    radial-gradient(50% 60% at  6% 12%, rgb(251 139 113 / .60), transparent 64%),
    radial-gradient(64% 72% at 14% 106%, rgb(123 128 228 / .75), transparent 66%),
    radial-gradient(52% 58% at 88% 102%, rgb(185 138 194 / .50), transparent 64%),
    radial-gradient(70% 40% at 50% 30%, rgb(255 255 255 / .09), transparent 70%),
    linear-gradient(202deg, rgb(38 26 44), rgb(24 18 34) 55%, rgb(14 11 22));
}
.fo-phones__stage--v3 {   /* coral-led, warm, sunset weighted low */
  background:
    radial-gradient(64% 74% at 50% 112%, rgb(251 139 113 / .85), transparent 68%),
    radial-gradient(50% 58% at  8% -4%, rgb(185 138 194 / .65), transparent 62%),
    radial-gradient(48% 56% at 94%  0%, rgb(123 128 228 / .60), transparent 62%),
    radial-gradient(70% 40% at 50% 40%, rgb(255 255 255 / .08), transparent 70%),
    linear-gradient(178deg, rgb(40 26 32), rgb(28 18 26) 55%, rgb(16 11 16));
}
.fo-phones__stage--v4 {   /* teal-green, the healthcare brand's own register */
  background:
    radial-gradient(58% 66% at 10% -6%, rgb(104 196 170 / .80), transparent 62%),
    radial-gradient(50% 60% at 92% 10%, rgb(123 128 228 / .60), transparent 64%),
    radial-gradient(62% 70% at 84% 106%, rgb(196 174 120 / .55), transparent 66%),
    radial-gradient(70% 40% at 50% 32%, rgb(255 255 255 / .09), transparent 70%),
    linear-gradient(158deg, rgb(22 36 34), rgb(15 26 26) 55%, rgb(10 16 17));
}
.fo-phones__stage--v5 {   /* gold, the caregiver app's own tan on deep bronze */
  background:
    radial-gradient(60% 68% at 86% -8%, rgb(196 160 96 / .85), transparent 64%),
    radial-gradient(48% 58% at  6%  8%, rgb(251 139 113 / .50), transparent 62%),
    radial-gradient(60% 70% at 12% 108%, rgb(196 160 96 / .55), transparent 66%),
    radial-gradient(70% 40% at 50% 30%, rgb(255 255 255 / .10), transparent 70%),
    linear-gradient(196deg, rgb(40 32 22), rgb(28 22 16) 55%, rgb(16 13 10));
}
.fo-phones__stage--v6 {   /* dusk blue, lights split top/bottom */
  background:
    radial-gradient(56% 64% at 50% -10%, rgb(123 128 228 / .80), transparent 64%),
    radial-gradient(52% 62% at  6% 108%, rgb(251 139 113 / .55), transparent 64%),
    radial-gradient(52% 62% at 94% 108%, rgb(185 138 194 / .60), transparent 64%),
    radial-gradient(70% 40% at 50% 36%, rgb(255 255 255 / .08), transparent 70%),
    linear-gradient(180deg, rgb(20 24 46), rgb(15 17 34) 55%, rgb(10 11 22));
}
.fo-phones__stage--v7 {   /* plum, one big warm light low-left */
  background:
    radial-gradient(72% 80% at 10% 110%, rgb(251 139 113 / .70), transparent 66%),
    radial-gradient(52% 60% at 92% -6%, rgb(185 138 194 / .85), transparent 62%),
    radial-gradient(44% 52% at 40%  0%, rgb(123 128 228 / .45), transparent 60%),
    radial-gradient(70% 40% at 50% 32%, rgb(255 255 255 / .09), transparent 70%),
    linear-gradient(214deg, rgb(36 22 40), rgb(24 16 30) 55%, rgb(14 10 18));
}

/* Captures that are already complete at their own ratio — the Uiland detail
   pair is 1:1.96 — must not be force-cropped to the handset shape. `--nat`
   lets a group keep its natural ratio; both members share it, so the row
   stays uniform. */
.fo-phones__stage--nat .fo-phones__bezel img { aspect-ratio: auto; object-fit: fill; }

/* ── a video in a filmstrip frame ──────────────────────────────────
   The Aether card carries the design-hub screen recording in place of
   a still. Every .fo-mock > img sizing rule has to apply to it too,
   or the frame collapses to the video's intrinsic size. Appended last
   so it wins on source order against the five img rules above. */
.fo-proj--strip .fo-rail .fo-mock > video {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
  border-radius: inherit; background: var(--bg-raise);
}

/* ── a strip holding a single frame ────────────────────────────────
   The Aether card is just the design-hub recording now. A lone 354px
   frame left 208px of the art window empty and read as a mistake, so
   when a strip has one child it fills the window instead of sitting
   at filmstrip size. Scoped to :only-child so the five-frame cards
   are untouched. */
@media (min-width: 1181px) {
  .fo-proj--strip .fo-rail > .fo-mock:only-child {
    height: 100%;
    width: 100%;
    aspect-ratio: auto;
    align-self: stretch;
  }
}

/* ── About hero: the surname outgrew the portrait ──────────────────
   Both names were set at clamp(46px, 11.5vw, 152px) so they'd read as
   one lockup, but "Tassy Omah" is ten glyphs to "Esther"'s six: 751px
   against a 540px portrait, overhanging ~105px each side. The given
   name keeps the full size; the surname is scaled to sit inside the
   photograph instead of straddling it. */
.fo-phead--portrait .fo-phead__h .fo-phead__last {
  font-size: clamp(40px, 8.2vw, 108px);
}

/* "Hi, I'm" is near-black type landing on dark hair, so no amount of
   paper-coloured halo separates it. Give it the same blurred chip the
   "but I mostly go by" label already uses, so the two small labels
   read as a pair and both survive the photograph. */
.fo-phead--portrait .fo-phead__h .fo-phead__hi {
  display: inline-block;
  padding: 4px 12px 5px;
  border-radius: 999px;
  background: rgb(var(--paper-rgb) / .62);
  -webkit-backdrop-filter: blur(7px);
  backdrop-filter: blur(7px);
  color: rgb(var(--ink-rgb) / .82);
  text-shadow: none;
}
