@font-face{font-family:'Figtree';src:url('fonts/Figtree-Variable-latin.woff2') format('woff2');font-weight:300 900;font-style:normal;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}
@font-face{font-family:'Figtree';src:url('fonts/Figtree-Variable-latin-ext.woff2') format('woff2');font-weight:300 900;font-style:normal;font-display:swap;unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;}
@font-face{font-family:'Google Sans Code';src:url('fonts/GoogleSansCode-Variable-latin.woff2') format('woff2');font-weight:300 800;font-style:normal;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2190-2199,U+2212,U+2215,U+FEFF,U+FFFD;}

*{box-sizing:border-box;}
button{font:inherit;color:inherit;}

/* Design tokens. Source of truth: DESIGN_SYSTEM.md. Use these, never literals. */
:root{
  color-scheme: dark;

  /* ---- Colour: neutrals (one violet hue, 300, runs through every grey) ---- */
  --bg-sunken:   oklch(0.16 0.02 300);   /* video and media wells */
  --bg:          oklch(0.19 0.02 300);   /* page */
  --surface:     oklch(0.22 0.02 300);   /* cards, panels */
  --surface-2:   oklch(0.26 0.02 300);   /* raised: chat bubbles, quote cards, hover fills */
  --line-soft:   oklch(0.26 0.02 300);   /* dividers inside cards, mobile nav rows */
  --line:        oklch(0.30 0.02 300);   /* default border and rule */
  --line-strong: oklch(0.34 0.02 300);   /* pill and chip borders, image frames, portrait ring */

  --text:   oklch(0.94 0.008 300);       /* headings, values (15.5:1 on --bg) */
  --text-2: oklch(0.85 0.01 300);        /* body copy (11.7:1) */
  --muted:  oklch(0.82 0.01 300);        /* labels, captions, meta, footer (APCA Lc 70; was 0.76) */

  /* Overlays on media */
  --scrim:       oklch(0.19 0.02 300 / 0.72);  /* glass buttons over the reel */
  --scrim-heavy: oklch(0.19 0.02 300 / 0.9);   /* lightbox, sticky bars */
  --glass-line:  oklch(1 0 0 / 0.12);

  /* Constant in both themes */
  --ink:      oklch(0.19 0.02 300);      /* fixed dark text on bright fills */
  --on-media: oklch(0.94 0.008 300);     /* fixed light text on video and photos */
  --shadow-card: none;                   /* soft violet shadow in light */
  --bubble-fill: var(--surface-2);       /* the "their reply" recommendation bubble */

  /* ---- Colour: accent family (all L 0.75 to 0.94, C 0.11 to 0.17) ----
     Each accent has six roles: --x small text, -large, -fill, -tint, -mark, -hover.
     In dark they collapse to the same colour, tint is --surface and mark is transparent. */
  --lavender:       oklch(0.84 0.11 300);  /* site accent: links, work, metrics */
  --lavender-large: var(--lavender);
  --lavender-fill:  var(--lavender);
  --lavender-tint:  var(--surface);
  --lavender-mark:  transparent;
  --lavender-hover: oklch(0.92 0.06 300);  /* hover for lavender links */

  --pink:           oklch(0.83 0.11 345);  /* recommendations: small text and fills (Lc 68) */
  --pink-large:     oklch(0.75 0.14 345);  /* recommendations and quotes: large text, marks, borders */
  --pink-fill:      var(--pink);
  --pink-tint:      oklch(0.75 0.14 345 / .08);
  --pink-mark:      transparent;
  --pink-hover:     var(--text);
  --pink-line:      oklch(0.75 0.14 345 / .45);

  --orange:         oklch(0.79 0.13 60);   /* resume section */
  --orange-large:   var(--orange);
  --orange-fill:    var(--orange);
  --orange-tint:    var(--surface);
  --orange-mark:    transparent;
  --orange-hover:   var(--text);

  --cyan:           oklch(0.80 0.11 205);  /* Aunty Maria's */
  --cyan-large:     var(--cyan);
  --cyan-fill:      var(--cyan);
  --cyan-tint:      var(--surface);
  --cyan-mark:      transparent;
  --cyan-hover:     var(--text);

  --lime:           oklch(0.90 0.17 130);  /* Flavius */
  --lime-large:     var(--lime);
  --lime-fill:      var(--lime);
  --lime-tint:      var(--surface);
  --lime-mark:      transparent;
  --lime-hover:     var(--text);

  --lime-bright:    oklch(0.94 0.16 125);  /* footer values panel (see decision 2) */
  --yellow:         oklch(0.89 0.13 89);   /* hero word effects only (was #FFD66B) */

  /* Contextual accent. Defaults to lavender. Set it with an .accent-* class
     on a section or card, never inline. Children read the six roles. */
  --accent:       var(--lavender);
  --accent-large: var(--lavender-large);
  --accent-fill:  var(--lavender-fill);
  --accent-tint:  var(--lavender-tint);
  --accent-mark:  var(--lavender-mark);
  --accent-hover: var(--lavender-hover);
  --on-accent:    var(--ink);              /* text on a filled accent */

  /* Back-compat: existing recommendations variables point at the new tokens */
  --color-recs: var(--pink-large);
  --color-recs-hover: var(--pink);
  --color-recs-border: var(--pink-line);

  /* ---- Type ---- */
  --font-sans: 'Figtree', sans-serif;          /* reading, headings */
  --font-mono: 'Google Sans Code', monospace;  /* labels, nav, buttons, meta */

  --fs-display: clamp(36px, 5vw, 58px);   /* page H1, one per page */
  --fs-h2:      clamp(32px, 4vw, 48px);   /* section titles */
  --fs-h3:      clamp(24px, 2.6vw, 32px); /* card headlines, contact, big quote leads */
  --fs-h4:      clamp(20px, 2vw, 24px);   /* sub-headings, card titles */
  --fs-lead:    clamp(19px, 1.6vw, 22px); /* page intro paragraph */
  --fs-title:   20px;                     /* case study section names, small headings */
  --fs-body-lg: 18px;                     /* case study and about body */
  --fs-body:    16px;                     /* default body, cards */
  --fs-small:   15px;                     /* captions, action links, section eyebrows */
  --fs-label:   13px;                     /* mono labels, pills, toggles, secondary buttons */
  --fs-micro:   12px;                     /* nav, footer, meta */

  --fw-regular: 400;
  --fw-semibold: 600;
  --fw-bold: 700;
  --fw-black: 800;                        /* display only */

  --lh-tight: 1.12;                       /* display, h2 */
  --lh-snug:  1.25;                       /* h3, h4, title */
  --lh-ui:    1.4;                        /* labels, buttons, pills, short UI text */
  --lh-body:  1.6;                        /* body, lead */

  --ls-display: -0.025em;
  --ls-heading: -0.02em;
  --ls-tight:   -0.01em;
  --ls-body:    0.0125em;                 /* set once on body */

  /* ---- Space (4px base) ---- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 40px;
  --space-8: 48px;
  --space-9: 64px;
  --space-section: 96px;                  /* between page sections (56px under 900px) */

  --gutter: 40px;                         /* 20px under 900px, 16px under 640px */
  --container: 1240px;                    /* .wrap, gutters inside: 1160px of content */

  /* ---- Radius ---- */
  --r-xs:   4px;                          /* focus rings, tiny marks */
  --r-sm:   8px;                          /* small media, inputs */
  --r-md:   14px;                         /* media frames, panels, video */
  --r-lg:   24px;                         /* cards, page header media, big panels */
  --r-pill: 999px;                        /* buttons, pills, chips, toggles */
  --r-tail: 6px;                          /* the speech-bubble corner (see .bubble) */

  /* ---- Motion ---- */
  --dur-fast: .16s;                       /* arrows, small transforms */
  --dur:      .2s;                        /* colour, border, background */
  --dur-wipe: .35s;                       /* link wipe, values trigger */
  --dur-slow: .7s;                        /* reveals, panel opens */
  --ease:      ease;
  --ease-wipe: cubic-bezier(.6, 0, .2, 1);
  --lift: translateY(-2px);               /* card and tag hover */
  --nudge: 4px;                           /* arrow travel on hover */

  /* ---- Focus ---- */
  --focus-width: 2px;
  --focus-offset: 3px;
}

/* Accent context classes (DESIGN_SYSTEM.md section 10). Put one on a section or card instead of an inline --accent. */
.accent-lavender{--accent:var(--lavender);--accent-large:var(--lavender-large);--accent-fill:var(--lavender-fill);--accent-tint:var(--lavender-tint);--accent-mark:var(--lavender-mark);--accent-hover:var(--lavender-hover);}
.accent-pink{--accent:var(--pink);--accent-large:var(--pink-large);--accent-fill:var(--pink-fill);--accent-tint:var(--pink-tint);--accent-mark:var(--pink-mark);--accent-hover:var(--pink-hover);}
.accent-orange{--accent:var(--orange);--accent-large:var(--orange-large);--accent-fill:var(--orange-fill);--accent-tint:var(--orange-tint);--accent-mark:var(--orange-mark);--accent-hover:var(--orange-hover);}
.accent-cyan{--accent:var(--cyan);--accent-large:var(--cyan-large);--accent-fill:var(--cyan-fill);--accent-tint:var(--cyan-tint);--accent-mark:var(--cyan-mark);--accent-hover:var(--cyan-hover);}
.accent-lime{--accent:var(--lime);--accent-large:var(--lime-large);--accent-fill:var(--lime-fill);--accent-tint:var(--lime-tint);--accent-mark:var(--lime-mark);--accent-hover:var(--lime-hover);}
.accent-ink{--accent:var(--text);--accent-large:var(--text);--accent-fill:var(--surface-2);--accent-tint:var(--surface);--accent-mark:transparent;--accent-hover:var(--text-2);}


@media (max-width: 900px){
  :root{ --gutter: 20px; --space-section: 56px; }
}
@media (max-width: 640px){
  :root{ --gutter: 16px; }
}

body{
  margin:0;
  background:var(--bg);
  font-family:var(--font-sans);
  color:var(--text);
  letter-spacing:var(--ls-body);
  /* Thinner rendering for light text on the dark background; reads crisper on macOS */
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
}

a{color:var(--lavender);text-decoration:none;}
a:hover{color:var(--lavender-hover);}

.nav-link{color:var(--muted);transition:color var(--dur) ease;}
.nav-link:hover{color:var(--lavender);}

.reveal{opacity:0;transform:translateY(26px);transition:opacity var(--dur-slow) ease,transform var(--dur-slow) ease;}
.reveal.revealed{opacity:1;transform:translateY(0);}
@media (scripting: none){.reveal{opacity:1;transform:none;}}
@media (prefers-reduced-motion: reduce){
  .reveal{opacity:1;transform:none;transition:none;}
  .hero-anim{opacity:1;animation:none;}
}

@keyframes fadeUp{from{opacity:0;transform:translateY(16px);}to{opacity:1;transform:translateY(0);}}
.hero-anim{opacity:0;animation:fadeUp var(--dur-slow) ease forwards;}

/* Buttons: secondary (.case-cta, 44px) and primary (.case-cta--lg, 56px). DESIGN_SYSTEM.md 6.1 */
.case-cta{
  display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:0 18px;border-radius:var(--r-pill);
  border:1px solid var(--accent);color:var(--accent);
  font-family:var(--font-mono);font-size:var(--fs-label);font-weight:var(--fw-semibold);cursor:pointer;
  transition:background var(--dur) ease,color var(--dur) ease;
}
.case-cta:hover{background:var(--accent);color:var(--on-accent);}
.case-cta-arrow{display:inline-block;transition:transform var(--dur-fast) ease;}
.case-cta:hover .case-cta-arrow{transform:translateX(var(--nudge));}
.case-cta:hover .case-cta-arrow--up{transform:translateY(calc(-1 * var(--nudge)));}
/* Neutral glass variant, for buttons sitting on media (the homepage highlights reel) */
.case-cta--glass{
  gap:10px;min-height:56px;padding:0 26px;font-size:var(--fs-body);font-weight:var(--fw-bold);
  background:var(--scrim);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  border-color:var(--glass-line);color:var(--on-media);
}
.case-cta--glass:hover{background:color-mix(in oklch, var(--surface-2) 85%, transparent);color:var(--on-media);}
.case-cta--glass:focus-visible{outline:var(--focus-width) solid var(--on-media);outline-offset:var(--focus-offset);}

.wrap{max-width:1240px;margin:0 auto;}

/* Skip link: first tab stop on every page, jumps to <main id="main"> */
.skip-link{position:absolute;left:16px;top:-60px;z-index:200;padding:10px 16px;border-radius:var(--r-pill);background:var(--lavender-fill);color:var(--on-accent);font-weight:var(--fw-semibold);}
.skip-link:focus{top:12px;color:var(--on-accent);}

/* Header / Hero */
.site-header{padding:36px 40px 0;}

nav.primary-nav{display:flex;justify-content:space-between;align-items:center;margin-bottom:96px;animation-delay:.05s;}
.brand{display:inline-flex;align-items:center;min-height:44px;font-size:24px;font-weight:var(--fw-semibold);letter-spacing:var(--ls-tight);}
.primary-nav .links{display:flex;gap:28px;font-family:var(--font-mono);font-size:16px;}
.primary-nav .links .nav-link{display:inline-flex;align-items:center;min-height:40px;}
/* Contact details only show in the mobile panel; the footer carries them on desktop */
.nav-extra{display:none;}
.primary-nav .nav-link:focus-visible,.nav-toggle:focus-visible{outline:var(--focus-width) solid var(--lavender);outline-offset:var(--focus-offset);border-radius:var(--r-xs);}

/* Theme toggle: a round icon button after the nav links (DESIGN_SYSTEM.md 6.6), a 36px disc in a 44px hit area.
   In the mobile panel it's a full-width row instead. The icon and row text follow <html data-theme> in CSS, so
   they're right before script.js runs; script.js keeps the aria-label in step. Hidden without JavaScript. */
.theme-toggle{
  display:inline-flex;align-items:center;justify-content:center;align-self:center;width:44px;height:44px;
  padding:0;border:0;background:none;color:var(--text);cursor:pointer;
}
.theme-toggle-disc{
  display:grid;place-items:center;width:36px;height:36px;border-radius:50%;
  border:1px solid var(--line-strong);background:var(--surface);transition:border-color var(--dur) ease;
}
.theme-toggle:hover .theme-toggle-disc{border-color:var(--accent);}
.theme-toggle:focus-visible{outline:var(--focus-width) solid var(--lavender);outline-offset:var(--focus-offset);border-radius:50%;}
.theme-toggle svg{display:block;flex:none;width:18px;height:18px;}
.theme-toggle .theme-icon-moon,.theme-toggle .theme-label-light,
[data-theme="light"] .theme-toggle .theme-icon-sun,[data-theme="light"] .theme-toggle .theme-label-dark{display:none;}
[data-theme="light"] .theme-toggle .theme-icon-moon{display:block;}
[data-theme="light"] .theme-toggle .theme-label-light{display:inline;}
.theme-toggle--row{display:none;}

/* Mobile nav: below 900px the links become a full-screen panel opened by the menu button */
.nav-toggle{display:none;}
@media (max-width: 900px){
  /* Hamburger: three bars that turn into a cross while the panel is open */
  .nav-toggle{
    position:relative;z-index:101;display:inline-flex;align-items:center;justify-content:center;
    width:48px;height:48px;margin-right:-12px;padding:0;border:0;background:none;cursor:pointer;color:var(--text);
  }
  .nav-toggle-bars,.nav-toggle-bars::before,.nav-toggle-bars::after{
    display:block;width:24px;height:2px;border-radius:var(--r-xs);background:currentColor;
    transition:transform var(--dur) ease,background-color var(--dur) ease;
  }
  .nav-toggle-bars{position:relative;}
  .nav-toggle-bars::before,.nav-toggle-bars::after{content:"";position:absolute;left:0;}
  .nav-toggle-bars::before{transform:translateY(-7px);}
  .nav-toggle-bars::after{transform:translateY(7px);}
  .primary-nav.is-open .nav-toggle-bars{background-color:transparent;}
  .primary-nav.is-open .nav-toggle-bars::before{transform:rotate(45deg);}
  .primary-nav.is-open .nav-toggle-bars::after{transform:rotate(-45deg);}
  .theme-toggle--icon{display:none;}
  /* In the panel: a pill button sized like a secondary button (DESIGN_SYSTEM.md 6.1), neutral like the nav icon */
  .theme-toggle--row{
    display:inline-flex;align-self:flex-start;gap:var(--space-2);width:auto;height:auto;min-height:44px;margin-top:var(--space-5);
    padding:0 18px;border:1px solid var(--line-strong);border-radius:var(--r-pill);background:var(--surface);
    font-family:var(--font-mono);font-size:var(--fs-label);font-weight:var(--fw-semibold);line-height:var(--lh-ui);
    transition:border-color var(--dur) ease;
  }
  .theme-toggle--row svg{width:16px;height:16px;}
  .theme-toggle--row:hover{border-color:var(--accent);}
  .theme-toggle--row:focus-visible{border-radius:var(--r-pill);}
  .nav-extra{display:flex;flex-direction:column;gap:4px;margin-top:40px;font-family:var(--font-sans);}
  .nav-extra-label{margin-bottom:6px;font-family:var(--font-mono);font-size:var(--fs-label);color:var(--muted);}
  .nav-extra-link{display:flex;align-items:center;min-height:44px;font-size:var(--fs-body-lg);color:var(--text);transition:color var(--dur) ease;}
  .nav-extra-link:hover{color:var(--lavender);}
  .nav-extra-link:focus-visible{outline:var(--focus-width) solid var(--lavender);outline-offset:var(--focus-offset);border-radius:var(--r-xs);}
  .primary-nav .brand{position:relative;z-index:101;}
  /* The panel's links line up with the page gutter (20px on every page) */
  .primary-nav .links{
    display:none;position:fixed;inset:0;z-index:100;flex-direction:column;gap:0;
    padding:96px var(--nav-gutter,20px) 40px;overflow-y:auto;background:var(--bg);font-size:20px;
  }
  .primary-nav .links .nav-link{min-height:56px;border-bottom:1px solid var(--line-soft);}
  .primary-nav.is-open .links{display:flex;}
  /* The nav's fade-in leaves a transform behind, which would trap the fixed panel inside it */
  .primary-nav.is-open{animation:none;opacity:1;transform:none;}
  /* Scrolled away from the top, the nav slides back in from the top whenever the visitor scrolls up
     (script.js). A spacer holds its place in the page. No transform once shown, so the menu panel still
     covers the screen. */
  .primary-nav.is-pinned{
    position:fixed;top:0;left:0;right:0;z-index:50;margin:0;padding:var(--space-2) 20px;
    background:var(--bg);border-bottom:1px solid var(--line-soft);
    animation:none;opacity:1;transform:translateY(-100%);transition:transform var(--dur-wipe) var(--ease-wipe);
  }
  .primary-nav.is-pinned.is-shown{transform:none;}
  .primary-nav.is-pinned.is-open{border-bottom-color:transparent;}
}
@media (prefers-reduced-motion: reduce){
  .primary-nav.is-pinned{transition:none;}
}
@media (scripting: none){.primary-nav .theme-toggle{display:none;}}

/* Hero: intro row, H1 and the highlights reel (no domains row: removed on purpose) (spec in handoff/homepage-hero/README.md).
   Mockup values mapped to the site's colours: #ECEAF2 is --text / --on-media, #15121c --bg, #C4C1CF --text-2,
   the subtle border --line-strong. */
.hero{position:relative;padding-bottom:72px;}
.hero-intro{display:flex;align-items:center;gap:var(--space-4);animation-delay:.15s;}
.hero-portrait{width:64px;height:64px;flex:none;border-radius:50%;border:2px solid var(--line-strong);object-fit:cover;display:block;}
.hero-hi{margin:0;font-size:var(--fs-body-lg);font-weight:var(--fw-semibold);line-height:var(--lh-snug);}
.hero-role{margin:2px 0 0;font-family:var(--font-mono);font-size:var(--fs-small);color:var(--muted);}
/* z-index keeps the word effects and popovers above the reel, which paint later */
.hero-title{position:relative;z-index:2;margin:var(--space-6) 0 0;max-width:900px;font-size:var(--fs-display);font-weight:var(--fw-black);line-height:var(--lh-tight);letter-spacing:var(--ls-display);animation-delay:.25s;}

/* RecommendedWord: highlighted words in the hero H1, each backed by a recommendation (assets/recommended-words.json).
   Ported from handoff/homepage-hero/hero-word-effects.css with its keyframes, timings and positions unchanged,
   scoped under .rw and moved onto tokens. script.js adds the effect class (.fx-neon, .fx-eye, .fx-beat) from the
   JSON and toggles .on while the popover is open. Mockup colours: #C9AEFF is --lavender, #B8F04A --lime (the
   projects page "colour" palette), #E86FB5 --pink-large (the recommendations pink), #ECEAF2 --text, #121118 --ink. */
.rw{position:relative;display:inline-block;}
/* The dotted underline: the site's dotted text-decoration (4px, 9px offset), as on the projects "colour" word.
   The letters are inline-block so they can animate, which stops a decoration on the link reaching them, so
   ::after redraws the word in transparent ink and carries the decoration. Empty alt text keeps it out of the name. */
.rw .hl{position:relative;display:inline-block;color:inherit;cursor:pointer;border-radius:var(--r-xs);}
.rw .hl::after{
  content:attr(aria-label);content:attr(aria-label) / "";position:absolute;inset:0;white-space:nowrap;color:transparent;pointer-events:none;
  text-decoration-line:underline;text-decoration-style:dotted;text-decoration-color:var(--lavender);
  text-decoration-thickness:4px;text-underline-offset:9px;
}
.rw .hl:hover{color:inherit;}
/* Touch and narrow screens: no popover or effect, so the words read as plain text (script.js drops the link) */
@media (hover: none), (pointer: coarse), (max-width: 639px){
  .rw .hl{cursor:auto;}
  .rw .hl::after{content:none;}
}
.rw .hl:focus-visible{outline:var(--focus-width) solid var(--lavender);outline-offset:var(--focus-offset);}
.rw .ch{display:inline-block;transform-origin:50% 90%;transition:color 300ms ease;}
.rw .i0{--i:0}.rw .i1{--i:1}.rw .i2{--i:2}.rw .i3{--i:3}.rw .i4{--i:4}.rw .i5{--i:5}.rw .i6{--i:6}.rw .i7{--i:7}.rw .i8{--i:8}
/* Energy: neon switch-on. The flicker's off state is --line-strong (mockup #5B5A62) */
/* Display-size letters take the large roles, so they stay coloured in light (where --lime is ink). The glow is the fill. */
.rw .fx-neon{--neon-glow-1:color-mix(in oklch, var(--lime-fill) 80%, transparent);--neon-glow-2:color-mix(in oklch, var(--lime-fill) 90%, transparent);--neon-glow-3:color-mix(in oklch, var(--lime-fill) 55%, transparent);}
.rw .fx-neon.on .ch{animation:neon 900ms linear both;animation-delay:calc(var(--i) * 55ms);}
@keyframes neon{0%{color:var(--text);text-shadow:none}8%{color:var(--lime-large);text-shadow:0 0 18px var(--neon-glow-1)}12%{color:var(--line-strong);text-shadow:none}22%{color:var(--lime-large);text-shadow:0 0 22px var(--neon-glow-2)}26%{color:var(--line-strong);text-shadow:none}40%,100%{color:var(--lime-large);text-shadow:0 0 24px var(--neon-glow-3)}}
/* Curiosity: the curious eye replaces the "o" */
.rw .oc{display:inline-block;position:relative;}
.rw .og{display:inline-block;transition:opacity 220ms ease;}
.rw .ov{position:absolute;left:50%;top:58%;width:0.62em;height:0.62em;transform:translate(-50%,-50%) scale(.6);opacity:0;transition:transform 520ms cubic-bezier(.3,1.5,.5,1),opacity 220ms ease;overflow:visible;pointer-events:none;}
.rw .ov-white{fill:var(--on-media);stroke:var(--lavender-large);stroke-width:6;}
.rw .ov-pupil{fill:var(--ink);}
.rw .ov-glint{fill:var(--on-media);}
.rw .pupil{transform-box:view-box;transform-origin:24px 24px;}
.rw .fx-eye.on .ch{color:var(--lavender-large);}
.rw .fx-eye.on .og{opacity:0;}
.rw .fx-eye.on .ov{opacity:1;transform:translate(-50%,-50%) scale(1.3);}
.rw .fx-eye.on .pupil{animation:look 2200ms ease-in-out 300ms infinite;}
@keyframes look{0%,12%{transform:translate(0,0)}20%,36%{transform:translate(-7px,1px)}44%,58%{transform:translate(7px,1px)}66%,82%{transform:translate(2px,-7px)}90%,100%{transform:translate(0,0)}}
/* Care: heartbeat through the letters, and a heart that pops in beside the word */
.rw .fx-beat.on .ch{color:var(--pink-large);animation:hb 1100ms ease-in-out both;animation-delay:calc(var(--i) * 70ms);}
@keyframes hb{0%,100%{transform:scale(1)}14%{transform:scale(1.14)}28%{transform:scale(1)}42%{transform:scale(1.09)}56%{transform:scale(1)}}
/* Centred on the middle of the lowercase letters (.65em down the line box); the margin centres the heart's ink, not its 30px box */
.rw .hbh{position:absolute;left:100%;top:.65em;width:30px;height:30px;margin:-18px 0 0 10px;transform-origin:50% 60%;animation:hbpop 1100ms ease-in-out 280ms both;pointer-events:none;fill:var(--pink-large);}
@keyframes hbpop{0%{transform:scale(0)}20%{transform:scale(1.15)}34%{transform:scale(.9)}48%{transform:scale(1.1)}62%,100%{transform:scale(1)}}

/* Popover: a speech bubble under the word. It's a sibling of the H1 (so the quote never becomes part of the
   heading), placed by script.js. The transparent top padding is the bridge the pointer crosses from the word. */
.rw-pop{position:absolute;z-index:5;width:360px;max-width:calc(100vw - 32px);padding-top:var(--space-1);}
.rw-pop[hidden]{display:none;}
.rw-bubble{
  display:block;padding:18px 20px var(--space-4);background:var(--bubble-fill);border:1px solid var(--line);
  border-radius:var(--r-tail) var(--r-lg) var(--r-lg) var(--r-lg);box-shadow:0 12px 28px rgba(0,0,0,0.28);color:var(--text);
}
.rw-pop.is-flipped .rw-bubble{border-radius:var(--r-lg) var(--r-tail) var(--r-lg) var(--r-lg);}
.rw-quote{margin:0;font-size:var(--fs-body-lg);line-height:var(--lh-body);font-weight:var(--fw-semibold);}
/* The person row is the link: avatar, name, organisation, and the arrow at the right edge */
.rec-link{display:flex;align-items:center;gap:10px;margin-top:14px;font-size:var(--fs-label);color:var(--text);}
.rec-link:hover{color:var(--text);}
.rec-avatar{
  flex:none;width:32px;height:32px;border-radius:50%;background:var(--line);color:var(--pink);
  display:flex;align-items:center;justify-content:center;font-size:var(--fs-micro);font-weight:var(--fw-bold);
}
.rec-name{flex:none;white-space:nowrap;font-weight:var(--fw-semibold);transition:color var(--dur-fast) ease;}
.rec-org{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--muted);}
.rec-arrow{display:inline-block;margin-left:auto;font-family:var(--font-mono);font-size:var(--fs-body);font-weight:var(--fw-bold);transition:transform var(--dur-fast) ease;}
.rec-link:hover .rec-arrow{transform:translateX(var(--nudge));}
.rec-link:hover .rec-name,.rec-link:focus-visible .rec-name{color:var(--pink);}
.rec-link:focus-visible{outline:var(--focus-width) solid var(--lavender);outline-offset:var(--focus-offset);border-radius:var(--r-xs);}

@media (prefers-reduced-motion: reduce){
  .nav-toggle-bars,.nav-toggle-bars::before,.nav-toggle-bars::after{transition:none;}
  /* From hero-word-effects.css: no letter animation, the heart and eye appear without moving */
  .rw .fx-neon.on .ch,.rw .fx-beat.on .ch,.rw .hbh,.rw .fx-eye.on .pupil{animation:none;}
  .rw .fx-neon.on .ch{color:var(--lime-large);}
  .rw .ov,.rw .og,.rw .ch{transition:none;}
  .rec-arrow,.rec-name{transition:none;}
  .link-action,.link-arrow,.case-cta-arrow{transition:none;}
}

/* HighlightsReel: the reel and its glass overlays. Everything on the reel is neutral: --on-media text on --scrim
   glass, which stay the same in both themes, and no accent colour. */
.reel{
  position:relative;margin-top:var(--space-9);aspect-ratio:16/9;border-radius:var(--r-lg);overflow:hidden;
  border:1px solid var(--line-strong);background:var(--bg);animation-delay:.45s;
}
.reel-video{display:block;width:100%;height:100%;object-fit:cover;}
.reel-glass{
  background:var(--scrim);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  border:1px solid var(--glass-line);border-radius:var(--r-pill);color:var(--on-media);
}
.reel-counter{position:absolute;top:var(--space-5);right:var(--space-5);margin:0;padding:8px 14px;font-family:var(--font-mono);font-size:var(--fs-label);line-height:var(--lh-snug);}
.reel-bar{position:absolute;left:var(--space-5);right:var(--space-5);bottom:var(--space-5);display:flex;align-items:center;justify-content:space-between;gap:var(--space-4);}
.reel-now{display:flex;align-items:center;gap:14px;min-width:0;padding:6px 22px 6px 6px;}
.reel-toggle{
  flex:none;width:44px;height:44px;border:0;border-radius:50%;padding:0;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  background:var(--on-media);color:var(--ink);
}
.reel-toggle svg{fill:currentColor;}
.reel-toggle .reel-icon-play,.reel-toggle.is-paused .reel-icon-pause{display:none;}
.reel-toggle.is-paused .reel-icon-play{display:block;}
.reel-toggle:focus-visible{outline:var(--focus-width) solid var(--on-media);outline-offset:var(--focus-offset);}
.reel-name{flex:none;font-size:var(--fs-body);font-weight:var(--fw-bold);white-space:nowrap;}
.reel-divider{flex:none;width:1px;height:18px;background:color-mix(in oklch, var(--on-media) 30%, transparent);}
.reel-what{font-size:var(--fs-small);color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.reel-cta{flex:none;}

/* Homepage section heading: eyebrow + title on the left, CTA on the right. An .accent-* class on it sets the section's colour. */
.sec-head{
  display:flex;flex-wrap:wrap;justify-content:space-between;align-items:flex-end;gap:24px;margin:0 0 48px;
}
.sec-head-intro{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:14px;}
.sec-eyebrow{margin:0;font-family:var(--font-mono);font-size:var(--fs-small);color:var(--accent);}
.sec-title{margin:0;font-size:var(--fs-h2);font-weight:var(--fw-bold);line-height:var(--lh-tight);letter-spacing:var(--ls-heading);}
.sec-head a:focus-visible{outline:var(--focus-width) solid var(--accent);outline-offset:var(--focus-offset);}

/* Case studies */
section#case-studies{padding:0 40px 100px;}
/* Work page: the same callouts; each has the ID its header card jumps to */
.work-callouts{padding:0 40px 100px;}
.work-callouts .csc{scroll-margin-top:32px;}

/* Case study callouts (CaseStudyCallout). Generated from each case study's `callout` block by
   build/casestudy/callout.py; spec in handoff/callout-handoff/HANDOFF-case-study-callouts.md.
   Homepage: pill and text on the left, the reel on the right spanning both rows, so the reel's top
   lines up with the pill and "Read case study" sits level with its bottom. Work page (.csc--work):
   the same card with the summary and facts. The headline's link stretches over the whole card.
   Lavender is only for "Read case study". */
.csc{
  position:relative;background:var(--surface);border-radius:var(--r-lg);padding:40px 40px 44px;margin-bottom:32px;box-shadow:var(--shadow-card);
  display:grid;grid-template-columns:minmax(0,35fr) minmax(0,65fr);column-gap:56px;row-gap:44px;align-items:start;
  grid-template-areas:"head media" "text media";grid-template-rows:auto 1fr;
  transition:opacity var(--dur-slow) ease,transform var(--dur-slow) ease,background-color var(--dur) ease;
}
.csc:last-child{margin-bottom:0;}
.csc:hover{background:var(--surface-2);}
.csc:focus-within{outline:var(--focus-width) solid var(--lavender);outline-offset:var(--focus-offset);}
.csc:has(.csc-toggle:focus-visible){outline:none;}
/* Pill: the homepage "Worked across" pill, at the card's smaller size */
.csc-pill{
  grid-area:head;justify-self:start;margin:0;padding:4px 12px;border:1px solid var(--line-strong);border-radius:var(--r-pill);
  font-size:var(--fs-label);line-height:var(--lh-snug);color:var(--text);
}
.csc-text{grid-area:text;align-self:stretch;display:flex;flex-direction:column;gap:16px;}
.csc-intro{display:flex;flex-direction:column;gap:12px;}
.csc-company{margin:0;font-family:var(--font-mono);font-size:var(--fs-label);color:var(--muted);}
.csc-headline{margin:0;font-size:var(--fs-h3);font-weight:var(--fw-semibold);line-height:var(--lh-tight);letter-spacing:var(--ls-heading);}
.csc-stretch{color:var(--text);}
.csc-stretch:hover{color:var(--text);}
.csc-stretch:focus{outline:none;}
/* z-index lifts the link over the media too, so the image is tappable; the play button (z-index 2) stays on top */
.csc-stretch::after{content:"";position:absolute;inset:0;z-index:1;border-radius:inherit;}
.csc-metric{margin:0;font-size:var(--fs-body);line-height:var(--lh-body);color:var(--muted);}
.csc-metric strong{font-weight:var(--fw-semibold);color:var(--text);}
.csc-more{margin-top:auto;padding-top:24px;align-self:flex-start;}
.csc-media{grid-area:media;position:relative;}
/* flow-root keeps the reel's negative crop margins inside the frame, so its top lines up with the pill */
.csc-frame{display:flow-root;width:100%;}
.csc-phone{display:none;}
.csc-video,.csc-still{display:block;width:var(--csc-w,100%);max-width:none;height:auto;margin:var(--csc-mt,0) 0 var(--csc-mb,0) var(--csc-ml,0);border-radius:var(--r-md);}
/* Round icon button over the reel's corner, above the stretched link */
.csc-toggle{
  position:absolute;z-index:2;right:16px;bottom:16px;width:44px;height:44px;padding:0;
  display:flex;align-items:center;justify-content:center;
  border:1px solid var(--line-strong);border-radius:var(--r-pill);background:var(--surface);color:var(--text);
  cursor:pointer;transition:background-color var(--dur) ease;
}
.csc-toggle[hidden]{display:none;}
.csc-toggle svg{fill:currentColor;}
.csc-toggle:hover{background:oklch(0.3 0.03 300);}
.csc-toggle:focus-visible{outline:var(--focus-width) solid var(--lavender);outline-offset:var(--focus-offset);}
.csc-icon-play,.csc-toggle.is-paused .csc-icon-pause{display:none;}
.csc-toggle.is-paused .csc-icon-play{display:block;}

/* Work page card: text on the left (pill, intro and summary, facts, link), reel on the right */
.csc--work{
  padding:40px;grid-template-columns:minmax(0,42fr) minmax(0,58fr);grid-template-areas:"head media" "text media";
  grid-template-rows:auto 1fr;row-gap:32px;align-items:stretch;
}
.csc--work .csc-text{gap:32px;}
.csc--work .csc-pill{align-self:start;}
.csc--work .csc-headline{font-size:var(--fs-h3);line-height:var(--lh-tight);}
.csc--work .csc-more{padding-top:0;}
.csc--work .csc-media{align-self:start;}
.csc--work .csc-toggle{right:14px;bottom:14px;}
.csc-summary{margin:0;font-size:var(--fs-body);line-height:var(--lh-body);color:var(--text-2);}
.csc-facts{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:18px 40px;margin:0;}
.csc-fact{display:flex;flex-direction:column;gap:4px;}
.csc-fact:first-child{grid-column:1 / -1;}
.csc-fact dt{font-family:var(--font-mono);font-size:var(--fs-label);color:var(--muted);}
.csc-fact dd{margin:0;font-size:var(--fs-small);color:var(--text);}

@media (prefers-reduced-motion: reduce){
  .csc{transition:opacity var(--dur-slow) ease,transform var(--dur-slow) ease;}
  .csc-toggle{transition:none;}
  .csc:hover .link-arrow{transform:none;}
}

@media (max-width: 900px){
  .csc,.csc--work{
    grid-template-columns:minmax(0,1fr);grid-template-areas:"head" "media" "text";grid-template-rows:auto;
    padding:24px;row-gap:24px;
  }
  .csc-more{padding-top:8px;}
  .csc-facts{grid-template-columns:minmax(0,1fr);row-gap:14px;}
}
/* The section's button repeated under its content. Only one of the two shows at a time. */
.sec-foot{display:none;}
.sec-foot a:focus-visible{outline:var(--focus-width) solid var(--accent);outline-offset:var(--focus-offset);}
@media (max-width: 900px){
  .sec-head{flex-direction:column;align-items:flex-start;margin-bottom:36px;}
  .sec-head:has(~ .sec-foot) > .case-cta{display:none;}
  .sec-foot{display:flex;margin-top:var(--space-6);}
  #recommendations .sec-foot{margin-top:0;}
}
/* Phones: a spotlight (real-size product UI, spotlight.css) or a cropped still stands in for the reel,
   which is unreadable at this size. Card layout from handoff/mobile-polish/README.md (Fix 1): the pill,
   then the media at the card's full width, then the text. No pause button. */
.sl{display:none;}
@media (max-width: 640px){
  .csc-media--phone .csc-frame,.csc-media--phone .csc-toggle,
  .csc-media--sl .csc-frame,.csc-media--sl .csc-toggle{display:none;}
  .csc-phone{display:block;width:100%;height:auto;border-radius:var(--r-md);}
  .csc,.csc--work{padding:var(--space-2);row-gap:var(--space-1);grid-template-areas:"head" "media" "text";}
  .csc-pill{margin:10px 6px 2px;}
  .csc-text{padding:16px 14px 18px;gap:14px;}
  .csc--work .csc-text{gap:var(--space-5);}
  .csc-intro{gap:var(--space-2);}
  .csc-headline{line-height:1.18;letter-spacing:-0.015em;text-wrap:balance;}
  .csc-more,.csc--work .csc-more{padding-top:0;}
  /* The next case study, at the end of a case study: no pill or metric, a smaller headline */
  .csc--next{grid-template-areas:"media" "text";margin:0;}
  .csc--next .csc-headline{font-size:22px;line-height:1.2;}
}

/* Recommendations (homepage): three Q&A cards in the chat style of the recommendations page.
   Spec: handoff/recommendations-handover/homepage-section-handover.md */
section#recommendations{
  padding:20px 40px 120px;display:flex;flex-direction:column;gap:56px;
}
#recommendations .sec-head{margin-bottom:0;}
#recommendations a:focus-visible{outline:var(--focus-width) solid var(--color-recs);outline-offset:var(--focus-offset);}

.rec-qa-cards{display:flex;flex-wrap:wrap;gap:24px;align-items:stretch;}
.rec-qa{
  flex:1 1 340px;min-width:0;display:flex;flex-direction:column;gap:22px;padding:28px;border-radius:var(--r-lg);
  background:var(--surface);border:1px solid transparent;color:var(--text);box-shadow:var(--shadow-card);
  transition:transform var(--dur) ease,border-color var(--dur) ease;
}
.rec-qa:hover{transform:translateY(calc(-1 * var(--nudge)));border-color:var(--pink-line);color:var(--text);}
.rec-qa-q{
  align-self:flex-end;max-width:100%;padding:14px 18px;border-radius:var(--r-lg) var(--r-lg) var(--r-tail) var(--r-lg);
  background:var(--accent-fill);color:var(--on-accent);font-size:var(--fs-body-lg);font-weight:var(--fw-semibold);line-height:var(--lh-ui);
}
.rec-qa-ans{display:grid;grid-template-columns:32px minmax(0,1fr);gap:10px;align-items:center;}
.rec-qa-ans blockquote{
  grid-column:1 / -1;margin:0;padding:16px 20px;border-radius:var(--r-lg) var(--r-lg) var(--r-lg) var(--r-tail);
  background:var(--bubble-fill);font-size:var(--fs-body-lg);line-height:var(--lh-body);color:var(--text);
}
.rec-qa-ans .recs-avatar{width:32px;height:32px;font-size:var(--fs-micro);}
/* Slightly tighter tracking keeps the longest name and role (Sarah Prescott's) on one line at 1160px */
.rec-qa-who{font-size:var(--fs-label);letter-spacing:var(--ls-tight);color:var(--muted);white-space:nowrap;}
.rec-qa-name{margin-right:4px;font-weight:var(--fw-semibold);color:var(--text);}
.rec-qa-more{
  margin-top:auto;align-self:flex-start;display:inline-flex;align-items:center;gap:12px;padding:12px 18px;
  border:1px dashed var(--line-strong);border-radius:var(--r-lg) var(--r-lg) var(--r-lg) var(--r-tail);
  font-size:var(--fs-small);color:var(--muted);transition:border-color var(--dur) ease,background var(--dur) ease,color var(--dur) ease;
}
.rec-qa:hover .rec-qa-more{border-color:var(--color-recs);background:var(--pink-tint);color:var(--color-recs-hover);}
.rec-qa-dots{display:inline-flex;gap:5px;}
.rec-qa-dots span{width:7px;height:7px;border-radius:50%;background:var(--muted);animation:recQaBlink 1.2s infinite;}
.rec-qa-dots span:nth-child(2){animation-delay:.15s;}
.rec-qa-dots span:nth-child(3){animation-delay:.3s;}
@keyframes recQaBlink{0%,100%{opacity:.3;}50%{opacity:1;}}
@media (prefers-reduced-motion: reduce){
  .rec-qa-dots span{animation:none;}
  .rec-qa,.rec-qa-more{transition:none;}
  .rec-qa:hover{transform:none;}
}
@media (max-width: 900px){
  section#recommendations{padding:20px 20px 88px;gap:40px;}
  .rec-qa{flex-basis:300px;padding:24px;}
  .rec-qa-who{white-space:normal;}
}
@media (max-width: 640px){
  .rec-qa{flex-basis:100%;}
}

/* Resume */
section#resume{padding:0 40px 100px;}
.resume-row{
  display:flex;justify-content:space-between;gap:24px;border-top:1px solid var(--line);padding:22px 0;
}
.resume-row:not(:has(+ .resume-row)){border-bottom:1px solid var(--line);}
.resume-role{font-size:var(--fs-body);font-weight:var(--fw-semibold);margin-bottom:4px;}
.resume-detail{font-size:var(--fs-label);color:var(--muted);}
.resume-dates{font-family:var(--font-mono);font-size:var(--fs-micro);color:var(--muted);white-space:nowrap;padding-top:2px;}

/* Footer. Spec: handoff/footer/README.md. One footer on every page: headline and email, Site and Elsewhere
   lists, then the credits line, whose three triggers open a panel under it (one at a time, script.js).
   Under 640px the email becomes a card with a copy button, the credits become rows, and Top moves to the
   bottom row. Both layouts are in the markup; each breakpoint hides the other's parts.
   Accent: --lime-bright in dark, deep lavender in light (the light block sets the footer's accent set). */
footer{border-top:1px solid var(--line);padding:48px 0;}
.site-footer{
  --accent:var(--lime-bright);--accent-large:var(--lime-bright);--accent-fill:var(--lime-bright);--accent-hover:var(--text);
  --foot-link:var(--text);              /* nav links: --text-2 in light */
  --foot-label:var(--muted);            /* list labels: --text in light */
  --foot-panel:var(--lime-bright);      /* credit panels: pastel lavender in light */
  --foot-panel-label:color-mix(in oklch, var(--ink) 70%, transparent);
  --foot-card:var(--surface);           /* mobile email card: --surface-2 in light */
  --foot-chip:var(--surface-2);         /* copy button and Top pill: lavender tint in light */
  --foot-tap:52px;                      /* tap targets from the handoff: buttons and mobile rows */
  --foot-row:72px;                      /* mobile credit rows */
  --foot-chev:36px;                     /* mobile chevron disc */
  padding:calc(var(--space-section) + var(--space-4)) 0 var(--space-8);
}
.site-footer > .wrap{display:flex;flex-direction:column;gap:var(--space-section);padding-inline:var(--gutter);}
.site-footer :is(a,button):focus-visible{outline:var(--focus-width) solid var(--lavender);outline-offset:var(--focus-offset);border-radius:var(--r-xs);}

.foot-top{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-8);}
.foot-hello{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-5);min-width:0;}
.foot-headline{margin:0;font-size:var(--fs-h2);font-weight:var(--fw-semibold);line-height:var(--lh-tight);letter-spacing:var(--ls-heading);color:var(--text);}
/* The email and the credit triggers share the link wipe: an --accent underline at rest, and the
   --foot-panel fill wipes up behind the text on hover with --on-accent text */
.foot-email,.cred-trigger{
  background-image:linear-gradient(var(--accent),var(--accent)),linear-gradient(var(--foot-panel),var(--foot-panel));
  background-position:left bottom,left bottom;background-repeat:no-repeat;
  transition:background-size var(--dur-wipe) var(--ease-wipe),color var(--dur) ease;
}
.foot-email{
  font-size:var(--fs-h3);font-weight:var(--fw-semibold);line-height:var(--lh-snug);color:var(--accent);
  padding:0 4px;margin:0 -4px;border-radius:var(--r-xs);background-size:100% 2px,100% 0%;
}
.foot-email:is(:hover,:focus-visible){background-size:100% 2px,100% 100%;color:var(--on-accent);}

.foot-nav{display:flex;gap:var(--space-section);}
.foot-label{display:block;margin-bottom:var(--space-2);font-family:var(--font-mono);font-size:var(--fs-label);line-height:var(--lh-ui);color:var(--foot-label);}
.foot-col ul{margin:0;padding:0;list-style:none;}
.foot-link{
  display:flex;align-items:center;gap:6px;min-height:44px;
  font-size:var(--fs-body-lg);line-height:var(--lh-ui);color:var(--foot-link);transition:color var(--dur) ease;
}
.foot-link:hover{color:var(--accent);}
.foot-ext{font-size:var(--fs-label);color:var(--muted);}
.foot-link:hover .foot-ext{color:inherit;}

/* Credits line and panels (above 640px) */
.foot-credits{display:flex;flex-direction:column;gap:var(--space-6);}
.foot-bottom{
  display:flex;justify-content:space-between;align-items:center;gap:var(--space-5);
  padding-top:var(--space-6);border-top:1px solid var(--line);
}
.foot-credits-line{margin:0;font-size:var(--fs-body-lg);line-height:var(--lh-body);color:var(--muted);}
.cred-trigger{
  margin:0 2px;padding:2px 4px 3px;border:0;border-radius:var(--r-xs);
  background-color:transparent;background-size:100% 1px,100% 0%;color:var(--accent);cursor:pointer;
}
.cred-trigger:is(:hover,:focus-visible){background-size:100% 1px,100% 100%;color:var(--on-accent);}
.cred-trigger[aria-expanded="true"]{background:var(--accent);color:var(--bg);}
.foot-copyright{font-family:var(--font-mono);font-size:var(--fs-small);line-height:var(--lh-ui);color:var(--muted);white-space:nowrap;}

.cred-panel{
  display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-7);
  padding:var(--space-8);border-radius:var(--r-lg);background:var(--foot-panel);color:var(--ink);
  animation:cred-in var(--dur-wipe) var(--ease-wipe);
}
.cred-panel[hidden]{display:none;}
.cred-panel-body{display:flex;flex-direction:column;gap:var(--space-3);max-width:1000px;}
.cred-panel-label{font-family:var(--font-mono);font-size:var(--fs-small);line-height:var(--lh-ui);color:var(--foot-panel-label);}
.cred-panel-title{margin:0;font-size:var(--fs-h3);font-weight:var(--fw-semibold);line-height:var(--lh-snug);letter-spacing:var(--ls-tight);}
.cred-panel p{margin:0;font-size:var(--fs-lead);line-height:var(--lh-body);}
.cred-close{
  flex:none;display:grid;place-items:center;width:var(--foot-tap);height:var(--foot-tap);border-radius:50%;
  border:1px solid color-mix(in oklch, var(--ink) 30%, transparent);background:none;color:var(--ink);cursor:pointer;
  transition:background-color var(--dur) ease,color var(--dur) ease;
}
.cred-close:hover{background:var(--ink);color:var(--foot-panel);}
.site-footer .cred-panel :is(a,button):focus-visible{outline-color:var(--ink);border-radius:50%;}
@keyframes cred-in{from{opacity:0;transform:translateY(8px);}}

/* Phone-only parts, hidden above 640px */
.foot-card,.foot-m-credits,.foot-m-bottom,.foot-narrow{display:none;}

/* 900px and under: the top block stacks */
@media (max-width: 900px){
  .foot-top{flex-direction:column;}
}

/* Phones */
@media (max-width: 640px){
  .site-footer{padding:var(--space-section) 0 var(--space-6);}
  .site-footer > .wrap{gap:var(--space-7);}
  .foot-email,.foot-credits,.foot-wide{display:none;}
  .foot-top{gap:var(--space-7);align-items:stretch;}
  .foot-hello{align-items:stretch;}

  /* Email card: the whole address area is the mailto link, the copy button sits on the right */
  .foot-card{
    display:flex;align-items:center;gap:var(--space-2);
    padding:var(--space-2) var(--space-2) var(--space-2) var(--space-4);border-radius:var(--r-lg);background:var(--foot-card);
  }
  .foot-card-link{flex:1 1 auto;min-width:0;min-height:var(--foot-tap);display:flex;flex-direction:column;justify-content:center;gap:2px;}
  .foot-card-label{font-family:var(--font-mono);font-size:var(--fs-label);line-height:var(--lh-ui);color:var(--muted);}
  .foot-card-address{
    overflow:hidden;white-space:nowrap;text-overflow:ellipsis;
    font-size:var(--fs-body-lg);font-weight:var(--fw-semibold);line-height:var(--lh-ui);color:var(--accent);
  }
  .foot-copy{
    flex:none;display:grid;place-items:center;width:var(--foot-tap);height:var(--foot-tap);
    border:0;border-radius:var(--r-md);background:var(--foot-chip);color:var(--text);cursor:pointer;
  }
  .foot-copy .icon-done,.foot-copy.is-copied .icon-copy{display:none;}
  .foot-copy.is-copied .icon-done{display:block;color:var(--accent);}

  /* Site and Elsewhere side by side; every link a row with a divider, except each column's last */
  .foot-nav{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--space-5);}
  .foot-narrow{display:list-item;}
  .foot-label{margin-bottom:var(--space-1);}
  .foot-link{min-height:var(--foot-tap);border-bottom:1px solid var(--line-soft);}
  .foot-col li:last-child .foot-link{border-bottom:0;}

  /* Credits: three disclosure rows, one open at a time */
  .foot-m-credits{display:block;border-top:1px solid var(--line);}
  .cred-item{border-bottom:1px solid var(--line);}
  .cred-row{
    width:100%;display:grid;grid-template-columns:1fr var(--foot-chev);align-items:center;column-gap:var(--space-3);
    min-height:var(--foot-row);padding:var(--space-2) 0;border:0;background:none;text-align:left;cursor:pointer;
  }
  .cred-row-text{display:flex;flex-direction:column;gap:2px;}
  .cred-row-lead{font-family:var(--font-mono);font-size:var(--fs-label);line-height:var(--lh-ui);color:var(--muted);}
  .cred-row-title{font-size:var(--fs-body-lg);font-weight:var(--fw-semibold);line-height:var(--lh-snug);color:var(--accent);}
  .cred-chev{
    display:grid;place-items:center;width:var(--foot-chev);height:var(--foot-chev);border-radius:50%;
    border:1px solid var(--line-strong);color:var(--accent);transition:transform var(--dur) ease;
  }
  .cred-row[aria-expanded="true"] .cred-chev{transform:rotate(180deg);}
  .cred-m-panel{
    display:flex;flex-direction:column;gap:var(--space-3);margin-bottom:var(--space-4);padding:var(--space-5);
    border-radius:var(--r-lg);background:var(--foot-panel);color:var(--ink);animation:cred-in var(--dur-wipe) var(--ease-wipe);
  }
  .cred-m-panel[hidden]{display:none;}
  .cred-m-panel .cred-panel-label{font-size:var(--fs-label);}
  .cred-m-title{margin:0;font-size:var(--fs-title);font-weight:var(--fw-semibold);line-height:var(--lh-snug);}
  .cred-m-panel p{margin:0;font-size:var(--fs-body);line-height:var(--lh-body);}

  .foot-m-bottom{display:flex;justify-content:space-between;align-items:center;gap:var(--space-3);}
  .foot-m-bottom .foot-copyright{font-size:var(--fs-label);}
  .foot-top-pill{
    display:inline-flex;align-items:center;gap:var(--space-2);min-height:var(--foot-tap);padding:0 var(--space-5);
    border-radius:var(--r-pill);background:var(--foot-chip);
    font-size:var(--fs-small);font-weight:var(--fw-semibold);color:var(--text);
  }
  .foot-top-pill:hover{color:var(--accent);}
  .site-footer .foot-top-pill:focus-visible{border-radius:var(--r-pill);}
}
@media (prefers-reduced-motion: reduce){
  .cred-panel,.cred-m-panel{animation:none;}
  .cred-trigger,.cred-close,.cred-chev,.foot-email,.foot-link{transition:none;}
}

/* Shared link hover: an underline that wipes up to a fill, for text links.
   Text is --accent and the band is --accent-fill, so it follows the section's .accent-* class. */
.link-wipe{
  color:var(--accent);
  background:linear-gradient(var(--accent-fill),var(--accent-fill)) no-repeat left bottom / 100% 1px;
  padding:0 3px;margin:0 -1px;border-radius:var(--r-xs);
  transition:background-size var(--dur-wipe) var(--ease-wipe),color var(--dur) ease;
}
.link-wipe:hover,.link-wipe:focus-visible{background-size:100% 100%;color:var(--on-accent);}
.link-wipe:focus-visible{outline:var(--focus-width) solid var(--accent);outline-offset:var(--focus-offset);}
@media (prefers-reduced-motion: reduce){.link-wipe{transition:none;}}
/* Action link: a standalone link with an arrow (DESIGN_SYSTEM.md 6.2). Older class names on the same
   elements (.rw-link, .csc-more, .cst-end-link and so on) only carry layout. */
.link-action{
  display:inline-flex;align-items:center;gap:6px;
  font-family:var(--font-mono);font-size:var(--fs-small);font-weight:var(--fw-semibold);line-height:var(--lh-ui);
  color:var(--accent);transition:color var(--dur) ease;
  text-decoration:underline 3px var(--accent-mark);text-underline-offset:5px;
}
.link-action:hover,.csc:hover .link-action{color:var(--accent-hover);}
.link-arrow{display:inline-block;transition:transform var(--dur-fast) ease;}
/* Standalone action links get a 44px tap area; the negative margin keeps the layout where it was */
.cst-back,.cst-end-link,.abt-card-link,.recs-all-link,.recs-entry-li{min-height:44px;margin-block:-11px;}
.link-action:hover .link-arrow,.csc:hover .link-arrow{transform:translateX(var(--nudge));}
.link-action:hover .link-arrow--back{transform:translateX(calc(-1 * var(--nudge)));}
.link-action:hover .link-arrow--down{transform:translateY(var(--nudge));}


/* Case study page header */
.cs-page-header{padding:36px 40px 0;}
.cs-page-header .brand{color:var(--text);text-decoration:none;}

/* Recommendations (full page): "Ask them" Q&A, then all recommendations in full.
   Spec in handoff/recommendations-handover/. Data in assets/recommendations.json, rendered by script.js.
   Mockup values mapped to the site's colours: #131317 the page background oklch(0.19), #18181D the panel oklch(0.22),
   #24242A the bubble oklch(0.27), #2A2A31 dividers oklch(0.3), #3A3A42 chip borders oklch(0.34),
   #ECEAE5 text oklch(0.94), #D2D0CA body oklch(0.85), #A3A1AA muted oklch(0.76), #8E8C96 faint labels oklch(0.7). */
.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;}

.recs [hidden]{display:none;}
.recs-label{font-family:var(--font-mono);font-size:var(--fs-label);color:var(--muted);}
.recs-avatar{
  flex:none;width:44px;height:44px;border-radius:50%;background:var(--line);color:var(--pink);
  display:flex;align-items:center;justify-content:center;font-size:var(--fs-small);font-weight:var(--fw-semibold);
}
.case-cta--lg{
  gap:10px;min-height:56px;padding:0 28px;font-size:var(--fs-body);font-weight:var(--fw-bold);
}
.recs a:focus-visible,.recs button:focus-visible,.recs summary:focus-visible{outline:var(--focus-width) solid var(--color-recs);outline-offset:var(--focus-offset);}

/* Ask them */
/* Header: shared PageHeader (.ph); the questions and chat panel are its entry row */
.ph.recs-ask{padding-bottom:80px;}
.recs-intro{margin:0;font-size:var(--fs-title);line-height:var(--lh-body);color:var(--muted);}
.recs-ask-body{display:flex;flex-wrap:wrap;gap:56px;align-items:flex-start;}

.recs-questions-col{flex:1 1 340px;min-width:0;max-width:440px;display:flex;flex-direction:column;align-items:flex-start;gap:24px;}
.recs-questions{align-self:stretch;display:flex;flex-direction:column;gap:12px;}
/* Jumps to All recommendations below the chat */
.recs-all-link{margin-left:20px;}
.recs-questions .recs-label{margin-bottom:4px;}
.recs-q{
  display:flex;align-items:center;justify-content:space-between;gap:16px;width:100%;min-height:64px;padding:14px 22px;
  border-radius:var(--r-md);border:1px solid var(--line);background:transparent;color:var(--text);
  font-family:inherit;font-size:var(--fs-body-lg);font-weight:var(--fw-semibold);line-height:var(--lh-ui);letter-spacing:inherit;text-align:left;cursor:pointer;
  transition:background var(--dur) ease,border-color var(--dur) ease,color var(--dur) ease;
}
.recs-q:hover{border-color:var(--color-recs);}
.recs-q[aria-pressed="true"]{background:var(--accent-fill);border-color:var(--accent-fill);color:var(--on-accent);}
.recs-q-arrow{flex:none;font-family:var(--font-mono);font-size:var(--fs-body-lg);transition:transform var(--dur) ease;}
.recs-q:hover .recs-q-arrow{transform:translateX(var(--nudge));}

.recs-panel{
  flex:999 1 560px;min-width:0;min-height:640px;padding:40px;border-radius:var(--r-lg);background:var(--surface);
  display:flex;flex-direction:column;gap:28px;
}
.recs-you{display:flex;flex-direction:column;align-items:flex-end;gap:8px;}
.recs-you .recs-label{font-size:var(--fs-label);}
.recs-you-bubble{
  margin:0;max-width:520px;padding:18px 24px;border-radius:var(--r-lg) var(--r-lg) var(--r-tail) var(--r-lg);background:var(--accent-fill);
  color:var(--on-accent);font-size:var(--fs-lead);font-weight:var(--fw-semibold);line-height:var(--lh-ui);
}
/* Question picker at the top of the chat: only when stacked (below 900px), built by script.js */
.recs-switch{display:none;}
.recs-switch-field{position:relative;}
.recs-switch-select{
  appearance:none;-webkit-appearance:none;display:block;width:100%;min-height:56px;padding:14px 48px 14px 20px;
  border:1px solid var(--line-strong);border-radius:var(--r-md);background:var(--surface-2);color:var(--text);
  font-family:inherit;font-size:var(--fs-body);font-weight:var(--fw-semibold);line-height:var(--lh-ui);letter-spacing:inherit;cursor:pointer;
}
.recs-switch-select:focus-visible{outline:var(--focus-width) solid var(--color-recs);outline-offset:var(--focus-offset);}
.recs-switch-arrow{position:absolute;top:50%;right:20px;transform:translateY(-50%);pointer-events:none;font-family:var(--font-mono);font-size:var(--fs-body-lg);color:var(--accent);}
.recs-answers{display:flex;flex-direction:column;gap:22px;}
.recs-answer{margin:0;display:flex;gap:14px;align-items:flex-end;max-width:640px;}
.recs-answer-body{display:flex;flex-direction:column;gap:8px;min-width:0;}
.recs-answer figcaption{font-size:var(--fs-small);color:var(--muted);}
.recs-answer-name{margin-right:8px;font-weight:var(--fw-semibold);color:var(--text);}
.recs-answer blockquote{
  margin:0;padding:18px 24px;border-radius:var(--r-lg) var(--r-lg) var(--r-lg) var(--r-tail);background:var(--bubble-fill);
  font-size:var(--fs-body-lg);line-height:var(--lh-body);color:var(--text);
}
.recs-answers.is-animating .recs-answer{opacity:0;animation:recsBubbleIn .45s cubic-bezier(.2,.8,.2,1) forwards;}
.recs-answers.is-animating .recs-answer:nth-child(2){animation-delay:.45s;}
.recs-answers.is-animating .recs-answer:nth-child(3){animation-delay:.9s;}
.recs-answers.is-animating .recs-answer:nth-child(4){animation-delay:1.35s;}
.recs-answers.is-animating .recs-answer:nth-child(5){animation-delay:1.8s;}
@keyframes recsBubbleIn{from{opacity:0;transform:translateY(14px);}to{opacity:1;transform:none;}}

/* All recommendations */
.recs-all{padding:0 40px 120px;scroll-margin-top:32px;}
.recs-all-inner{display:flex;flex-direction:column;gap:56px;}
.recs-all-head{
  display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:32px;
  border-top:1px solid var(--line);padding-top:56px;
}
.recs-all-title{display:flex;flex-direction:column;gap:16px;max-width:640px;}
.recs-all-title h2{margin:0;font-size:var(--fs-h2);font-weight:var(--fw-bold);line-height:var(--lh-tight);letter-spacing:var(--ls-heading);}
.recs-all-title p{margin:0;font-size:var(--fs-body-lg);line-height:var(--lh-body);color:var(--muted);}
.recs-chips{display:flex;flex-wrap:wrap;gap:10px;}
.recs-chip{
  display:inline-flex;align-items:center;gap:10px;min-height:44px;padding:0 20px;border-radius:var(--r-pill);
  border:1px solid var(--line-strong);background:transparent;color:var(--text);
  font-family:inherit;font-size:var(--fs-body);font-weight:var(--fw-semibold);letter-spacing:inherit;cursor:pointer;
  transition:background var(--dur) ease,border-color var(--dur) ease,color var(--dur) ease;
}
.recs-chip:hover{border-color:var(--color-recs);}
.recs-chip[aria-pressed="true"]{background:var(--accent-fill);border-color:var(--accent-fill);color:var(--on-accent);}
.recs-chip-count{font-family:var(--font-mono);font-size:var(--fs-label);opacity:.75;}

.recs-all-body{display:flex;flex-wrap:wrap;gap:72px;align-items:flex-start;}
.recs-index{flex:1 1 240px;max-width:280px;min-width:0;position:sticky;top:32px;display:flex;flex-direction:column;}
.recs-index .recs-label,.recs-jump summary{font-size:var(--fs-label);padding-bottom:10px;border-bottom:1px solid var(--line);}
.recs-index-link{
  display:flex;justify-content:space-between;gap:12px;padding:9px 0;border-bottom:1px solid var(--line-soft);
  font-size:var(--fs-small);color:var(--text-2);transition:color var(--dur) ease;
}
.recs-index-link:hover{color:var(--pink);}
.recs-index-year{font-family:var(--font-mono);font-size:var(--fs-label);color:var(--muted);}
.recs-jump{display:none;}

.recs-list{flex:999 1 600px;min-width:0;display:flex;flex-direction:column;}
.recs-entry{
  scroll-margin-top:32px;display:flex;flex-direction:column;gap:24px;padding:48px 0;
  border-bottom:1px solid var(--line);
}
.recs-entry-meta{display:flex;flex-wrap:wrap;align-items:center;gap:12px;}
.recs-entry-date{font-family:var(--font-mono);font-size:var(--fs-label);color:var(--muted);}
.recs-entry-rel{padding:4px 12px;border:1px solid var(--color-recs-border);border-radius:var(--r-pill);font-size:var(--fs-label);color:var(--color-recs-hover);}
.recs-entry-lead{margin:0;max-width:820px;font-size:var(--fs-h3);font-weight:var(--fw-semibold);line-height:var(--lh-snug);letter-spacing:var(--ls-tight);color:var(--accent-large);}
.recs-entry-text{display:flex;flex-direction:column;gap:16px;max-width:720px;}
.recs-entry-text p{margin:0;font-size:var(--fs-body-lg);line-height:var(--lh-body);color:var(--text-2);}
.recs-entry footer{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:16px;margin-top:4px;}
.recs-entry-who{display:flex;align-items:center;gap:14px;}
.recs-entry-who .recs-avatar{width:48px;height:48px;font-size:var(--fs-body);}
.recs-entry-who > span:last-child{display:flex;flex-direction:column;gap:2px;}
.recs-entry-name{font-size:var(--fs-body-lg);font-weight:var(--fw-semibold);}
.recs-entry-role{font-size:var(--fs-small);color:var(--muted);}
.recs-entry-li{font-family:var(--font-mono);font-size:var(--fs-small);color:var(--muted);}
.recs-entry-li:hover{color:var(--pink);}
.recs-list > .case-cta--lg{align-self:flex-start;margin-top:48px;}

@media (max-width: 900px){
  .ph.recs-ask{padding-bottom:56px;}
  .recs-ask-body{flex-direction:column;align-items:stretch;gap:40px;}
  .recs-questions-col{flex:none;max-width:none;}
  .recs-panel{flex:none;min-height:auto;padding:24px 20px;border-radius:var(--r-lg);scroll-margin-top:var(--space-4);}
  .recs-switch{display:flex;flex-direction:column;gap:var(--space-2);padding-bottom:var(--space-5);border-bottom:1px solid var(--line);}
  .recs-all-link{display:none;}
  .recs-answer blockquote{padding:16px 20px;}
  .recs-answer{gap:10px;}
  .recs-answer .recs-avatar{width:34px;height:34px;}

  .recs-all{padding:0 20px 88px;}
  .recs-all-head{padding-top:40px;}
  .recs-all-body{flex-direction:column;align-items:stretch;gap:32px;}
  .recs-index{display:none;}
  .recs-jump{display:block;}
  .recs-jump summary{cursor:pointer;font-family:var(--font-mono);color:var(--muted);}
  .recs-jump summary{display:flex;align-items:center;justify-content:space-between;min-height:44px;list-style:none;}
  .recs-jump summary::-webkit-details-marker{display:none;}
  .recs-jump summary::after{content:"\2193";transition:transform var(--dur) ease;}
  .recs-jump[open] summary::after{transform:rotate(180deg);}
  .recs-jump .recs-index-link{min-height:44px;align-items:center;}
  .recs-list{flex:none;}
  .recs-entry{padding:40px 0;}
}

@media (prefers-reduced-motion: reduce){
  .recs-answers.is-animating .recs-answer{animation:none;opacity:1;}
  .recs-q,.recs-q-arrow,.recs-chip,.recs-index-link,.case-cta--lg .case-cta-arrow{transition:none;}
}

/* PageHeader: the shared header on Work, Projects, About and Recommendations.
   Spec: handoff/page-headers/page-headers-handover.md (and projects-header/ for Projects).
   Markup: <header class="site-header ph-nav wrap"> for the nav, then a .ph section holding .ph-eyebrow,
   .ph-title, .ph-intro and, when the page has one, an entry row (.ph-entry, usually .ph-cards).
   Hex values map to the site's colours: #EEEBF3 text oklch(0.94), #A9A5B5 muted oklch(0.76),
   #C4C0CF secondary oklch(0.85), #1E1C26 card oklch(0.22), #34313F border oklch(0.3).
   Container: the same .wrap edge as the nav and page body, so every page shares one left edge. */
.ph-nav{padding:36px 40px 0;}
.ph-nav .brand{color:var(--text);text-decoration:none;}
.primary-nav .nav-link[aria-current="page"]{color:var(--text);}
.ph-nav nav.primary-nav{margin-bottom:clamp(64px,9vw,128px);}
.ph{max-width:1240px;margin:0 auto;padding:0 40px 88px;}
.ph-eyebrow{display:block;margin:0 0 32px;font-family:var(--font-mono);font-size:var(--fs-body-lg);font-weight:var(--fw-regular);color:var(--muted);}
/* Same type as the homepage .hero-title, so every page headline reads at one size; balanced so lines wrap evenly */
.ph-title{margin:0 0 32px;max-width:900px;font-size:var(--fs-display);font-weight:var(--fw-black);line-height:var(--lh-tight);letter-spacing:var(--ls-display);color:var(--text);text-wrap:balance;}
.ph-intro{margin:0;max-width:700px;font-size:var(--fs-lead);line-height:var(--lh-body);color:var(--text-2);}
.ph-entry{margin-top:72px;}
/* Media slot (About only): text column keeps its widths, the picture takes the right */
.ph-split{display:flex;flex-wrap:wrap;gap:64px;align-items:flex-start;}
.ph-split-text{flex:1 1 560px;max-width:700px;}
.ph-media{flex:1 1 360px;min-width:0;max-height:640px;aspect-ratio:4/5;}
.ph-media img{display:block;width:100%;height:100%;max-height:640px;object-fit:cover;border-radius:var(--r-lg);border:1px solid var(--line-strong);}

/* Entry cards: one per thing on the page, each jumping to it further down. --accent is the name colour. */
.ph-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--ph-card-min,240px),1fr));gap:24px;}
.ph-card{
  display:flex;justify-content:space-between;align-items:center;gap:16px;padding:28px 32px;border-radius:var(--r-lg);
  border:1px solid var(--line);background:var(--surface);color:var(--accent);
  transition:border-color var(--dur) ease,transform var(--dur-fast) ease;
}
.ph-card:hover{color:var(--accent);border-color:var(--accent);transform:var(--lift);}
.ph-card:focus-visible{outline:var(--focus-width) solid var(--accent);outline-offset:var(--focus-offset);}
/* Text fills the card's height and the name sits at the bottom, so names line up across a row whatever the label wraps to */
.ph-card-text{display:flex;flex-direction:column;gap:10px;align-self:stretch;}
.ph-card-name{margin-top:auto;}
.ph-card-label{font-family:var(--font-mono);font-size:var(--fs-small);font-weight:var(--fw-regular);color:var(--muted);}
.ph-card-name{font-size:var(--fs-h3);font-weight:var(--fw-bold);line-height:var(--lh-tight);letter-spacing:var(--ls-heading);}
.ph-card-arrow{flex:none;font-size:22px;color:var(--muted);transition:transform var(--dur-fast) ease;}
.ph-card:hover .ph-card-arrow{color:var(--accent-large);transform:translateY(3px);}
/* Go arrows (→) nudge in their own direction instead of down */
.ph-card:hover .ph-card-arrow--go{transform:translateX(var(--nudge));}
@media (prefers-reduced-motion: no-preference){
  html:has(.ph-cards),html:has(.recs-all-link){scroll-behavior:smooth;}
}
@media (prefers-reduced-motion: reduce){
  .ph-card,.ph-card-arrow{transition:none;}
}
@media (max-width: 900px){
  .ph-nav{padding:24px 20px 0;}
  .ph{padding:0 20px 56px;}
  .work-callouts{padding:0 20px 72px;}
}

/* Projects (personal projects page) */
.prj-cards{--ph-card-min:260px;}

/* "colour": a dotted underline like the homepage hero words (.rw .hl) at rest; on hover the letters hop and change colour.
   The letters are inline-block so they can move, which stops a text-decoration on the wrapper reaching them,
   so ::after redraws the word in transparent ink with a dotted text-decoration.
   The empty alt text keeps ::after out of the heading's accessible name; the visually hidden span supplies the word. */
.prj-cw{position:relative;display:inline-block;white-space:nowrap;}
.prj-cw::after{
  content:attr(data-word);content:attr(data-word) / "";position:absolute;inset:0;color:transparent;pointer-events:none;transform-origin:left center;
  text-decoration-line:underline;text-decoration-style:dotted;text-decoration-color:var(--lavender);
  text-decoration-thickness:4px;text-underline-offset:9px;
}
.prj-cw-l{display:inline-block;transition:color var(--dur-fast);transition-delay:calc(var(--i) * 60ms);}
.prj-cw:hover .prj-cw-l{color:var(--c);animation:prj-cw-hop .55s cubic-bezier(.3,1.6,.5,1) both;animation-delay:calc(var(--i) * 60ms);}
.prj-cw:hover::after{animation:prj-cw-pop var(--dur-slow) cubic-bezier(.3,1.6,.5,1) both;}
@keyframes prj-cw-hop{0%{transform:none;}40%{transform:translateY(-.28em) rotate(-8deg);}100%{transform:none;}}
@keyframes prj-cw-pop{0%{transform:scaleX(1);}35%{transform:scaleX(1.06) scaleY(1.6);}100%{transform:scaleX(1);}}

.prj-project{padding:72px 40px 96px;border-top:1px solid var(--line-soft);scroll-margin-top:16px;}
.prj-project-head{display:grid;grid-template-columns:1.3fr 1fr;gap:56px;align-items:start;margin-bottom:40px;}
.prj-role{font-family:var(--font-mono);font-size:var(--fs-micro);color:var(--accent);margin-bottom:14px;}
.prj-role:has(+ .prj-role-detail){margin-bottom:4px;}
.prj-role-detail{margin:0 0 14px;font-size:var(--fs-small);line-height:var(--lh-ui);color:var(--muted);}
.prj-role-tags{display:flex;flex-wrap:wrap;gap:8px;list-style:none;padding:0;margin-top:0;}
.prj-role-tags li{padding:4px 10px;border:1px solid color-mix(in oklch,var(--accent) 45%,transparent);border-radius:var(--r-pill);}
.prj-project h2{margin:0 0 10px;font-size:var(--fs-h2);font-weight:var(--fw-bold);line-height:var(--lh-tight);letter-spacing:var(--ls-tight);}
.prj-tagline{margin:0 0 18px;font-size:var(--fs-title);font-weight:var(--fw-semibold);line-height:var(--lh-ui);color:var(--accent-large);}
.prj-body{margin:0;font-size:var(--fs-small);line-height:var(--lh-body);color:var(--text-2);max-width:60ch;}
.prj-highlights{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;}
.prj-highlights li{
  display:grid;grid-template-columns:96px 1fr;gap:16px;padding:16px 0;
  border-top:1px solid var(--line);font-size:var(--fs-small);line-height:var(--lh-body);color:var(--text-2);
}
.prj-highlights li:last-child{border-bottom:1px solid var(--line);}
.prj-hl-k{font-family:var(--font-mono);font-size:var(--fs-micro);color:var(--accent);padding-top:3px;}

/* Masonry-style gallery: columns keep mixed portrait/landscape photos at their natural ratio */
.prj-gallery{columns:3;column-gap:16px;}
.prj-shot{margin:0 0 16px;break-inside:avoid;}
.prj-shot button{
  display:block;width:100%;padding:0;border:1px solid var(--line);border-radius:var(--r-sm);overflow:hidden;
  background:var(--surface);cursor:zoom-in;appearance:none;
  transition:border-color var(--dur) ease,transform var(--dur-fast) ease;
}
.prj-shot button:hover{border-color:var(--accent);transform:var(--lift);}
.prj-shot button:focus-visible{outline:var(--focus-width) solid var(--accent);outline-offset:var(--focus-offset);border-color:var(--accent);}
.prj-shot img{display:block;width:100%;height:auto;}
/* Feature grid: a lead landscape + portrait pair on top, a row of three below */
.prj-gallery--feature{columns:auto;display:grid;grid-template-columns:repeat(6,1fr);gap:16px;}
.prj-gallery--feature .prj-shot{grid-column:span 2;margin:0;display:flex;flex-direction:column;}
.prj-gallery--feature .prj-shot:first-child{grid-column:span 4;}
.prj-gallery--feature .prj-shot button{flex:1;}
.prj-gallery--feature .prj-shot img{height:100%;object-fit:cover;}
.prj-gallery--feature .prj-shot:first-child img{aspect-ratio:4/3;}
.prj-gallery--feature .prj-shot:nth-child(2) img{aspect-ratio:2/3;}
.prj-gallery--feature .prj-shot:nth-child(n+3) img{aspect-ratio:4/3;object-position:50% 30%;}
.prj-shot figcaption,.prj-feature figcaption{margin-top:8px;font-family:var(--font-mono);font-size:var(--fs-micro);color:var(--muted);}
.prj-feature figcaption b{color:var(--accent);font-weight:var(--fw-semibold);}

.prj-feature{margin:0 0 32px;}
.prj-video{aspect-ratio:16/9;border-radius:var(--r-md);overflow:hidden;border:1px solid var(--line);background:var(--bg-sunken);}
.prj-video iframe{display:block;width:100%;height:100%;border:0;}

.prj-stages{display:flex;flex-direction:column;gap:40px;}
.prj-stage-label{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:12px;row-gap:4px;margin-bottom:14px;}
.prj-stage-name{font-size:var(--fs-body-lg);font-weight:var(--fw-bold);color:var(--text);}
.prj-stage-meta{font-family:var(--font-mono);font-size:var(--fs-micro);color:var(--muted);}
/* Equal columns for however many photos an event has */
.prj-stage-pair{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:16px;}
.prj-stage-pair .prj-shot button{height:100%;}
.prj-stage-pair .prj-shot img{height:100%;object-fit:cover;}
.prj-stage-pair .prj-shot{margin:0;}

/* Case study screenshot lightbox */
.lightbox-overlay{
  position:fixed;inset:0;background:oklch(0 0 0 / 0.75);
  display:flex;align-items:center;justify-content:center;padding:24px;
  z-index:200;opacity:0;pointer-events:none;transition:opacity var(--dur) ease;
}
.lightbox-overlay.open{opacity:1;pointer-events:auto;}
.lightbox{
  position:relative;max-width:min(1100px,92vw);max-height:88vh;max-height:88dvh;
  transform:scale(.97);transition:transform var(--dur) ease;
}
.lightbox-overlay.open .lightbox{transform:scale(1);}
.lightbox-img{
  display:block;width:100%;max-height:88vh;max-height:88dvh;object-fit:contain;
  border-radius:var(--r-sm);border:1px solid var(--line);background:var(--bg-sunken);
}
.lightbox-close{
  position:absolute;top:12px;right:12px;width:44px;height:44px;border-radius:50%;
  border:1px solid var(--line-strong);background:var(--scrim-heavy);color:var(--text-2);
  font-size:var(--fs-body);cursor:pointer;display:flex;align-items:center;justify-content:center;
  transition:border-color var(--dur) ease,color var(--dur) ease;
}
.lightbox-close:hover,.lightbox-close:focus-visible{border-color:var(--lavender);color:var(--lavender);}
.lightbox-close:focus-visible{outline:var(--focus-width) solid var(--lavender);outline-offset:var(--focus-offset);}

@media (prefers-reduced-motion: reduce){
  .lightbox-overlay,.lightbox,.prj-shot button{transition:none;}
  .prj-cw:hover .prj-cw-l,.prj-cw:hover::after{animation:none;}
}

@media (max-width: 900px){
  /* Homepage: every section on the same 20px edge as recommendations */
  .site-header{padding:24px 20px 0;}
  section#case-studies{padding:0 20px 88px;}
  section#resume{padding:0 20px 88px;}
  .resume-row{flex-direction:column;gap:4px;}

  .prj-project{padding:56px 20px 72px;}
  .prj-project-head{grid-template-columns:1fr;gap:28px;}
  .prj-gallery{columns:2;column-gap:12px;}
  .prj-shot{margin-bottom:12px;}
  .prj-gallery--feature{grid-template-columns:1fr 1fr;gap:12px;}
  .prj-gallery--feature .prj-shot,.prj-gallery--feature .prj-shot:nth-child(2){grid-column:span 1;}
  .prj-gallery--feature .prj-shot:first-child{grid-column:1/-1;}
  .prj-gallery--feature .prj-shot:nth-child(2) img{aspect-ratio:3/4;}
  .prj-stage-pair{grid-auto-flow:row;gap:12px;}
  .prj-stage-name{font-size:var(--fs-body);}

  .cs-page-header{padding:24px 20px 0;}

}


@media (max-width: 640px){
  /* Smaller pills so two or three fit per row, with the label on its own line above */
  /* Phones: the controls move under the video so nothing covers it. Off the media they drop the glass:
     the now-playing pill is a surface pill and Case study is a standard secondary button. */
  /* Phones: the homepage headline scales with the content width (viewport less the 20px gutters), so it breaks
     on the same words at every phone size and "with." never sits alone on the last line. */
  .hero-title{font-size:clamp(36px, calc((100vw - 40px) * .118), 48px);}
  .reel{margin-top:var(--space-8);aspect-ratio:auto;overflow:visible;border:0;border-radius:0;background:none;}
  .reel-video{aspect-ratio:16/9;height:auto;border:1px solid var(--line-strong);border-radius:var(--r-md);background:var(--bg);}
  .reel-counter,.reel-divider,.reel-what{display:none;}
  .reel-bar{position:static;margin-top:var(--space-3);gap:var(--space-2);}
  .reel-now{
    gap:10px;padding:4px 16px 4px 4px;background:var(--surface);border-color:var(--line);color:var(--text);
    -webkit-backdrop-filter:none;backdrop-filter:none;
  }
  .reel-toggle{background:var(--text);color:var(--bg);}
  .reel-toggle:focus-visible{outline-color:var(--accent);}
  .reel-name{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;font-size:var(--fs-small);}
  .reel-cta.case-cta--glass{
    min-height:44px;padding:0 18px;gap:8px;font-size:var(--fs-label);font-weight:var(--fw-semibold);
    background:none;-webkit-backdrop-filter:none;backdrop-filter:none;border-color:var(--accent);color:var(--accent);
  }
  .reel-cta.case-cta--glass:hover{background:var(--accent-fill);color:var(--on-accent);}
  .reel-cta.case-cta--glass:focus-visible{outline-color:var(--accent);}
}

@media (prefers-reduced-motion: reduce){
  .case-cta--glass .case-cta-arrow{transition:none;}
}

/* Legal pages (privacy): plain reading text under the page header */
.legal{padding:0 var(--gutter) var(--space-section);}
.legal h2{max-width:700px;margin:var(--space-8) 0 var(--space-3);font-size:var(--fs-h4);font-weight:var(--fw-bold);line-height:var(--lh-snug);letter-spacing:var(--ls-tight);color:var(--text);}
.legal h2:first-child{margin-top:0;}
.legal p{max-width:700px;margin:0 0 var(--space-4);font-size:var(--fs-body-lg);line-height:var(--lh-body);color:var(--text-2);}
.legal .legal-updated{margin-top:var(--space-6);font-family:var(--font-mono);font-size:var(--fs-label);color:var(--muted);}


/* Light theme (DESIGN_SYSTEM.md section 10). Source: handoff/light-mode/light-tokens.css.
   It sits last so its component rules win ties with the base rules above. Guarded by @supports so
   browsers without oklch stay on the dark hex fallbacks above. */
@supports (color: oklch(0 0 0)) {
:root[data-theme="light"]{
  color-scheme: light;

  /* ---- Neutrals ---- */
  --bg-sunken:   oklch(0.945 0.012 300);
  --bg:          oklch(0.972 0.008 300);   /* lavender paper */
  --surface:     oklch(0.99 0.004 300);
  --surface-2:   oklch(0.945 0.012 300);
  --line-soft:   oklch(0.925 0.01 300);
  --line:        oklch(0.885 0.012 300);
  --line-strong: oklch(0.82 0.016 300);     /* see DS decision 6 (control borders) */

  --text:   oklch(0.22 0.02 300);           /* Lc 98 */
  --text-2: oklch(0.37 0.02 300);           /* Lc 89 on the page, 81 on tints */
  --muted:  oklch(0.49 0.016 300);          /* Lc 76 on the page. On tints use --text-2 */

  /* ---- Accents: small text, large text, fill, tint, mark, hover ---- */
  --lavender:        oklch(0.48 0.20 300);  /* deep, Lc 79 */
  --lavender-large:  oklch(0.545 0.20 300); /* vivid */
  --lavender-fill:   oklch(0.86 0.072 300); /* pastel */
  --lavender-tint:   oklch(0.935 0.022 300);
  --lavender-mark:   transparent;
  --lavender-hover:  oklch(0.40 0.18 300);

  --pink:            oklch(0.48 0.17 350);  /* deep, Lc 78 */
  --pink-large:      oklch(0.545 0.20 350);
  --pink-fill:       oklch(0.86 0.08 350);
  --pink-tint:       oklch(0.935 0.023 350);
  --pink-mark:       transparent;
  --pink-hover:      var(--text);
  --pink-line:       oklch(0.545 0.20 350 / .45);

  --orange:          var(--text);           /* no orange small text in light */
  --orange-large:    oklch(0.545 0.116 60);
  --orange-fill:     oklch(0.86 0.085 60);
  --orange-tint:     oklch(0.935 0.024 60);
  --orange-mark:     oklch(0.86 0.085 60);
  --orange-hover:    var(--text);

  --cyan:            var(--text);
  --cyan-large:      oklch(0.545 0.084 210);
  --cyan-fill:       oklch(0.86 0.10 210);
  --cyan-tint:       oklch(0.935 0.03 210);
  --cyan-mark:       oklch(0.86 0.10 210);
  --cyan-hover:      var(--text);

  --lime:            var(--text);
  --lime-large:      oklch(0.545 0.142 135);
  --lime-fill:       oklch(0.86 0.11 135);
  --lime-tint:       oklch(0.935 0.04 135);
  --lime-mark:       oklch(0.86 0.11 135);
  --lime-hover:      var(--text);

  --yellow:          oklch(0.74 0.14 80);   /* hero particles only, decorative */
  /* --lime-bright stays as it is: the values panel is a fill with --ink on it */

  --on-accent: var(--ink);                  /* fills are pastel in light, so text on them is ink */
  --bubble-fill: var(--pink-tint);          /* the "their reply" recommendation bubble */
  --shadow-card: 0 1px 2px oklch(0.3 0.05 300 / .05), 0 10px 28px -8px oklch(0.3 0.05 300 / .12);
}

/* Dark text on light reads better without thin smoothing */
:root[data-theme="light"] body{ -webkit-font-smoothing: auto; -moz-osx-font-smoothing: auto; }

/* ==========================================================================
   Light-only component rules. These are the only theme-specific component
   rules on the site. Everything else changes through tokens.
   ========================================================================== */

/* Primary button: pastel pill with ink text. Hover rings it in the vivid accent. */
[data-theme="light"] .case-cta--lg:not(.case-cta--glass){
  background: var(--accent-fill); border-color: var(--accent-fill); color: var(--on-accent);
}
[data-theme="light"] .case-cta--lg:not(.case-cta--glass):hover{
  background: var(--accent-fill); border-color: var(--accent-large); color: var(--on-accent);
}
/* Secondary button: an outline in the vivid accent with accent text. Hover fills it pastel with ink text. */
[data-theme="light"] .case-cta:not(.case-cta--lg):not(.case-cta--glass){
  background: transparent; border-color: var(--accent-large); color: var(--accent);
}
[data-theme="light"] .case-cta:not(.case-cta--lg):not(.case-cta--glass):hover{
  background: var(--accent-fill); border-color: var(--accent-fill); color: var(--on-accent);
}
/* The glass button on media stays dark glass, hover included */
[data-theme="light"] .case-cta--glass:hover{ background: var(--scrim-heavy); color: var(--on-media); }

/* Tinted surfaces: entry cards, tags, their bubbles */
[data-theme="light"] .ph-card{ background: var(--accent-tint); border-color: transparent; box-shadow: none; color: var(--accent-large); }
[data-theme="light"] .ph-card:hover{ border-color: var(--accent-fill); }
[data-theme="light"] :is(.csc-pill, .cst-tag, .recs-entry-rel){ background: var(--accent-tint); border-color: transparent; color: var(--text); }
/* Muted labels sit below Lc 75 on tints, so step them up to --text-2 there */
[data-theme="light"] :is(.ph-card-label, .ph-card-arrow){ color: var(--text-2); }

/* The link wipe rests as a highlighter band rather than a hairline */
/* The link wipe in light: a 1px underline in the vivid accent at rest (the pastel fill is too faint as a line),
   and the pastel fill wipes up under the text on hover */
[data-theme="light"] .link-wipe{
  background-image: linear-gradient(var(--accent-large), var(--accent-large)), linear-gradient(var(--accent-fill), var(--accent-fill));
  background-size: 100% 1px, 100% 0%; background-position: left bottom, left bottom; background-repeat: no-repeat;
}
[data-theme="light"] :is(.link-wipe:is(:hover, :focus-visible, [aria-expanded="true"]), a.abt-domain:hover .abt-domain-go){ background-size: 100% 1px, 100% 100%; }
/* Cyan and lime keep their colour in light where they label a project, like Jessihoopz's pink: Jess's call over
   the ink rule in DESIGN_SYSTEM.md 2.3. Vivid is the darkest tier with no deep step for these hues */
[data-theme="light"] :is(.accent-cyan, .accent-lime) :is(.prj-role, .prj-hl-k, .prj-feature figcaption b),
[data-theme="light"] .abt-inline:is(.accent-cyan, .accent-lime):not(:hover, :focus-visible){ color: var(--accent-large); }
/* Section eyebrows: orange small text is vivid orange (Lc 70), Jess's call over the ink rule in DESIGN_SYSTEM.md 2.3 */
[data-theme="light"] .accent-orange .sec-eyebrow{ color: var(--orange-large); }
/* Orange secondary buttons take vivid orange text too, to match their outline (same Lc 70 exception) */
[data-theme="light"] .accent-orange .case-cta:not(.case-cta--lg):not(.case-cta--glass):not(:hover){ color: var(--orange-large); }
/* Media controls sit on dark glass or over a reel: keep their text light, and give the callout play button a
   light hover instead of the dark one */
[data-theme="light"] .reel-what{ color: var(--on-media); }
[data-theme="light"] .csc-toggle:hover{ background: var(--surface-2); }

/* Things that sit on media keep their dark-theme look */
[data-theme="light"] .abt-tile-role{color:var(--on-media);}
[data-theme="light"] .abt-tile-name{color:var(--accent-fill);}   /* pastel reads on the photo's dark gradient */
[data-theme="light"] .lightbox-close{color:var(--on-media);}
[data-theme="light"] .lightbox-close:is(:hover,:focus-visible){border-color:var(--lavender-fill);color:var(--lavender-fill);}
/* Footer: the lavender set in light (lime small text is below Lc 75). Deep lavender text and triggers,
   pastel lavender panels, a lavender-tinted copy button and Top pill */
[data-theme="light"] .site-footer{
  --accent:var(--lavender);--accent-large:var(--lavender-large);--accent-fill:var(--lavender);--accent-hover:var(--lavender-hover);
  --foot-link:var(--text-2);--foot-label:var(--text);--foot-panel:var(--lavender-fill);--foot-panel-label:var(--lavender);
  --foot-card:var(--surface-2);--foot-chip:var(--lavender-tint);
}
/* Avatars: deep pink on --line is below Lc 75, so light fills them pastel with ink initials */
[data-theme="light"] :is(.recs-avatar,.rec-avatar){background:var(--pink-fill);color:var(--on-accent);}
/* Reels: the shadow baked into each transparent reel is clipped at the frame edge, which shows on paper.
   Fade the reel's transparent margin (--fade-*, written by the build) out from the window edge. */
[data-theme="light"] :is(.csc-video,.cst-hero-video){
  -webkit-mask-image:
    linear-gradient(to right, transparent, var(--ink) var(--fade-l,0%), var(--ink) calc(100% - var(--fade-r,0%)), transparent),
    linear-gradient(to bottom, transparent, var(--ink) var(--fade-t,0%), var(--ink) calc(100% - var(--fade-b,0%)), transparent);
  -webkit-mask-composite:source-in;
  mask-image:
    linear-gradient(to right, transparent, var(--ink) var(--fade-l,0%), var(--ink) calc(100% - var(--fade-r,0%)), transparent),
    linear-gradient(to bottom, transparent, var(--ink) var(--fade-t,0%), var(--ink) calc(100% - var(--fade-b,0%)), transparent);
  mask-composite:intersect;
}
/* Muted meta on the hero's recommendation bubble (a tint in light) steps up to --text-2 */
[data-theme="light"] .rw-bubble .rec-org{color:var(--text-2);}
}

/* Light needs oklch(), so browsers on the hex fallbacks stay dark and don't get the toggle */
@supports not (color: oklch(0 0 0)){.primary-nav .theme-toggle{display:none;}}

/* colour-fallback:start (generated by build/casestudy/colours.py, don't edit) */
@supports not (color: oklch(0 0 0)) {
:root{--bg-sunken:#0f0b15;--bg:#15121c;--surface:#1c1923;--surface-2:#25222c;--line-soft:#25222c;--line:#2f2c37;--line-strong:#393641;--text:#eceaf0;--text-2:#ceccd3;--muted:#c5c3ca;--scrim:rgba(21,18,28,0.72);--scrim-heavy:rgba(21,18,28,0.9);--glass-line:rgba(255,255,255,0.12);--ink:#15121c;--on-media:#eceaf0;--lavender:#d5baff;--lavender-hover:#eadcff;--pink:#fbaad8;--pink-large:#ec88c2;--pink-tint:rgba(236,136,194,0.08);--pink-line:rgba(236,136,194,0.45);--orange:#f7a55f;--cyan:#56d2df;--lime:#b8f474;--lime-bright:#d3fe80;--yellow:#fdd66f;}
.case-cta--glass:hover{background:rgba(37,34,44,0.85);}
.rw .fx-neon{--neon-glow-1:rgba(184,244,116,0.8);--neon-glow-2:rgba(184,244,116,0.9);--neon-glow-3:rgba(184,244,116,0.55);}
.reel-divider{background:rgba(236,234,240,0.3);}
.csc-toggle:hover{background:#302a3b;}
.site-footer{--foot-panel-label:rgba(21,18,28,0.7);}
.cred-close{border:1px solid rgba(21,18,28,0.3);}
.prj-role-tags li{border:1px solid rgba(213,186,255,0.45);}
.lightbox-overlay{background:rgba(0,0,0,0.75);}
}
/* colour-fallback:end */
