@import url('https://fonts.googleapis.com/css2?family=Adamina&family=Caveat:wght@400&family=Inter:wght@400;500;600&display=swap');

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

@font-face {
  font-family: 'Bespoke Serif';
  src: url('../fonts/BespokeSerif-Medium.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

:root,
[data-theme="normal"] {
  /* The paper is pure white; the inks are one cool slate family (~212° hue).
     Saturation tapers as the greys lighten — the 20% that reads as slate at
     display weight reads as plainly blue by the time it is a 55% subtext. */
  --bg: #ffffff;
  --note-halo: rgba(255, 255, 255, 0.95);
  --text: #333f4d;
  --text-body: #2b3542;
  --text-muted: #586676;
  --text-subtle: #3e4c5c;
  --text-light: #818c98;
  --text-nav: #3e4c5c;
  --text-detail: #040506;
  --text-resume-header: #445161;
  --surface: #ffffff;
  --surface-muted: #ffffff;
  --border-color: #ffffff;
  --nav-bg: rgba(251, 250, 247, 0.62);
  --theme-popover-bg: rgba(251, 250, 247, 0.48);
  --nav-glass-border: rgba(253, 252, 248, 0.55);
  /* One ink per project, sampled from that project's hero wash. Shared by the work
     rows on the home page and the chrome on the project pages, so the two agree. */
  --ink-amber: #967a12;
  --ink-teal: #267d90;
  --ink-blue: #307187;
  --ink-violet: #864bb1;
  --ink-green: #3b7c68;
  --nav-shadow: 0 2px 12px rgba(0, 0, 0, 0.07), 0 1px 2px rgba(0, 0, 0, 0.04);
  --nav-active-bg: rgba(251, 250, 247, 0.5);
  --nav-active-shadow: 0 2px 10px rgba(0, 0, 0, 0.076), 0 1px 6px rgba(0, 0, 0, 0.048);
  --nav-hover-bg: rgba(0, 0, 0, 0.03);
  --nav-text-active: #0c0f13;
  --nav-text-inactive: #758291;
  --nav-pill-home: transparent;
  --nav-pill-about: transparent;
  --nav-pill-resume: transparent;
  --hero-glow: rgba(251, 250, 247, 0.5);
  --texture-opacity: 1;
  --switcher-bg: rgba(251, 250, 247, 0.72);
  --switcher-hover: rgba(0, 0, 0, 0.05);
  --white: #ffffff;
  /* White mount around framed photos; goes dark-grey on the dark canvas. */
  --frame-border: #ffffff;
  --border-white: 3px solid var(--border-color);
  --serif: 'Bespoke Serif', Georgia, serif;
  --sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  --adamina: 'Adamina', Georgia, serif;
  --hand: 'Caveat', 'Bespoke Serif', cursive;
  --content-narrow: 555px;
  --content-mid: 669px;
  --content-wide: 924px;
  --content-text: 435px;
  --about-content: 390px;
  --line-art-stroke: #3b3935;
  --content-resume: 480px;
  --resume-paper: #ffffff;
  --resume-paper-border: rgba(0, 0, 0, 0.1);
  --resume-paper-shadow:
    0 1px 2px rgba(0, 0, 0, 0.04),
    0 6px 16px rgba(0, 0, 0, 0.05),
    0 24px 48px rgba(0, 0, 0, 0.07);
  --nav-height: 48px;
  --nav-border-width: 2px;
  --nav-toolbar-height: 48px;
  --nav-toolbar-item-height: 34px;
  --nav-radius: 10px;
  --nav-item-radius: 8px;
  --nav-offset: 27px;
  --home-bottom-ascii-height: 110px;
  --home-closing-spacing-bottom: 56px;
  --footer-height: 48px;
  --work-divider-space: 55px;
  --home-content-width: calc(var(--content-mid) * 0.85);
  --home-content-padding-x: 24px;
  --selection-bg: #12110d;
  --selection-color: #ffffff;
  --location-polaroid-bg: #ffffff;
  --location-polaroid-border: rgba(0, 0, 0, 0.06);
  --location-polaroid-photo-bg: #ebe8e1;
  --location-polaroid-shadow:
    0 10px 28px rgba(0, 0, 0, 0.12),
    0 2px 6px rgba(0, 0, 0, 0.06);
  --location-polaroid-caption-amsterdam: #6c6973;
  --location-polaroid-caption-limerick: #646e7a;
}

[data-theme="dark"] {
  /* Mirror of the light palette: neutrals nudged toward blue so the dark canvas
     reads cool rather than flat black — a hint of hue, not a blue-grey. */
  --bg: #151516;
  --note-halo: rgba(0, 0, 0, 0.95);
  --nav-border-width: 1px;
  --text: #e8e8ea;
  --text-body: #f5f5f6;
  --text-muted: #a2a3a5;
  --text-subtle: #8d8e90;
  --text-light: #727375;
  --text-nav: #b0b1b3;
  --text-detail: #e1e1e3;
  --text-resume-header: #c8c9cb;
  --surface: #1f2021;
  --surface-muted: #252628;
  --border-color: #343537;
  --nav-bg: rgba(31, 32, 33, 0.62);
  --theme-popover-bg: rgba(31, 32, 33, 0.48);
  --nav-glass-border: rgba(255, 255, 255, 0.14);
  --nav-shadow: 0 2px 12px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.18);
  --nav-active-bg: rgba(43, 44, 46, 0.5);
  --nav-active-shadow: 0 2px 10px rgba(0, 0, 0, 0.332), 0 1px 6px rgba(0, 0, 0, 0.19);
  --nav-hover-bg: rgba(255, 255, 255, 0.05);
  --nav-text-active: #f7f7f8;
  --nav-text-inactive: #8d8e90;
  --nav-pill-home: transparent;
  --nav-pill-about: transparent;
  --nav-pill-resume: transparent;
  --hero-glow: rgba(255, 255, 255, 0.08);
  --texture-opacity: 0.05;
  --switcher-bg: rgba(31, 32, 33, 0.9);
  --switcher-hover: rgba(255, 255, 255, 0.08);
  --white: #1f2021;
  --frame-border: #2f3033;
  --resume-paper: #232426;
  --resume-paper-border: rgba(255, 255, 255, 0.12);
  --resume-paper-shadow:
    0 1px 2px rgba(0, 0, 0, 0.2),
    0 8px 24px rgba(0, 0, 0, 0.28),
    0 32px 64px rgba(0, 0, 0, 0.35);
  --line-art-stroke: #f1f1f2;
  --preview-frame-border: #3c3d3f;
  --preview-frame-shadow:
    0 8px 22px rgba(255, 255, 255, 0.07),
    0 1px 4px rgba(255, 255, 255, 0.05);
  --dog-polaroid-bg: #2d2e30;
  --dog-polaroid-photo-bg: #1b1b1d;
  --dog-polaroid-caption: #e8e8ea;
  --dog-polaroid-shadow:
    0 14px 36px rgba(0, 0, 0, 0.55),
    0 4px 12px rgba(0, 0, 0, 0.35),
    0 0 0 1px rgba(255, 255, 255, 0.04);
  --location-polaroid-bg: #2d2e30;
  --location-polaroid-border: rgba(255, 255, 255, 0.1);
  --location-polaroid-photo-bg: #1b1b1d;
  --location-polaroid-shadow:
    0 14px 36px rgba(0, 0, 0, 0.55),
    0 4px 12px rgba(0, 0, 0, 0.35),
    0 0 0 1px rgba(255, 255, 255, 0.04);
  --location-polaroid-caption-amsterdam: #c7c5cb;
  --location-polaroid-caption-limerick: #b8bdc3;
  --selection-bg: #f1f1f2;
  --selection-color: #151516;
}

[data-theme="pastel-blue"] {
  --bg: #e8f4fc;
  --text: #2a4a5e;
  --text-body: #1a3344;
  --text-muted: #4a7088;
  --text-subtle: #3d6278;
  --text-light: #6a90a8;
  --text-nav: #3d6278;
  --text-detail: #1a3344;
  --text-resume-header: #3d6278;
  --surface: #f5fbff;
  --surface-muted: #edf6fc;
  --border-color: #cce4f4;
  --nav-bg: rgba(245, 251, 255, 0.62);
  --theme-popover-bg: rgba(245, 251, 255, 0.48);
  --nav-glass-border: rgba(255, 255, 255, 0.6);
  --nav-shadow: 0 2px 12px rgba(42, 74, 94, 0.08), 0 1px 2px rgba(42, 74, 94, 0.05);
  --nav-active-bg: rgba(255, 255, 255, 0.5);
  --nav-active-shadow: 0 2px 10px rgba(42, 74, 94, 0.095), 0 1px 6px rgba(42, 74, 94, 0.057);
  --nav-hover-bg: rgba(42, 74, 94, 0.035);
  --nav-text-active: #1a3344;
  --nav-text-inactive: #6a90a8;
  --nav-pill-home: transparent;
  --nav-pill-about: transparent;
  --nav-pill-resume: transparent;
  --hero-glow: rgba(180, 220, 255, 0.5);
  --texture-opacity: 1;
  --switcher-bg: rgba(245, 251, 255, 0.9);
  --switcher-hover: rgba(42, 74, 94, 0.06);
  --white: #f5fbff;
  --resume-paper: #ffffff;
  --resume-paper-border: rgba(42, 74, 94, 0.1);
  --resume-paper-shadow:
    0 1px 2px rgba(42, 74, 94, 0.05),
    0 6px 16px rgba(42, 74, 94, 0.07),
    0 24px 48px rgba(42, 74, 94, 0.1);
  --line-art-stroke: #2a4a5e;
  --selection-bg: #1a3344;
  --selection-color: #ffffff;
}

[data-theme="pastel-green"] {
  --bg: #e8fbf0;
  --text: #285e42;
  --text-body: #17442f;
  --text-muted: #47886a;
  --text-subtle: #3a785a;
  --text-light: #67a888;
  --text-nav: #3a785a;
  --text-detail: #17442f;
  --text-resume-header: #3a785a;
  --surface: #f4fdf8;
  --surface-muted: #ecfbf2;
  --border-color: #ccecd8;
  --nav-bg: rgba(244, 253, 248, 0.62);
  --theme-popover-bg: rgba(244, 253, 248, 0.48);
  --nav-glass-border: rgba(255, 255, 255, 0.6);
  --nav-shadow: 0 2px 12px rgba(40, 94, 66, 0.08), 0 1px 2px rgba(40, 94, 66, 0.05);
  --nav-active-bg: rgba(255, 255, 255, 0.5);
  --nav-active-shadow: 0 2px 10px rgba(40, 94, 66, 0.095), 0 1px 6px rgba(40, 94, 66, 0.057);
  --nav-hover-bg: rgba(40, 94, 66, 0.035);
  --nav-text-active: #17442f;
  --nav-text-inactive: #67a888;
  --nav-pill-home: transparent;
  --nav-pill-about: transparent;
  --nav-pill-resume: transparent;
  --hero-glow: rgba(180, 255, 210, 0.5);
  --texture-opacity: 1;
  --switcher-bg: rgba(244, 253, 248, 0.9);
  --switcher-hover: rgba(40, 94, 66, 0.06);
  --white: #f4fdf8;
  --resume-paper: #ffffff;
  --resume-paper-border: rgba(40, 94, 66, 0.1);
  --resume-paper-shadow:
    0 1px 2px rgba(40, 94, 66, 0.05),
    0 6px 16px rgba(40, 94, 66, 0.07),
    0 24px 48px rgba(40, 94, 66, 0.1);
  --line-art-stroke: #285e42;
  --selection-bg: #17442f;
  --selection-color: #ffffff;
}

[data-theme="pastel-pink"] {
  --bg: #fce8f0;
  --text: #5e2a44;
  --text-body: #441a30;
  --text-muted: #884a6a;
  --text-subtle: #783d5a;
  --text-light: #a86a88;
  --text-nav: #783d5a;
  --text-detail: #441a30;
  --text-resume-header: #783d5a;
  --surface: #fff5f9;
  --surface-muted: #fceef4;
  --border-color: #f4cce0;
  --nav-bg: rgba(255, 245, 249, 0.62);
  --theme-popover-bg: rgba(255, 245, 249, 0.48);
  --nav-glass-border: rgba(255, 255, 255, 0.6);
  --nav-shadow: 0 2px 12px rgba(94, 42, 68, 0.08), 0 1px 2px rgba(94, 42, 68, 0.05);
  --nav-active-bg: rgba(255, 255, 255, 0.5);
  --nav-active-shadow: 0 2px 10px rgba(94, 42, 68, 0.095), 0 1px 6px rgba(94, 42, 68, 0.057);
  --nav-hover-bg: rgba(94, 42, 68, 0.035);
  --nav-text-active: #441a30;
  --nav-text-inactive: #a86a88;
  --nav-pill-home: transparent;
  --nav-pill-about: transparent;
  --nav-pill-resume: transparent;
  --hero-glow: rgba(255, 180, 210, 0.5);
  --texture-opacity: 1;
  --switcher-bg: rgba(255, 245, 249, 0.9);
  --switcher-hover: rgba(94, 42, 68, 0.06);
  --white: #fff5f9;
  --resume-paper: #ffffff;
  --resume-paper-border: rgba(94, 42, 68, 0.1);
  --resume-paper-shadow:
    0 1px 2px rgba(94, 42, 68, 0.05),
    0 6px 16px rgba(94, 42, 68, 0.07),
    0 24px 48px rgba(94, 42, 68, 0.1);
  --line-art-stroke: #5e2a44;
  --selection-bg: #441a30;
  --selection-color: #ffffff;
}

[data-theme="pastel-yellow"] {
  --bg: #fcf6e8;
  --text: #5e4a2a;
  --text-body: #44341a;
  --text-muted: #88704a;
  --text-subtle: #78603d;
  --text-light: #a8906a;
  --text-nav: #78603d;
  --text-detail: #44341a;
  --text-resume-header: #78603d;
  --surface: #fffdf5;
  --surface-muted: #fcf8ed;
  --border-color: #f4e8cc;
  --nav-bg: rgba(255, 253, 245, 0.62);
  --theme-popover-bg: rgba(255, 253, 245, 0.48);
  --nav-glass-border: rgba(255, 255, 255, 0.6);
  --nav-shadow: 0 2px 12px rgba(94, 74, 42, 0.08), 0 1px 2px rgba(94, 74, 42, 0.05);
  --nav-active-bg: rgba(255, 255, 255, 0.5);
  --nav-active-shadow: 0 2px 10px rgba(94, 74, 42, 0.095), 0 1px 6px rgba(94, 74, 42, 0.057);
  --nav-hover-bg: rgba(94, 74, 42, 0.035);
  --nav-text-active: #44341a;
  --nav-text-inactive: #a8906a;
  --nav-pill-home: transparent;
  --nav-pill-about: transparent;
  --nav-pill-resume: transparent;
  --hero-glow: rgba(255, 230, 160, 0.5);
  --texture-opacity: 1;
  --switcher-bg: rgba(255, 253, 245, 0.9);
  --switcher-hover: rgba(94, 74, 42, 0.06);
  --white: #fffdf5;
  --resume-paper: #ffffff;
  --resume-paper-border: rgba(94, 74, 42, 0.1);
  --resume-paper-shadow:
    0 1px 2px rgba(94, 74, 42, 0.05),
    0 6px 16px rgba(94, 74, 42, 0.07),
    0 24px 48px rgba(94, 74, 42, 0.1);
  --line-art-stroke: #78603d;
  --selection-bg: #5e4a2a;
  --selection-color: #ffffff;
}

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: 15px;
  scroll-behavior: auto;
  scroll-padding-top: 12px;
  scroll-padding-bottom: calc(var(--nav-offset) + var(--nav-height) + 12px);
  -webkit-font-smoothing: antialiased;
  background: var(--bg);
  overflow-x: hidden;
}

@view-transition {
  navigation: auto;
}

::view-transition-old(root),
::view-transition-new(root) {
  background-color: var(--bg);
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

body {
  font-family: var(--sans);
  font-weight: 500;
  background: var(--bg);
  color: var(--text);
  line-height: 1.3;
  min-height: 100vh;
  position: relative;
  display: flex;
  flex-direction: column;
  transition: background-color 0.3s ease, color 0.3s ease;
}

::selection {
  background-color: var(--selection-bg);
  color: var(--selection-color);
}

::-moz-selection {
  background-color: var(--selection-bg);
  color: var(--selection-color);
}

body::before {
  content: '';
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-image: url('../images/bg-texture.png');
  background-repeat: repeat;
  background-size: 128px auto;
  image-rendering: -webkit-optimize-contrast;
  image-rendering: pixelated;
  mix-blend-mode: color-dodge;
  opacity: var(--texture-opacity);
  pointer-events: none;
  /* Above .page (z-index 1) so the grain sits over the content rather than only
     the canvas — the project heroes read as being behind the texture. The fixed
     chrome is at 300 and stays clear of it. */
  z-index: 2;
  transition: opacity 0.3s ease;
}

/* Light (default) theme: color-dodge washes out on the near-white bg, so use a
   blend that keeps the grain visible — same as the pastel themes. */
html:not([data-theme]) body::before,
[data-theme="normal"] body::before {
  mix-blend-mode: multiply;
  opacity: 0.05;
}

[data-theme="pastel-blue"] body::before,
[data-theme="pastel-pink"] body::before,
[data-theme="pastel-yellow"] body::before,
[data-theme="pastel-green"] body::before {
  mix-blend-mode: soft-light;
}

/* Progressive blur along the bottom edge. Eight stacked backdrop-filter layers,
   each masked to a different band and doubling the previous blur radius, so the
   page fades gradually into the edge instead of hitting one flat blur. Theme
   neutral — the layers only sample whatever is behind them.
   z-index 100 matches the old bottom fade; the nav/toolbar sit at 300. */
.progressive-blur {
  position: fixed;
  z-index: 100;
  right: 0;
  left: 0;
  height: 200px;
  overflow: hidden;
  pointer-events: none;
}

.progressive-blur.bottom-blur {
  --blur-direction: to top;
  bottom: -32px;
}

.progressive-blur .layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.progressive-blur .blur-1 {
  z-index: 1;
  -webkit-backdrop-filter: blur(0.078125px);
  backdrop-filter: blur(0.078125px);
  -webkit-mask-image: linear-gradient(
    var(--blur-direction),
    transparent 87.5%,
    #000 100%
  );
  mask-image: linear-gradient(
    var(--blur-direction),
    transparent 87.5%,
    #000 100%
  );
}

.progressive-blur .blur-2 {
  z-index: 2;
  -webkit-backdrop-filter: blur(0.15625px);
  backdrop-filter: blur(0.15625px);
  -webkit-mask-image: linear-gradient(
    var(--blur-direction),
    transparent 75%,
    #000 87.5% 100%
  );
  mask-image: linear-gradient(
    var(--blur-direction),
    transparent 75%,
    #000 87.5% 100%
  );
}

.progressive-blur .blur-3 {
  z-index: 3;
  -webkit-backdrop-filter: blur(0.3125px);
  backdrop-filter: blur(0.3125px);
  -webkit-mask-image: linear-gradient(
    var(--blur-direction),
    transparent 62.5%,
    #000 75% 87.5%,
    transparent 100%
  );
  mask-image: linear-gradient(
    var(--blur-direction),
    transparent 62.5%,
    #000 75% 87.5%,
    transparent 100%
  );
}

.progressive-blur .blur-4 {
  z-index: 4;
  -webkit-backdrop-filter: blur(0.625px);
  backdrop-filter: blur(0.625px);
  -webkit-mask-image: linear-gradient(
    var(--blur-direction),
    transparent 50%,
    #000 62.5% 75%,
    transparent 87.5%
  );
  mask-image: linear-gradient(
    var(--blur-direction),
    transparent 50%,
    #000 62.5% 75%,
    transparent 87.5%
  );
}

.progressive-blur .blur-5 {
  z-index: 5;
  -webkit-backdrop-filter: blur(1.25px);
  backdrop-filter: blur(1.25px);
  -webkit-mask-image: linear-gradient(
    var(--blur-direction),
    transparent 37.5%,
    #000 50% 62.5%,
    transparent 75%
  );
  mask-image: linear-gradient(
    var(--blur-direction),
    transparent 37.5%,
    #000 50% 62.5%,
    transparent 75%
  );
}

.progressive-blur .blur-6 {
  z-index: 6;
  -webkit-backdrop-filter: blur(2.5px);
  backdrop-filter: blur(2.5px);
  -webkit-mask-image: linear-gradient(
    var(--blur-direction),
    transparent 25%,
    #000 37.5% 50%,
    transparent 62.5%
  );
  mask-image: linear-gradient(
    var(--blur-direction),
    transparent 25%,
    #000 37.5% 50%,
    transparent 62.5%
  );
}

.progressive-blur .blur-7 {
  z-index: 7;
  -webkit-backdrop-filter: blur(5px);
  backdrop-filter: blur(5px);
  -webkit-mask-image: linear-gradient(
    var(--blur-direction),
    transparent 12.5%,
    #000 25% 37.5%,
    transparent 50%
  );
  mask-image: linear-gradient(
    var(--blur-direction),
    transparent 12.5%,
    #000 25% 37.5%,
    transparent 50%
  );
}

.progressive-blur .blur-8 {
  z-index: 8;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  -webkit-mask-image: linear-gradient(
    var(--blur-direction),
    transparent 0%,
    #000 12.5% 25%,
    transparent 37.5%
  );
  mask-image: linear-gradient(
    var(--blur-direction),
    transparent 0%,
    #000 12.5% 25%,
    transparent 37.5%
  );
}

@media (max-width: 680px) {
  .progressive-blur {
    height: 160px;
  }
}

/* Hidden until the page scrolls. initBottomBlurVisibility() adds the flag once
   past the top and drops it again over the last 10% — defaulting to hidden
   avoids a flash before main.js runs. */
/* The fade lives on the layers, never on this container: any opacity below 1 (or
   a will-change hinting at one) turns an ancestor into a backdrop root, and the
   layers then sample an empty backdrop instead of the page — the blur vanishes.
   visibility is safe, and steps only after the fade so it can't snap mid-ramp. */
.progressive-blur.bottom-blur {
  visibility: hidden;
  transition: visibility 0s linear 0.9s;
}

body.bottom-blur-visible .progressive-blur.bottom-blur {
  visibility: visible;
  transition: visibility 0s linear 0s;
}

/* Eased in gently at both ends. The decelerating curve used elsewhere on the
   site reaches most of its opacity in the first quarter of the ramp, which on a
   stack of backdrop filters reads as a pop rather than a fade. */
.progressive-blur.bottom-blur .layer {
  opacity: 0;
  transition: opacity 0.9s cubic-bezier(0.4, 0, 0.2, 1);
}

body.bottom-blur-visible .progressive-blur.bottom-blur .layer {
  opacity: 1;
}

a {
  color: inherit;
  text-decoration: none;
}

img {
  max-width: 100%;
  display: block;
}

.container-text {
  width: 100%;
  max-width: var(--content-text);
}

.container-resume {
  width: 100%;
  max-width: var(--content-resume);
}

/* Page spacing */
.page {
  position: relative;
  z-index: 1;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  padding-top: calc(var(--nav-offset) + 12px);
  padding-bottom: calc(var(--nav-offset) + var(--nav-height) + 24px);
  padding-left: 24px;
  padding-right: 24px;
}

.container {
  width: 100%;
  padding: 0;
}

.container-narrow {
  max-width: var(--content-narrow);
}

.container-mid {
  max-width: var(--content-mid);
}

.container-wide {
  max-width: var(--content-wide);
}

/* Theme switcher */
.theme-switcher {
  position: relative;
  display: flex;
  flex-shrink: 0;
}

.theme-switcher-inner {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--nav-toolbar-item-height);
  min-width: var(--nav-toolbar-item-height);
  height: var(--nav-toolbar-item-height);
  padding: 0;
  background: transparent;
  border: none;
  border-radius: var(--nav-item-radius);
  cursor: default;
  transition: color 0.2s ease, background-color 0.2s ease;
}

.theme-switcher-label {
  display: flex;
  align-items: center;
  justify-content: center;
  color: inherit;
  pointer-events: auto;
}

/* Off-screen but still read: section headings that the design doesn't show. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.theme-switcher-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  display: block;
}

.theme-switcher-options {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 350;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  padding: 8px 8px 7px;
  background: var(--theme-popover-bg);
  backdrop-filter: blur(28px) saturate(1.45);
  -webkit-backdrop-filter: blur(28px) saturate(1.45);
  border: 1px solid var(--nav-glass-border);
  border-radius: 13px;
  box-shadow: var(--nav-shadow);
  transform: translate(-100%, 8px);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition:
    opacity 0.2s ease,
    visibility 0.2s ease,
    transform 0.2s ease,
    background-color 0.3s ease,
    border-color 0.3s ease,
    box-shadow 0.3s ease;
}

.theme-switcher-options::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: auto;
  bottom: 100%;
  height: 10px;
}

.theme-switcher-options.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: translate(-100%, 4px);
}

/* Opens upward when the toolbar sits at the bottom (project pages) */
.theme-switcher-options.is-up {
  transform: translate(-100%, calc(-100% - 8px));
}

.theme-switcher-options.is-up.is-open {
  transform: translate(-100%, calc(-100% - 4px));
}

.theme-switcher-options.is-up::after {
  top: 100%;
  bottom: auto;
}

.theme-switcher-swatches {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
}

@keyframes themeSwatchAppear {
  from {
    opacity: 0;
    transform: scale(0.72);
  }

  to {
    opacity: 1;
    transform: scale(1);
  }
}

.theme-option {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 5px 12px 5px 5px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
  cursor: pointer;
  opacity: 0;
  transform: scale(0.72);
  transform-origin: left center;
  transition: transform 0.15s ease, background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.theme-option:hover {
  background: #ffffff;
  border-color: rgba(0, 0, 0, 0.08);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.06);
}

html[data-theme="dark"] .theme-option:hover {
  background: #2c2c31;
  border-color: rgba(255, 255, 255, 0.12);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45), 0 1px 3px rgba(0, 0, 0, 0.35);
}

.theme-option-name {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1;
  color: #111111;
  white-space: nowrap;
}

html[data-theme="dark"] .theme-option-name {
  color: #ffffff;
}

.theme-option.is-active .theme-option-name {
  text-decoration: underline;
  text-decoration-style: dotted;
  text-decoration-color: currentColor;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}

.theme-switcher-options.is-open .theme-option {
  animation: themeSwatchAppear 0.24s linear forwards;
}

.theme-switcher-options.is-open .theme-option:nth-child(1) { animation-delay: 0ms; }
.theme-switcher-options.is-open .theme-option:nth-child(2) { animation-delay: 40ms; }
.theme-switcher-options.is-open .theme-option:nth-child(3) { animation-delay: 80ms; }
.theme-switcher-options.is-open .theme-option:nth-child(4) { animation-delay: 120ms; }
.theme-switcher-options.is-open .theme-option:nth-child(5) { animation-delay: 160ms; }

@media (prefers-reduced-motion: reduce) {
  .theme-option {
    opacity: 1;
    transform: none;
  }

  .theme-switcher-options.is-open .theme-option {
    animation: none;
  }
}

.theme-option:hover {
  transform: scale(1.12);
}

.theme-shortcut {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  margin-top: 4px;
  padding: 9px 5px 1px;
  border-top: 1px solid color-mix(in srgb, var(--text) 12%, transparent);
}

.theme-shortcut-text {
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--text-light);
}

.theme-shortcut-key.is-pressed {
  animation: themeKeyPress 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes themeKeyPress {
  0% { transform: scale(1); }
  40% { transform: scale(0.82); }
  100% { transform: scale(1); }
}

.theme-shortcut-key {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 20px;
  padding: 0 7px;
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--text-muted);
  background: color-mix(in srgb, var(--text) 5%, transparent);
  border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
  border-radius: 5px;
  box-shadow:
    0 1px 0 color-mix(in srgb, var(--text) 12%, transparent),
    inset 0 1px 0 color-mix(in srgb, #ffffff 40%, transparent);
}

.theme-swatch {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid rgba(0, 0, 0, 0.12);
  flex-shrink: 0;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

html[data-theme="dark"] .theme-swatch {
  border-color: rgba(255, 255, 255, 0.35);
}

.theme-option.is-active .theme-swatch {
  box-shadow: 0 0 0 2px var(--text-nav);
}

.theme-swatch[data-theme="normal"] { background: #ffffff; }
.theme-swatch[data-theme="dark"] { background: #151516; }
.theme-swatch[data-theme="pastel-blue"] { background: #e8f4fc; }
.theme-swatch[data-theme="pastel-pink"] { background: #fce8f0; }
.theme-swatch[data-theme="pastel-yellow"] { background: #fcf6e8; }
.theme-swatch[data-theme="pastel-green"] { background: #e8fbf0; }

/* Navigation */
.nav {
  position: fixed;
  top: var(--nav-offset);
  bottom: auto;
  left: 0;
  right: 0;
  z-index: 300;
  height: var(--nav-height);
  pointer-events: none;
}

.nav-primary {
  position: absolute;
  top: 0;
  bottom: auto;
  right: 24px;
  left: auto;
  transform: none;
  pointer-events: none;
  animation: navDropIn 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}

@keyframes navDropIn {
  from { opacity: 0; transform: translateY(-22px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Sound + theme sit bare in the corner — no glass pill behind them. The hover fill
   on each button stays, so they still respond to the pointer. */
.nav-primary .nav-inner {
  gap: 4px;
  background: none;
  border-color: transparent;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.pc-back,
.pc-close {
  animation: navDropIn 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}

.nav-inner {
  position: relative;
  display: flex;
  gap: 2px;
  align-items: center;
  height: var(--nav-toolbar-height);
  padding: 0 6px;
  background: var(--nav-bg);
  backdrop-filter: blur(18px) saturate(1.25);
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
  border: var(--nav-border-width) solid transparent;
  border-radius: var(--nav-radius);
  box-shadow: none;
  transition: background 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
  pointer-events: auto;
  box-sizing: border-box;
}

.nav-indicator {
  position: absolute;
  top: calc((var(--nav-toolbar-height) - (var(--nav-border-width) * 2) - var(--nav-toolbar-item-height)) / 2);
  left: 0;
  height: var(--nav-toolbar-item-height);
  width: 0;
  background: var(--nav-active-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid color-mix(in srgb, var(--nav-text-active) 10%, transparent);
  border-radius: var(--nav-item-radius);
  box-sizing: border-box;
  box-shadow: var(--nav-active-shadow);
  transform: translateX(0);
  opacity: 0;
  transition:
    transform 0.32s cubic-bezier(0.4, 0, 0.2, 1),
    width 0.32s cubic-bezier(0.4, 0, 0.2, 1),
    opacity 0.15s ease,
    border-color 0.3s ease;
  pointer-events: none;
  z-index: 0;
}

.nav-indicator.is-ready {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .nav-indicator {
    transition: none;
  }
}

.nav-divider {
  width: 1px;
  height: 18px;
  margin: 0 4px 0 2px;
  background: color-mix(in srgb, var(--text-nav) 22%, transparent);
  flex-shrink: 0;
}

.nav-primary .theme-switcher-inner {
  color: var(--nav-text-inactive);
}

.nav-primary .nav-icon-btn:hover,
.nav-primary .theme-switcher-inner:hover {
  background: var(--nav-hover-bg);
  color: var(--nav-text-active);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
}

/* Mobile: split toolbar — audio top-left, theme top-right */
@media (max-width: 640px) {
  /* Home collapses the nav buttons into the hamburger menu instead */
  body[data-page="home"] .nav-primary {
    display: none;
  }

  .nav-primary {
    left: 16px;
    right: 16px;
  }

  .nav-primary .nav-inner {
    width: 100%;
    justify-content: space-between;
    padding: 0;
    height: var(--nav-toolbar-height);
    background: none;
    border: none;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  .nav-primary .nav-inner .nav-divider {
    display: none;
  }

  .nav-primary .nav-volume-btn,
  .nav-primary .theme-switcher-inner {
    width: var(--nav-toolbar-height);
    height: var(--nav-toolbar-height);
    background: var(--nav-bg);
    border: var(--nav-border-width) solid var(--nav-glass-border);
    border-radius: var(--nav-radius);
    box-shadow: var(--nav-shadow);
    backdrop-filter: blur(18px) saturate(1.25);
    -webkit-backdrop-filter: blur(18px) saturate(1.25);
  }

  /* keep the theme popover on-screen, anchored to the right */
  .theme-switcher-options {
    left: auto !important;
    right: 16px;
    transform: translateY(8px);
  }

  .theme-switcher-options.is-open {
    transform: translateY(4px);
  }
}

.nav-icon-btn {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Square, so the hover fill sits the same distance off every edge of the icon.
     At 44 wide against a 34 height the highlight read letterboxed. */
  width: var(--nav-toolbar-item-height);
  min-width: var(--nav-toolbar-item-height);
  height: var(--nav-toolbar-item-height);
  padding: 0;
  color: var(--nav-text-inactive);
  background: transparent;
  border: none;
  border-radius: var(--nav-item-radius);
  cursor: pointer;
  transition: color 0.2s ease, background-color 0.2s ease;
  flex-shrink: 0;
}

.nav-icon-btn:hover {
  background: var(--nav-hover-bg);
  color: var(--nav-text-active);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
}

.nav-icon,
.theme-switcher-icon {
  display: block;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

@keyframes navTapPop {
  0% { transform: scale(1); }
  40% { transform: scale(1.28); }
  70% { transform: scale(0.9); }
  100% { transform: scale(1); }
}

.nav-icon-stack.is-tapped,
.theme-swatch.is-tapped {
  animation: navTapPop 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Sun/moon theme toggle */
.theme-toggle-icons {
  position: relative;
  display: block;
  width: 20px;
  height: 20px;
}

.theme-toggle-sun,
.theme-toggle-moon {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transition: opacity 0.35s ease, transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.theme-toggle-sun {
  opacity: 1;
  transform: rotate(0deg) scale(1);
}

.theme-toggle-moon {
  opacity: 0;
  transform: rotate(-90deg) scale(0.3);
}

html[data-theme="dark"] .theme-toggle-sun {
  opacity: 0;
  transform: rotate(90deg) scale(0.3);
}

html[data-theme="dark"] .theme-toggle-moon {
  opacity: 1;
  transform: rotate(0deg) scale(1);
}

.theme-toggle-icons.is-tapped {
  animation: navTapPop 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}

.pc-menu-toggle-icons {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--text-muted);
}

.pc-menu-item .theme-toggle-icons svg {
  width: 100%;
  height: 100%;
}

/* Click spark (when sound is on) */
.click-spark {
  position: fixed;
  z-index: 500;
  width: 0;
  height: 0;
  pointer-events: none;
}

.click-spark-ray {
  position: absolute;
  left: 0;
  top: 0;
  width: 3px;
  height: 11px;
  margin: -5.5px 0 0 -1.5px;
  border-radius: 3px;
  transform: rotate(var(--a)) translateY(-3px) scaleY(0.5);
  transform-origin: center;
  opacity: 0;
  animation: clickSpark 0.5s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

@keyframes clickSpark {
  0% { opacity: 0.95; transform: rotate(var(--a)) translateY(-3px) scaleY(0.5); }
  100% { opacity: 0; transform: rotate(var(--a)) translateY(-20px) scaleY(1); }
}

@media (prefers-reduced-motion: reduce) {
  .nav-icon-stack.is-tapped,
  .theme-swatch.is-tapped,
  .theme-toggle-icons.is-tapped {
    animation: none;
  }

  .theme-toggle-sun,
  .theme-toggle-moon {
    transition: opacity 0.2s ease;
  }
}

.nav-icon-stack {
  position: relative;
  display: block;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.nav-icon-stack .nav-icon {
  position: absolute;
  inset: 0;
  transition: opacity 0.15s ease;
}

.nav-volume-btn.is-muted .nav-icon--volume-on {
  opacity: 0;
  visibility: hidden;
}

.nav-volume-btn:not(.is-muted) .nav-icon--volume-off {
  opacity: 0;
  visibility: hidden;
}

.nav-link {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  height: var(--nav-toolbar-item-height);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--nav-text-inactive);
  padding: 0 14px;
  border-radius: var(--nav-item-radius);
  border: none;
  background: transparent;
  transition: color 0.2s ease, background-color 0.2s ease;
  white-space: nowrap;
  box-sizing: border-box;
}

.nav-primary .nav-link.active {
  color: var(--nav-text-active);
  font-weight: 600;
}

.nav-primary .nav-link:not(.active):hover {
  background: var(--nav-hover-bg);
  color: var(--nav-text-active);
}

.nav-link:hover {
  color: var(--nav-text-active);
}

/* Footer */
.footer-bar {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--content-wide);
  height: var(--footer-height);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  margin: 48px auto 24px;
  background: transparent;
  transition: background-color 0.3s ease;
}

.footer-name,
.footer-time {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.15px;
  line-height: 1.5;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* Site footer — details grid with dotted leaders */
.site-footer {
  position: relative;
  z-index: 1;
  width: 100vw;
  max-width: 100vw;
  margin: 96px 0;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  padding: 0 24px;
  font-family: var(--sans);
}

.site-footer-rule {
  border: 0;
  border-top: 1px solid var(--text-light);
  opacity: 0.4;
  margin: 0 0 48px;
}

.site-footer-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  column-gap: 56px;
  max-width: 760px;
  margin: 0 auto;
}

.site-footer-col {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.site-footer-row {
  display: flex;
  align-items: baseline;
  font-size: 14px;
  font-weight: 400;
  letter-spacing: -0.01em;
  line-height: 1.4;
  opacity: 0.5;
}

.site-footer-label {
  color: var(--text-light);
  white-space: nowrap;
}

.site-footer-value {
  color: var(--text-body);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.site-footer-leader {
  flex: 1 1 auto;
  min-width: 24px;
  margin: 0 12px;
  align-self: flex-end;
  transform: translateY(-4px);
  border-bottom: 1px dotted var(--text-light);
  opacity: 0.55;
}

.site-footer-copy {
  margin: 52px 0 0;
  font-size: 14px;
  letter-spacing: -0.01em;
  color: var(--text-light);
}

@media (max-width: 640px) {
  .site-footer {
    margin-top: 64px;
    margin-bottom: 64px;
  }

  .site-footer-grid {
    grid-template-columns: 1fr;
    row-gap: 16px;
  }
}

/* Home */
body[data-page="home"],
body[data-page="about"],
body[data-page="project"] {
  overflow-x: clip;
}

body[data-page="home"] {
  --ascii-bleed-top: calc(var(--nav-offset) + 12px + 58px + 8px);
  --ascii-bleed-bottom: 0;
}

body[data-page="home"] .page {
  padding-bottom: 0;
}

body[data-page="about"] {
  --ascii-bleed-top: calc(var(--nav-offset) + 12px + 8px);
}

.about-content--home {
  width: 100%;
  max-width: var(--about-content);
  margin: 0 auto;
  padding: 0 var(--home-content-padding-x) 88px;
}

.home-about-intro {
  margin-bottom: 0;
}

.home-about-intro .about-hero-title-wrap {
  width: 100%;
  max-width: var(--home-content-width);
  margin-top: 6px;
  padding: 0 var(--home-content-padding-x);
  flex-direction: column;
  align-items: center;
  gap: 0;
}

.home-about-intro .about-hero-title {
  margin: 0;
  font-size: 44px;
}

.about-interest-icons {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  width: 100%;
  margin: 28px 0 0;
  padding: 0;
  list-style: none;
}

.about-interest-icon {
  display: flex;
  width: 22px;
  height: 22px;
  flex-shrink: 0;
}

.about-interest-icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

.about-interest-icon--green,
.about-interest-icon--orange,
.about-interest-icon--yellow,
.about-interest-icon--blue,
.about-interest-icon--red {
  color: var(--text);
}

[data-theme="dark"] .about-interest-icon--green {
  color: #34d399;
}

[data-theme="dark"] .about-interest-icon--orange {
  color: #fb923c;
}

[data-theme="dark"] .about-interest-icon--yellow {
  color: #facc15;
}

[data-theme="dark"] .about-interest-icon--blue {
  color: #60a5fa;
}

[data-theme="dark"] .about-interest-icon--red {
  color: #f87171;
}

.hero-title-mark {
  text-decoration: underline;
  text-decoration-style: dashed;
  text-decoration-color: var(--text-light);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.14em;
}

.home-about-intro + .work-column--about {
  margin-top: var(--work-divider-space);
}

.home-about-intro + .work-column--about .work-column-inner {
  padding-top: 0;
}

.work-column--about .work-group {
  width: 100%;
}

.work-column--about .work-row--about {
  grid-template-columns: 108px minmax(0, 1fr);
  column-gap: 72px;
  align-items: start;
}

.work-column--about .work-row--about .work-col--company {
  align-self: start;
  line-height: 1.55;
  color: var(--text-light);
}

.work-column--about .work-col--about-copy {
  min-width: 0;
  width: 100%;
}

.work-column--about .work-col--about-copy .work-col--about-text + .work-col--about-text {
  margin-top: 1em;
}

.work-column--about .work-col--about-text {
  margin: 0;
  min-width: 0;
  width: 100%;
  max-width: none;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.55;
  color: var(--text);
  text-align: justify;
  text-justify: inter-word;
}

.work-column--about .work-col--contact {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

.about-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-style: dotted;
  text-decoration-color: var(--text-light);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}

.about-link:hover {
  color: var(--text);
  text-decoration-color: var(--text);
}

.contact-link {
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.55;
  color: var(--text-light);
  width: fit-content;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  text-align: left;
  text-decoration: underline;
  text-decoration-style: dotted;
  text-decoration-color: var(--text-light);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}

.work-column--about .contact-link {
  color: var(--text);
}

.contact-link:hover {
  color: var(--text);
  text-decoration-color: var(--text);
}

.contact-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  width: fit-content;
}

.contact-external {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  color: var(--text-light);
  opacity: 0;
  transform: translate(-3px, 3px);
  transition: opacity 0.25s ease, transform 0.25s ease;
  pointer-events: none;
}

.contact-item--link:hover .contact-external,
.contact-item--email:hover .contact-external {
  opacity: 0.55;
  transform: translate(0, 0);
}

.contact-external svg {
  width: 14px;
  height: 14px;
}

.work-column--about .work-column-inner {
  padding-bottom: 0;
}

.work-column--about + .home-bottom-ascii {
  margin-top: calc(var(--work-divider-space) + 50px);
}

.home-bottom-ascii .home-closing-inner {
  width: 100%;
  max-width: var(--home-content-width);
  margin: 0 auto;
  padding: 24px var(--home-content-padding-x)
    calc((var(--nav-offset) + var(--nav-height) + var(--home-closing-spacing-bottom)) / 2);
}

.home-closing-title-wrap {
  margin-top: 0;
}

.home-closing-title {
  margin: 0;
}

.work-column + .home-about-intro {
  margin-top: calc(var(--work-divider-space) + 28px);
}

.work-column--fun .work-column-inner {
  padding-bottom: 0;
}

body[data-page="home"] .home-main {
  padding-top: 58px;
}

.home-main {
  width: 100%;
  max-width: var(--content-mid);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
  padding-top: 8px;
  padding-bottom: 0;
}

.home-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 10px;
  position: relative;
  width: 100%;
  margin-bottom: var(--work-divider-space);
  overflow: visible;
}

body[data-page="home"] .home-hero.ascii-bg-section {
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  margin-top: calc(-1 * var(--ascii-bleed-top));
  padding-top: var(--ascii-bleed-top);
}

body[data-page="home"] .home-bottom-ascii.ascii-bg-section {
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  margin-bottom: 0;
  padding-bottom: var(--home-bottom-ascii-height);
  position: relative;
  overflow: visible;
}

/* The footer's own top/bottom margin is the gap between the ASCII pattern and the
   footer text. .page adds bottom padding to clear the fixed bottom-pinned nav of
   the project pages — nothing is pinned there on home, and it would stack under
   the footer and make the space below the text nearly double the space above. */
body[data-page="home"] .page {
  padding-bottom: 0;
}

.home-bottom-ascii-content {
  position: relative;
  z-index: 1;
  width: 100%;
  text-align: center;
}

.ascii-canvas {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(
    140% 72% at 50% 0%,
    #000 0%,
    #000 12%,
    rgba(0, 0, 0, 0.3) 36%,
    rgba(0, 0, 0, 0.07) 54%,
    transparent 70%
  );
  mask-image: radial-gradient(
    140% 72% at 50% 0%,
    #000 0%,
    #000 12%,
    rgba(0, 0, 0, 0.3) 36%,
    rgba(0, 0, 0, 0.07) 54%,
    transparent 70%
  );
}

.ascii-bg-section--flip-y .ascii-canvas {
  -webkit-mask-image: none;
  mask-image: none;
}

.hero-title-scramble,
.home-closing-reach-out,
.pc-lead-scramble {
  white-space: nowrap;
}

.hero-title-scramble .hero-scramble-char,
.pc-lead-scramble .hero-scramble-char {
  transition: color 0.16s ease;
}

.home-content-shell {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--home-content-width);
  margin: 0 auto;
  padding: 0 var(--home-content-padding-x);
}

.hero-title-wrap {
  position: relative;
  width: 100%;
  min-height: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: visible;
}

.home-hero .hero-title-wrap {
  padding-top: 50px;
}

.hero-title {
  font-family: var(--serif);
  font-size: 48px;
  font-weight: 400;
  line-height: 1.12;
  letter-spacing: -0.06em;
  color: var(--text);
  text-align: center;
  position: relative;
  z-index: 1;
  width: 100%;
  margin: 0;
  overflow: visible;
}

.hero-title-line {
  display: block;
  overflow: visible;
}

/* Homepage hero — left-aligned "digital home" layout */
.hero-title--home {
  text-align: left;
  letter-spacing: -0.03em;
}

.hero-head {
  /* The h1 — inherits the .hero-title sizing rather than the browser's. */
  margin: 0;
  font-size: inherit;
  font-weight: inherit;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}

.hero-name {
  font-family: var(--serif);
  font-size: clamp(29px, 3.6vw, 39px);
  line-height: 1.1;
  letter-spacing: -0.04em;
  color: var(--text);
}

.hero-ref {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  letter-spacing: 0;
  color: var(--text-light);
  white-space: nowrap;
}

.hero-bio {
  display: block;
  /* Fills the hero column rather than measuring itself — the shell above already
     caps the line length. */
  max-width: 100%;
  /* Paragraphs now, so the UA's bottom margin has to go. */
  margin-bottom: 0;
  font-family: var(--serif);
  font-size: clamp(14px, 1.55vw, 16px);
  line-height: 1.5;
  letter-spacing: -0.02em;
  color: var(--text-light);
  margin-top: 28px;
}

.hero-bio + .hero-bio {
  margin-top: 20px;
}

.hero-heart {
  display: inline-block;
  width: 0.82em;
  height: 0.82em;
  vertical-align: -0.06em;
  color: var(--text-light);
}

.hero-heart svg {
  width: 100%;
  height: 100%;
  display: block;
}

.hero-bio-icon {
  display: inline-block;
  width: 0.85em;
  height: 0.85em;
  vertical-align: -0.09em;
}

.hero-bio-icon svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* Miro link matches the subtext colour with a dotted underline; turns dark on hover */
.hero-bio .hero-title-link {
  color: var(--text-light);
  text-decoration: none;
  cursor: pointer;
  transition: color 0.2s ease;
}

.hero-bio .hero-title-link:hover {
  color: var(--text-body);
  opacity: 1;
}

/* Override the dark-theme custom arrow cursor for the subtext Miro link */
[data-theme="dark"] .hero-bio .hero-title-link {
  cursor: pointer;
}

.hero-second-line {
  white-space: nowrap;
}

.hero-amp {
  opacity: 0.5;
  font-weight: 300;
}

.hero-title-muted {
  opacity: 0.5;
}

/* On the first homepage view of a session the hero lands as one solid line, then
   the connecting words ("is a", "and") settle back to muted a beat later — so the
   name reads first. The .hero-intro flag is set once, in theme-init.js. */
.hero-intro .hero-title--home .hero-title-muted {
  opacity: 1;
  animation: heroMutedSettle 0.7s ease-in 1s forwards;
}

@keyframes heroMutedSettle {
  to {
    opacity: 0.5;
  }
}

/* "sunny" gets crossed out on hover with a handwritten correction */
.hero-sunny {
  position: relative;
  display: inline-block;
}

.hero-sunny::after {
  content: '';
  position: absolute;
  left: -0.04em;
  right: -0.04em;
  top: 54%;
  height: 0.055em;
  border-radius: 3px;
  background: currentColor;
  opacity: 0.55;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
}

.hero-sunny:hover::after {
  transform: scaleX(1);
}

.hero-sunny-note {
  position: absolute;
  left: 50%;
  top: calc(100% - 0.12em);
  transform: translate(-50%, 4px) rotate(-7deg);
  font-family: var(--hand);
  font-size: 0.5em;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0;
  color: var(--text);
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.25s ease, transform 0.25s ease;
  pointer-events: none;
}

.hero-sunny:hover .hero-sunny-note {
  opacity: 1;
  transform: translate(-50%, 8px) rotate(-7deg);
}

.hero-title-link {
  color: inherit;
  text-decoration: none;
  opacity: 1;
  transition: opacity 0.2s ease;
  cursor: url('../images/miro-cursor.svg?v=3') 6 6, pointer;
}

[data-theme="dark"] .hero-title-link {
  cursor: url('../images/miro-cursor-dark.svg?v=4') 6 6, pointer;
}

.hero-title-link:hover {
  opacity: 0.7;
}

.hero-icon-group {
  display: inline-flex;
  align-items: center;
  vertical-align: baseline;
  white-space: nowrap;
  gap: 0.14em;
}

.hero-icon-wrap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 0.78em;
  height: 0.78em;
  margin: 0;
  flex-shrink: 0;
  vertical-align: -0.1em;
}

.hero-icon {
  display: block;
  width: 100%;
  height: 100%;
  color: var(--text);
  pointer-events: none;
}

.hero-icon-wrap--photo {
  width: 1.15em;
  height: 1.15em;
  vertical-align: -0.28em;
}

.hero-icon-photo {
  object-fit: contain;
}


.home-closing-heart {
  cursor: pointer;
  border: none;
  background: transparent;
  padding: 0;
  font: inherit;
  line-height: inherit;
  position: relative;
}

.home-closing-heart .hero-icon {
  transition:
    color 0.25s ease,
    transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

.home-closing-heart.is-liked .hero-icon {
  color: #ef4444;
}

.home-closing-heart.is-animating .hero-icon {
  transition: color 0.25s ease;
  animation: closingHeartPop 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}

.home-closing-heart.is-animating::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1.7em;
  height: 1.7em;
  border-radius: 50%;
  border: 1.5px solid #ef4444;
  opacity: 0;
  pointer-events: none;
  animation: closingHeartRing 0.55s ease-out forwards;
}

.home-closing-heart.is-animating:not(.is-liked)::after {
  border-color: var(--text);
}

@keyframes closingHeartPop {
  0% {
    transform: scale(1);
  }

  38% {
    transform: scale(1.38);
  }

  62% {
    transform: scale(0.9);
  }

  100% {
    transform: scale(1);
  }
}

@keyframes closingHeartRing {
  0% {
    opacity: 0.55;
    transform: translate(-50%, -50%) scale(0.55);
  }

  100% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(2.4);
  }
}

@media (prefers-reduced-motion: reduce) {
  .home-closing-heart.is-animating .hero-icon,
  .home-closing-heart.is-animating::after {
    animation: none;
  }
}

.hero-glow {
  position: absolute;
  width: 100%;
  max-width: 520px;
  height: 120px;
  top: 55%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(ellipse, var(--hero-glow) 0%, transparent 70%);
  mix-blend-mode: lighten;
  opacity: 0.3;
  pointer-events: none;
  z-index: 0;
}

.hero-copy {
  width: 100%;
  max-width: 382px;
}

.hero-subtitle {
  width: 100%;
  max-width: 382px;
  margin: 0;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 1.35;
  color: var(--text-muted);
  text-align: center;
}

/* Work column */
.work-column {
  width: 100%;
  display: flex;
  justify-content: center;
}

.work-column + .work-column {
  margin-top: 96px;
}

.work-column + .work-column .work-column-inner {
  padding-top: 0;
}

.work-column:not(:last-child) .work-column-inner {
  padding-bottom: 0;
}

.work-column-inner {
  width: 100%;
  max-width: var(--home-content-width);
  margin: 0 auto;
  padding: 0 var(--home-content-padding-x) 88px;
}

.work-column-rule {
  display: block;
  width: 100%;
  margin: 0 0 var(--work-divider-space);
  padding: 0;
  border: none;
  /* Drawn as a gradient rather than `border-style: dashed`, which gives no control
     over dash length or gap. */
  height: 1px;
  background-image: repeating-linear-gradient(to right,
    var(--resume-paper-border) 0 3px,
    transparent 3px 9px);
}

.work-column-rule--trailing {
  margin: var(--work-divider-space) 0 0;
}

.work-group + .work-group {
  margin-top: 52px;
}

.work-row {
  display: grid;
  grid-template-columns: 108px minmax(0, 1fr) 48px;
  column-gap: 72px;
  align-items: center;
  min-height: 34px;
  padding: 2px 0;
}

.work-column--interactive .work-row {
  grid-template-columns: 108px 1fr;
}

.work-row-main {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 48px;
  column-gap: 72px;
  align-items: center;
  min-height: 30px;
  padding: 3px 10px;
  margin: -1px -10px;
  border-radius: 10px;
  border: 1px solid transparent;
  box-sizing: border-box;
  transition:
    border-color 0.2s ease,
    background-color 0.2s ease;
}

.work-column--interactive .work-row-main {
  cursor: pointer;
}

/* Each row hovers in its own project's colour, sampled from that project's hero
   wash — so the row and the preview that appears beside it agree. Two custom
   properties per project drive it: the wash and the ink that sits on it. */
.work-column--interactive .work-row-main[data-project] {
  --row-wash: color-mix(in srgb, var(--text) 4%, transparent);
  --row-ink: var(--text);
}

.work-column--interactive .work-row-main[data-project="custom-stickers"],
.work-column--interactive .work-row-main[data-project="navigation"] {
  --row-wash: #fef8e0;
  --row-ink: var(--ink-amber);
}

.work-column--interactive .work-row-main[data-project="automations"],
.work-column--interactive .work-row-main[data-project="visualisations"] {
  --row-wash: #effafc;
  --row-ink: var(--ink-teal);
}

.work-column--interactive .work-row-main[data-project="developer-tools"] {
  --row-wash: #f3fafd;
  --row-ink: var(--ink-blue);
}

.work-column--interactive .work-row-main[data-project="ask-ai"] {
  --row-wash: #faf6fd;
  --row-ink: var(--ink-violet);
}

.work-column--interactive .work-row-main[data-project="customer-insights"],
.work-column--interactive .work-row-main[data-project="design-systems"] {
  --row-wash: #eff7f4;
  --row-ink: var(--ink-green);
}

.work-column--interactive .work-row-main:hover {
  border-color: transparent;
  background: var(--row-wash);
}

/* A project still in flight: no page to open yet, so it takes the neutral grey wash
   rather than a project colour, drops the dashed underline that marks the others as
   links, and shakes off a click instead of going anywhere. */
.work-row-main--locked {
  cursor: default;
  /* No project colour to borrow, so it hovers in a light grey instead. Both tokens
     are set: the dark-theme hover mixes its background from the ink, not the wash,
     so leaving that one out left it with nothing to paint. */
  --row-wash: color-mix(in srgb, var(--text) 6%, transparent);
  --row-ink: var(--text);
}

/* The year sits here at rest and "In progress" arrives on hover. The cell is pinned
   to the end of the year track so its right edge lands where the other years' do,
   and the label is taken out of flow so the swap doesn't resize anything — it just
   fades in over the year's position. */
.work-row-main--locked .work-col--year {
  justify-self: end;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  min-height: 16px;
}

.wip-dots {
  /* Lining figures, same as the years below it. */
  font-variant-numeric: tabular-nums;
  transition: opacity 0.2s ease;
}

.wip-label {
  position: absolute;
  right: 0;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.2s ease;
}

/* Sized off the label rather than fixed, so it tracks the row's type. */
.wip-label svg {
  width: 0.85em;
  height: 0.85em;
  flex: 0 0 auto;
}

.work-row-main--locked:hover .wip-dots,
.work-row-main--locked:focus-visible .wip-dots {
  opacity: 0;
}

/* Once it's arrived, the label breathes gently — a live status rather than a
   fixed one. The fade-in runs on opacity, so the pulse waits for it to finish
   before taking the property over. */
.work-row-main--locked:hover .wip-label,
.work-row-main--locked:focus-visible .wip-label {
  opacity: 1;
  animation: wipPulse 2.2s ease-in-out 0.2s infinite;
}

@keyframes wipPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

@media (prefers-reduced-motion: reduce) {
  .work-row-main--locked:hover .wip-label,
  .work-row-main--locked:focus-visible .wip-label {
    animation: none;
  }
}



.work-row-main--locked .work-col--project {
  text-decoration: none;
}

.work-column--interactive .work-row-main--locked:hover .work-col--project,
.work-column--interactive .work-row-main--locked:hover .work-col--year {
  color: var(--text-light);
}

.work-row-main--locked.is-refusing {
  animation: workRowRefuse 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

/* A nudge that settles rather than a rattle: each swing smaller than the last. */
@keyframes workRowRefuse {
  25% { translate: -3px 0; }
  55% { translate: 2px 0; }
  80% { translate: -1px 0; }
  100% { translate: 0 0; }
}

@media (prefers-reduced-motion: reduce) {
  .work-row-main--locked.is-refusing {
    animation: none;
  }
}

.work-column--interactive .work-row-main:hover .work-col--project,
.work-column--interactive .work-row-main:hover .work-col--year {
  color: var(--row-ink);
}

/* On the dark canvas the pale wash would glare, so the same ink drives both: a
   low tint of it behind, a light tint of it in front. */
html[data-theme="dark"] .work-column--interactive .work-row-main:hover {
  background: color-mix(in srgb, var(--row-ink) 20%, transparent);
}

/* The locked row's ink is the near-white text colour rather than a project hue, so
   the shared 20% lands far brighter here than it does on the coloured rows. */
html[data-theme="dark"] .work-column--interactive .work-row-main--locked:hover {
  background: color-mix(in srgb, var(--row-ink) 9%, transparent);
}

html[data-theme="dark"] .work-column--interactive .work-row-main:hover .work-col--project,
html[data-theme="dark"] .work-column--interactive .work-row-main:hover .work-col--year {
  color: color-mix(in srgb, var(--row-ink) 35%, #ffffff);
}

.work-column--interactive .work-row-main:hover .work-col--project {
  text-decoration-color: transparent;
  transition: text-decoration-color 0.15s ease;
}

.work-column--interactive .work-col--project {
  transition: text-decoration-color 0.3s ease 0.2s;
}

@media (prefers-reduced-motion: reduce) {
  .work-row-main {
    transition: none;
  }

  .work-column--interactive .work-col--project {
    transition: none;
  }
}

.work-col--company {
  /* An h3 on the first row of each group — reset the UA heading styles. */
  margin: 0;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.45;
  color: var(--text);
  text-decoration: none;
}

.work-column--experience .work-col--company,
.work-column--fun .work-col--company {
  opacity: 0.5;
  transition: opacity 0.2s ease;
}

.work-column--experience .work-group:hover .work-col--company,
.work-column--fun .work-group:hover .work-col--company {
  opacity: 1;
}

.work-col--project {
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.45;
  color: var(--text);
  text-decoration: underline;
  text-decoration-style: dashed;
  text-decoration-color: var(--text-light);
  text-decoration-thickness: 1px;
  text-underline-offset: 8px;
}

.work-col--year {
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.45;
  color: var(--text-muted);
  opacity: 0.5;
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* In-progress hover status (rotating word + animated dots), sits outside the button */
.work-row-main--wip {
  position: relative;
  grid-template-columns: minmax(0, 1fr) auto;
}

.work-row-main--wip .work-col--year {
  overflow: visible;
}

.work-row-main--wip .work-col--project {
  text-decoration: none;
}

.wip-year-hover {
  display: none;
}

.work-row-main--wip:hover .wip-year-default,
.work-row-main--wip:focus-visible .wip-year-default {
  display: none;
}

.work-row-main--wip:hover .wip-year-hover,
.work-row-main--wip:focus-visible .wip-year-hover {
  display: inline;
}

.wip-status {
  position: absolute;
  left: calc(100% + 14px);
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  font-family: var(--sans);
  font-size: 14px;
  letter-spacing: -0.02em;
  color: var(--text-muted);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
}

.work-row-main--wip:hover .wip-status,
.work-row-main--wip:focus-visible .wip-status {
  opacity: 1;
}

.work-row-main--wip.is-nudging {
  animation: wipNudge 0.4s ease;
}

@keyframes wipNudge {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-4px); }
  40% { transform: translateX(4px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(2px); }
}

@media (prefers-reduced-motion: reduce) {
  .work-row-main--wip.is-nudging {
    animation: none;
  }
}

.wip-word {
  display: inline-block;
  animation: wipFlash 2.4s ease-in-out infinite;
}

.wip-word-text {
  display: inline-block;
  transition: opacity 0.26s ease, filter 0.26s ease;
}

.wip-word-text.is-fading {
  opacity: 0;
  filter: blur(4px);
}

@keyframes wipFlash {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

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

  .wip-word-text {
    transition: none;
  }
}

.work-col--icon {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  align-self: center;
  height: 22px;
  line-height: 0;
  font-size: 0;
}

.work-col--icon .work-icon {
  width: 16px;
  height: 16px;
  display: block;
  flex-shrink: 0;
  overflow: visible;
}

/* Project pages */
body[data-page="project"] .page {
  padding-bottom: calc(var(--nav-offset) + 56px);
}

/* Project pages: shift the toolbar left to make room for the home button */
body[data-page="project"] .nav-primary {
  right: 84px;
}

/* Project detail page — 4× image / divider / description */
/* Each project page carries its own ink, so page chrome can tint to the project
   the same way its row on the home page does. */
body[data-project] {
  --project-ink: var(--text);
}

body[data-project="custom-stickers"],
body[data-project="navigation"] {
  --project-ink: var(--ink-amber);
}

body[data-project="automations"],
body[data-project="visualisations"] {
  --project-ink: var(--ink-teal);
}

body[data-project="developer-tools"] {
  --project-ink: var(--ink-blue);
}

body[data-project="ask-ai"] {
  --project-ink: var(--ink-violet);
}

body[data-project="customer-insights"],
body[data-project="design-systems"] {
  --project-ink: var(--ink-green);
}

.pc-close {
  position: fixed;
  top: var(--nav-offset);
  right: 24px;
  z-index: 300;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--nav-toolbar-height);
  height: var(--nav-toolbar-height);
  /* Softer than the shared nav radius, without going fully round. */
  border-radius: 16px;
  background: var(--nav-bg);
  /* A hairline rather than the nav's shared 2px, which reads heavy on a button
     this small. Dark theme is already at 1px, so only light changes. */
  border: 1px solid var(--nav-glass-border);
  box-shadow: var(--nav-shadow);
  backdrop-filter: blur(18px) saturate(1.25);
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
  color: var(--nav-text-inactive);
  cursor: pointer;
  text-decoration: none;
  /* Scale is its own property here so the hover press composes with, rather than
     overwrites, the drop-in entrance and the leaving transition — both own transform. */
  transition: color 0.2s ease, background-color 0.2s ease, border-color 0.2s ease,
    transform 0.2s ease, scale 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

.pc-close:hover {
  /* The project's own ink mixed into the glass border, so the edge firms up on
     hover in the same colour the project's row hovers in on the home page. */
  border-color: color-mix(in srgb, var(--project-ink, #000) 45%, var(--nav-glass-border));
  color: var(--project-ink, var(--nav-text-active));
  transform: translateY(-1px);
  scale: 0.95;
}

/* On the dark canvas the ink is too deep to read against the background, so it's
   lifted toward white before it's mixed into the border and the icon. */
[data-theme="dark"] .pc-close:hover {
  --project-ink-lifted: color-mix(in srgb, var(--project-ink, #fff) 45%, #ffffff);
  border-color: color-mix(in srgb, var(--project-ink-lifted) 40%, var(--nav-glass-border));
  color: var(--project-ink-lifted);
}

.pc-close svg {
  width: 20px;
  height: 20px;
}

.pc-back-company,
.pc-back-sep {
  color: var(--text);
  opacity: 0.3;
}

.pc-back-title {
  color: var(--text);
  opacity: 0.5;
}

.pc-next {
  position: fixed;
  bottom: var(--nav-offset);
  right: 24px;
  z-index: 300;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: var(--nav-toolbar-height);
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--text-muted);
  text-decoration: none;
  opacity: 0;
  visibility: hidden;
  transform: translateY(16px);
  transition: opacity 0.4s ease, transform 0.4s ease, visibility 0.4s ease, color 0.2s ease;
  pointer-events: none;
}

.pc-next.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  pointer-events: auto;
}

.pc-next:hover {
  color: var(--text);
}

.pc-next svg {
  width: 18px;
  height: 18px;
}

.pc-next-title {
  color: var(--text);
  opacity: 0.5;
}

.pc-back svg,
.pc-next svg {
  transition: transform 0.2s ease;
}

.pc-back:hover svg {
  transform: translateX(-3px);
}

.pc-next:hover svg {
  transform: translateX(3px);
}

.pc-key-hint {
  position: fixed;
  bottom: calc(var(--nav-offset) + var(--nav-toolbar-height) + 12px);
  right: 24px;
  z-index: 300;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  font-family: var(--sans);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--text-body);
  background: var(--nav-bg);
  border: var(--nav-border-width) solid var(--nav-glass-border);
  border-radius: 10px;
  box-shadow: var(--nav-shadow);
  backdrop-filter: blur(18px) saturate(1.25);
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity 0.35s ease, transform 0.35s ease, visibility 0.35s ease;
  pointer-events: none;
}

.pc-key-hint.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.pc-key-hint kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  font-family: var(--sans);
  font-size: 11px;
  line-height: 1;
  color: var(--text-body);
  background: color-mix(in srgb, var(--text) 8%, transparent);
  border: 1px solid var(--nav-glass-border);
  border-radius: 5px;
}

/* Old on-scroll next button + hint pill are no longer used */
.pc-next,
.pc-key-hint {
  display: none;
}

/* Centered "Next project" pill at the very bottom of the page */
.pc-next-pill {
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin: 104px auto 8px;
  padding: 10px 20px;
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--nav-text-inactive);
  background: var(--nav-bg);
  border: var(--nav-border-width) solid var(--nav-glass-border);
  /* A squircle, not a capsule: well under half the pill's height so the corners
     stay square-shouldered. */
  border-radius: 14px;
  box-shadow: var(--nav-shadow);
  text-decoration: none;
  /* Slow and eased at both ends, so the pill leaves and returns as gently as it
     arrives. Every hover property runs on the same curve and duration. */
  transition:
    color 0.4s cubic-bezier(0.65, 0, 0.35, 1),
    background-color 0.4s cubic-bezier(0.65, 0, 0.35, 1),
    transform 0.4s cubic-bezier(0.65, 0, 0.35, 1),
    border-radius 0.4s cubic-bezier(0.65, 0, 0.35, 1);
}

/* One line, "Company / Project", matching the back link at the top of the page. */
.pc-next-copy {
  display: flex;
  flex-direction: row;
  align-items: baseline;
  gap: 5px;
  text-align: left;
}

.pc-next-name {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--nav-text-active);
}

/* The company and its separator sit back so the project name leads. Mixed from
   --text rather than a fixed grey, so it inverts with the theme instead of
   washing out when light content scrolls behind the pill. */
.pc-next-company,
.pc-next-sep {
  font-size: 13px;
  font-weight: 400;
  letter-spacing: -0.02em;
  color: color-mix(in srgb, var(--text) 38%, transparent);
}

.pc-next-pill > svg {
  width: 16px;
  height: 16px;
  transition: transform 0.4s cubic-bezier(0.65, 0, 0.35, 1);
}

/* Hover eases the corners open a touch, staying a squircle rather than rounding
   the pill right off. */
.pc-next-pill:hover {
  color: var(--nav-text-active);
  transform: translateY(-1px) scale(0.9);
  border-radius: 17px;
}

/* Press: a smooth squeeze on the way down, springing back on release. The
   docked pill keeps its centring translate, which the shorthand would drop. */
.pc-next-pill:active {
  transform: scale(0.95);
  transition: transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}

body[data-page="project"] .pc-next-pill.is-docked:active {
  transform: translate(-50%, 0) scale(0.95);
  transition: transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}

.pc-next-pill:hover > svg {
  transform: translateX(3px);
}

/* Dock the "Next project" pill to the bottom-centre of the screen, sliding in
   with a magnetic ease once the reader reaches the last 20% of the page. */
body[data-page="project"] .pc-next-pill {
  position: fixed;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 48px);
  margin: 0;
  transform: translate(-50%, 200%);
  opacity: 0;
  pointer-events: none;
  z-index: 320;
  animation: none;
  will-change: transform;
  background: rgba(255, 255, 255, 0.74);
  backdrop-filter: blur(18px) saturate(1.25);
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
  /* The dock's own transition replaces the base one, so the hover properties
     have to be listed again here or they snap instead of easing. */
  transition:
    transform 0.6s cubic-bezier(0.22, 1.4, 0.36, 1),
    opacity 0.4s ease,
    color 0.4s cubic-bezier(0.65, 0, 0.35, 1),
    background-color 0.4s cubic-bezier(0.65, 0, 0.35, 1),
    border-radius 0.4s cubic-bezier(0.65, 0, 0.35, 1);
}

/* Dark theme: a white 50% pill reads as an unreadable light blob against the
   dark backdrop, so use a dark translucent fill with a hairline border. */
[data-theme="dark"] body[data-page="project"] .pc-next-pill {
  background: rgba(20, 20, 22, 0.78);
  border-color: rgba(255, 255, 255, 0.12);
}

body[data-page="project"] .pc-next-pill.is-docked {
  transform: translate(-50%, 0);
  opacity: 1;
  pointer-events: auto;
}

/* Faded keyboard glyph, bottom-right of project pages. Hover or focus it to list
   the shortcuts; it sits clear of the bottom-centre "Next project" pill. */
.pc-shortcuts {
  position: fixed;
  right: 20px;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 20px);
  z-index: 320;
}

.pc-shortcuts-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text);
  opacity: 0.22;
  cursor: help;
  transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

.pc-shortcuts:hover .pc-shortcuts-btn,
.pc-shortcuts:focus-within .pc-shortcuts-btn {
  opacity: 0.65;
  transform: rotate(-15deg);
}

@media (prefers-reduced-motion: reduce) {
  .pc-shortcuts-btn {
    transition: opacity 0.25s ease;
  }

  .pc-shortcuts:hover .pc-shortcuts-btn,
  .pc-shortcuts:focus-within .pc-shortcuts-btn {
    transform: none;
  }
}

.pc-shortcuts-panel {
  position: absolute;
  right: 0;
  bottom: calc(100% + 10px);
  display: flex;
  flex-direction: column;
  gap: 7px;
  width: max-content;
  /* No panel around it — the rows read straight off the page, so the padding is
     only there to hold them clear of the button below. */
  padding: 12px 2px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(4px);
  pointer-events: none;
  transition:
    opacity 0.22s ease,
    visibility 0.22s ease,
    transform 0.22s cubic-bezier(0.22, 1, 0.36, 1);
}

.pc-shortcuts:hover .pc-shortcuts-panel,
.pc-shortcuts:focus-within .pc-shortcuts-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.pc-shortcuts-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.pc-shortcuts-key {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 20px;
  padding: 0 5px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 10px;
  line-height: 1;
  color: var(--text);
  background: color-mix(in srgb, var(--text) 7%, transparent);
  border: 1px solid var(--nav-glass-border);
  border-radius: 5px;
}

/* Keys stay in a column on the left; the label is pushed over so the wording
   finishes flush with the panel's right edge. */
.pc-shortcuts-label {
  margin-left: auto;
  font-family: var(--sans);
  text-align: right;
  font-size: 11px;
  letter-spacing: -0.01em;
  color: var(--text-subtle);
}

/* No hover to reveal it, and no hardware keyboard to use it */
@media (hover: none), (max-width: 768px) {
  .pc-shortcuts {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pc-shortcuts-btn,
  .pc-shortcuts-panel {
    transition: opacity 0.15s linear, visibility 0.15s linear;
    transform: none;
  }
}

/* The in-flow keyboard-nav hint no longer applies now the pill is docked */
.pc-next-hint {
  display: none;
}

.pc-next-hint--legacy {
  align-self: center;
  margin: 10px auto 8px;
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: -0.01em;
  color: var(--text-muted);
  opacity: 0;
  transform: translateY(-2px);
  transition: opacity 0.2s ease, transform 0.2s ease;
  pointer-events: none;
}

.pc-next-pill:hover + .pc-next-hint {
  opacity: 0.45;
  transform: translateY(0);
}

/* Project page mobile menu (hamburger) */
.pc-title-center,
.pc-menu-wrap {
  display: none;
}

.pc-menu-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--nav-toolbar-height);
  height: var(--nav-toolbar-height);
  /* Matches the close button's softer corner. */
  border-radius: 16px;
  background: var(--nav-bg);
  border: var(--nav-border-width) solid var(--nav-glass-border);
  box-shadow: var(--nav-shadow);
  backdrop-filter: blur(18px) saturate(1.25);
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
  color: var(--nav-text-inactive);
  cursor: pointer;
}

.pc-menu-btn svg {
  width: 22px;
  height: 22px;
}

.pc-menu-bars {
  position: relative;
  width: 20px;
  height: 14px;
}

.pc-menu-bar {
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: transform 0.28s ease, opacity 0.18s ease, top 0.28s ease;
}

.pc-menu-bar:nth-child(1) { top: 0; }
.pc-menu-bar:nth-child(2) { top: 6px; }
.pc-menu-bar:nth-child(3) { top: 12px; }

.pc-menu-btn[aria-expanded="true"] .pc-menu-bar:nth-child(1) {
  top: 6px;
  transform: rotate(45deg);
}

.pc-menu-btn[aria-expanded="true"] .pc-menu-bar:nth-child(2) {
  opacity: 0;
}

.pc-menu-btn[aria-expanded="true"] .pc-menu-bar:nth-child(3) {
  top: 6px;
  transform: rotate(-45deg);
}

.pc-menu {
  position: absolute;
  top: calc(var(--nav-toolbar-height) + 8px);
  right: 0;
  min-width: 210px;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--theme-popover-bg);
  backdrop-filter: blur(28px) saturate(1.45);
  -webkit-backdrop-filter: blur(28px) saturate(1.45);
  border: 1px solid var(--nav-glass-border);
  border-radius: 14px;
  box-shadow: var(--nav-shadow);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
}

.pc-menu.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.pc-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 12px;
  border: 0;
  border-radius: 8px;
  background: none;
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--text-body);
  text-decoration: none;
  text-align: left;
  cursor: pointer;
}

.pc-menu-item:hover {
  background: color-mix(in srgb, var(--text) 6%, transparent);
}

/* Menu rows lay their icons out inline, so the muted state swaps them with display
   rather than the stacked opacity fade the toolbar button uses. */
.pc-menu-item .nav-icon--volume-off,
.pc-menu-item.is-muted .nav-icon--volume-on {
  display: none;
}

.pc-menu-item.is-muted .nav-icon--volume-off {
  display: block;
}

.pc-menu-item svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--text-muted);
}

.pc-menu-divider {
  height: 1px;
  margin: 6px 4px;
  background: var(--nav-glass-border);
}

.pc-menu-chevron {
  margin-left: auto;
  transition: transform 0.2s ease;
}

#pc-menu-theme-btn[aria-expanded="true"] .pc-menu-chevron {
  transform: rotate(180deg);
}

.pc-menu-themes {
  display: none;
  grid-template-columns: repeat(3, 1fr);
  justify-items: center;
  gap: 14px;
  margin: 2px 0 0;
  padding: 8px 4px;
}

.pc-menu-themes.is-open {
  display: grid;
}

.pc-menu-swatch {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 2px solid rgba(0, 0, 0, 0.12);
  padding: 0;
  cursor: pointer;
}

.pc-menu-swatch.is-active {
  box-shadow: 0 0 0 2px var(--text-nav);
}

@media (max-width: 640px) {
  body[data-page="project"] .nav-primary {
    display: none;
  }

  .top-blur {
    display: block;
  }

  .pc-close {
    display: none;
  }

  .pc-back-company,
  .pc-back-sep,
  .pc-back-title {
    display: none;
  }

  .pc-title-center {
    display: none;
    position: fixed;
    top: 16px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 300;
    height: var(--nav-toolbar-height);
    line-height: var(--nav-toolbar-height);
    max-width: 52vw;
    font-family: var(--sans);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: -0.02em;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-align: center;
    opacity: 0;
    transition: opacity 0.3s ease;
  }

  .pc-title-center.is-visible {
    opacity: 1;
  }

  .pc-menu-wrap {
    display: block;
    position: fixed;
    top: 16px;
    right: 16px;
    z-index: 310;
  }

  /* Scoped to body[data-page] so top/left win over the later-in-source base
     .pc-back rule, which otherwise pins this back to the desktop 34px/27px and
     leaves it sitting lower and further in than the menu button opposite. */
  body[data-page="project"] .pc-back {
    left: 16px;
    /* Matches the 16px inset on the menu button opposite, top and side. */
    top: 16px;
    width: var(--nav-toolbar-height);
    justify-content: center;
    gap: 0;
    padding: 0;
    /* Matches the close button's softer corner. */
    border-radius: 16px;
    background: var(--nav-bg);
    border: var(--nav-border-width) solid var(--nav-glass-border);
    box-shadow: var(--nav-shadow);
    backdrop-filter: blur(18px) saturate(1.25);
    -webkit-backdrop-filter: blur(18px) saturate(1.25);
    color: var(--nav-text-inactive);
  }

  .pc-back .pc-back-chevron {
    display: block;
    width: 22px;
    height: 22px;
  }

  /* Keep hero/section images within the viewport on mobile — the desktop
     150%/175% widths overflow horizontally and push the fixed toolbar off-screen. */
  .pc-image,
  .pc-image--main,
  .pc-image-row {
    width: 100% !important;
  }

  /* Keep the project title within the viewport — the desktop 122% width
     overflows on narrow screens and clips the title off the edge. Let the
     words wrap/stack instead. (Scoped to body[data-page] so this wins over the
     later-in-source base .pc-lead-block { width: 122% } rule.) */
  body[data-page="project"] .pc-lead-block {
    width: 100%;
    max-width: 100%;
  }

  body[data-page="project"] .pc-lead {
    font-size: clamp(27px, 8vw, 37px);
    overflow-wrap: break-word;
    word-break: break-word;
  }

}

.top-blur {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 88px;
  z-index: 100;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.3s ease;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--bg) 70%, transparent) 0%,
    color-mix(in srgb, var(--bg) 28%, transparent) 50%,
    transparent 100%
  );
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 30%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 30%, transparent 100%);
}

.top-blur.is-visible {
  opacity: 1;
}

.pc-back {
  position: fixed;
  top: var(--nav-offset);
  left: 34px;
  z-index: 300;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: var(--nav-toolbar-height);
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--text-muted);
  text-decoration: none;
  transition: color 0.2s ease;
}

.pc-back:hover {
  color: var(--text);
}

.pc-back svg {
  width: 18px;
  height: 18px;
}

/* The company · title label carries the back affordance on its own. Mobile turns
   .pc-back into an icon-only button, so the media query below re-shows it there. */
.pc-back-chevron {
  display: none;
}

.pc-page {
  width: 100%;
  max-width: var(--home-content-width);
  display: flex;
  flex-direction: column;
  padding-top: 80px;
  padding-bottom: 82px;
}

.pc-page .animate-in {
  animation-fill-mode: both;
}

.pc-lead-block {
  width: 122%;
  max-width: 680px;
  align-self: center;
  margin: 0 0 72px;
  text-align: center;
}

.pc-lead-muted {
  opacity: 0.5;
}

/* Two-line summary under the project title — same font/size as the home hero subtext */
.pc-lead-summary {
  max-width: 24em;
  margin: 18px auto 0;
  font-family: var(--sans);
  font-size: clamp(12px, 1.55vw, 14px);
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: -0.02em;
  color: var(--text-light);
}

.pc-lead-icon {
  display: inline-flex;
  align-items: center;
  margin-left: 0.14em;
  vertical-align: -0.12em;
  color: var(--text-body);
  opacity: 0.5;
}

.pc-lead-icon--before {
  margin-left: 0;
  margin-right: 0.14em;
}

.pc-lead-icon svg {
  width: 0.72em;
  height: 0.72em;
}

.pc-lead {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(33px, 4.5vw, 45px);
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -0.055em;
  color: var(--text-body);
}

.pc-image {
  width: 115%;
  align-self: center;
  aspect-ratio: 16 / 10;
  margin: 0 0 22px;
  background: color-mix(in srgb, var(--text) 4%, var(--bg));
  border: 2px solid var(--frame-border);
  border-radius: 10px;
  box-shadow: none;
  overflow: hidden;
}

.pc-image--main {
  width: 163%;
  aspect-ratio: 3 / 2;
}

/* Two images side by side, together matching the hero width above */
.pc-image-row {
  width: 150%;
  align-self: center;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  margin: 0 0 22px;
}

.pc-image-row .pc-image {
  width: 100%;
  aspect-ratio: 1 / 1;
  margin: 0;
}

.pc-image.has-image {
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* Gif slot: crop the empty bottom by shortening the frame and anchoring to top */
.pc-image.pc-image--gif {
  aspect-ratio: 800 / 600;
  background-size: 100% auto;
  background-position: top center;
}

.pc-image--main.has-image {
  border: 2px solid var(--frame-border);
}

.pc-image--main.pc-image--fit.has-image {
  background-size: cover;
  background-position: center;
}

/* Uniform frame — every fit image crops to the same aspect ratio and fills it.
   !important overrides the per-image inline aspect-ratio set in HTML/JS. */
.pc-image--main.pc-image--fit {
  aspect-ratio: 16 / 9 !important;
}

.pc-image--video {
  position: relative;
  overflow: hidden;
}

.pc-hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Top-anchored like the still heroes — UI footage reads from the top down, so
     the crop should come off the bottom rather than off both edges. */
  object-position: top center;
  display: block;
  /* Video is composited, so it ignores the parent's rounded overflow clip —
     round the element itself so its corners match the frame. */
  border-radius: 8px;
}

/* Fades the screenshot itself out to white — it blends the UI in the image, not the
   page behind it, so it stays white on the dark canvas too. The start colour is a
   transparent *white* rather than `transparent`, which is rgba(0,0,0,0) and would
   grey the midpoint. Bottom corners match the frame's inner radius. */
.pc-image--video::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 22%;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0), #fff);
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
  pointer-events: none;
}

.pc-image.has-stickers {
  position: relative;
  overflow: hidden;
}

.pc-image--fade-bottom {
  position: relative;
}

.pc-image--fade-bottom::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 20%;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0), #fff);
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
  pointer-events: none;
}

.pc-photo {
  position: absolute;
  top: var(--y);
  left: var(--x);
  width: var(--s);
  padding: 0;
  border: 0;
  background: none;
  transform: translate(-50%, -50%) rotate(var(--r, 0deg));
  transform-origin: center;
  opacity: 0;
  cursor: zoom-in;
  animation: stickerPop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) var(--d, 0ms) forwards;
}

.pc-photo-img {
  display: block;
  width: 100%;
  height: auto;
  border: 6px solid #fff;
  border-radius: 3px;
  box-shadow: 0 12px 26px rgba(0, 0, 0, 0.22);
  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.25s ease;
}

.pc-photo--plain .pc-photo-img {
  border: 0;
  border-radius: 8px;
  box-shadow: none;
}

.pc-photo--static {
  animation: none;
  opacity: 1;
  cursor: default;
}

.pc-photo--static .pc-photo-img {
  transition: none;
}

.pc-photo.pc-photo--static:hover .pc-photo-img,
.pc-photo.pc-photo--static:focus-visible .pc-photo-img {
  transform: none;
  box-shadow: none;
}

.pc-photo:hover {
  z-index: 6;
}

.pc-photo:hover .pc-photo-img,
.pc-photo:focus-visible .pc-photo-img {
  transform: scale(1.06);
  box-shadow: 0 20px 44px rgba(0, 0, 0, 0.3);
}

/* Zoomed photo lightbox */
.pc-lightbox {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 5vh 5vw;
  background: color-mix(in srgb, rgba(0, 0, 0, 0.62), var(--bg) 12%);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  opacity: 0;
  visibility: hidden;
  cursor: zoom-out;
  transition: opacity 0.28s ease, visibility 0.28s ease;
}

.pc-lightbox.is-open {
  opacity: 1;
  visibility: visible;
}

.pc-lightbox-img {
  max-width: min(90vw, 820px);
  max-height: 90vh;
  border: 10px solid var(--frame-border);
  border-radius: 6px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.45);
  transform: scale(0.92);
  transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1);
}

.pc-lightbox.is-open .pc-lightbox-img {
  transform: scale(1);
}

@media (prefers-reduced-motion: reduce) {
  .pc-photo-img,
  .pc-lightbox,
  .pc-lightbox-img {
    transition: none;
  }

  .pc-polaroid:active img {
    transform: none;
  }
}

.pc-sticker {
  position: absolute;
  top: var(--y);
  left: var(--x);
  width: var(--s);
  height: auto;
  transform: translate(-50%, -50%) rotate(var(--r, 0deg));
  transform-origin: center;
  opacity: 0;
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-user-drag: none;
  filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.14));
  animation: stickerPop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) var(--d, 0ms) forwards;
}

.pc-sticker.is-dragging {
  cursor: grabbing;
  z-index: 10;
  filter: drop-shadow(0 16px 30px rgba(0, 0, 0, 0.28));
}

@keyframes stickerPop {
  from { opacity: 0; transform: translate(-50%, -50%) rotate(var(--r, 0deg)) scale(0.3); }
  to { opacity: 1; transform: translate(-50%, -50%) rotate(var(--r, 0deg)) scale(1); }
}

/* Standalone polaroid photos above the quote divider */
.pc-polaroids {
  align-self: center;
  display: flex;
  justify-content: center;
  margin: 20px 0 68px;
}

.pc-polaroids[hidden] {
  display: none;
}

/* Caption sits close to the photos, so the block's own bottom gap moves onto the
   caption instead of opening up between the two. */
.pc-polaroids:has(+ .pc-polaroids-caption) {
  margin-bottom: 28px;
}

/* Compound selector on purpose: .pc-subhead is defined further down the file with
   a `margin` shorthand, so a single-class rule here would lose the bottom gap. */
.pc-subhead.pc-polaroids-caption {
  margin: 16px auto 80px;
}

.pc-polaroid {
  position: relative;
  width: 250px;
  max-width: 46%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  transform: rotate(var(--r, 0deg));
  opacity: 0;
  animation: polaroidPop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) var(--d, 0ms) forwards;
}

.pc-polaroid + .pc-polaroid {
  margin-left: -34px;
}

.pc-polaroid:hover,
.pc-polaroid:focus-visible {
  z-index: 2;
}

.pc-polaroid img {
  display: block;
  width: 100%;
  height: auto;
  border: 8px solid var(--frame-border);
  border-radius: 12px;
  box-shadow: 0 14px 30px rgba(0, 0, 0, 0.18);
  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.25s ease;
}

.pc-polaroid:hover img,
.pc-polaroid:focus-visible img {
  transform: scale(1.03);
  box-shadow: 0 20px 42px rgba(0, 0, 0, 0.24);
}

/* Press feedback: dips in quickly under the finger, then eases back out on release
   via the slower transition on the image itself. */
.pc-polaroid:active img {
  transform: scale(0.95);
  transition-duration: 0.1s;
}

@keyframes polaroidPop {
  from { opacity: 0; transform: rotate(var(--r, 0deg)) scale(0.8); }
  to { opacity: 1; transform: rotate(var(--r, 0deg)) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .pc-sticker,
  .pc-photo {
    animation: none;
    opacity: 1;
  }
}

.pc-divider {
  width: 100%;
  margin: 0 0 24px;
  border: 0;
  /* Drawn as a gradient rather than `border-style: dashed`, which gives no control
     over dash length or gap. */
  height: 1px;
  background-image: repeating-linear-gradient(to right,
    var(--resume-paper-border) 0 3px,
    transparent 3px 9px);
}

.pc-desc {
  max-width: 66%;
  margin: 24px auto 72px;
  align-self: center;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.55;
  color: color-mix(in srgb, var(--text-body) 75%, transparent);
  text-align: justify;
  /* Justified text needs word-breaking or the narrow column opens rivers of
     whitespace between words. */
  hyphens: auto;
  -webkit-hyphens: auto;
}

/* Caption under an illustration — body size and italic, so it reads as a note on
   the drawing rather than a heading. line-height is set explicitly because
   .pc-diagram zeroes it to keep the images flush. */
.pc-subhead {
  width: 70%;
  margin: 16px auto 0;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  font-style: italic;
  letter-spacing: -0.02em;
  line-height: 1.5;
  color: var(--text-body);
  opacity: 0.5;
  text-align: center;
}

.pc-desc:first-of-type {
  margin-top: 32px;
  margin-bottom: 16px;
}

.pc-desc:last-child {
  margin-bottom: 0;
}

.pc-desc:last-of-type {
  margin-bottom: 80px;
}

/* Inline illustration between copy blocks — runs wider than the 70% text column
   so the drawing has room to read, but stops short of the 115% bleed the hero
   images take. */
/* Line drawing with its paper cut out to alpha, so the page shows through. The ink
   is pure black in the file, so dark mode just inverts it to white. */
.pc-sketch {
  /* Sized to the quote block, so the caption below shares that measure. */
  width: 86%;
  align-self: center;
  margin: 8px 0 16px;
  line-height: 0;
}

.pc-sketch img {
  display: block;
  /* 62% of the content column, expressed against the wider figure. */
  width: 72%;
  height: auto;
  margin: 0 auto;
}

/* Same size and face as the pull quote. line-height is explicit because .pc-sketch
   zeroes it to keep the image flush. */
/* Starts its own line with no gap of its own — the break comes from the block,
   the spacing from line-height alone. Italic here only; the same class stays
   upright in the project headlines. */
/* Small caps label above each illustration caption — Problem on the first
   figure, Solution on the second. Sans, so it reads as a marker rather than part
   of the serif sentence beneath it. */
.pc-eyebrow {
  display: block;
  margin-bottom: 14px;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-light);
}

.pc-sketch-caption .pc-lead-muted {
  display: block;
  font-style: italic;
}

.pc-sketch-caption {
  margin: 22px auto 0;
  font-family: var(--serif);
  font-size: clamp(17px, 2.3vw, 23px);
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: var(--text-body);
  text-align: center;
}

/* These figures lost their drawing but kept the caption. Both rules carry an extra
   class purely to outrank the per-project margins below, which were each written for
   a figure with art in it: the caption drops the gap that sat it clear of an image,
   and every problem statement takes the same air above it regardless of project. */
body[data-project] .pc-sketch--textonly.pc-sketch .pc-sketch-caption {
  margin-top: 0;
}

body[data-project] .pc-sketch--textonly.pc-sketch {
  margin-top: 56px;
}

/* Every caption shares one measure — a touch wider than the copy column below —
   expressed against each figure's own width so they stay identical on the page. */
.pc-sketch .pc-sketch-caption {
  width: calc(100% * 82 / 86);
  margin-inline: auto;
}

.pc-diagram .pc-sketch-caption {
  width: calc(100% * 82 / 115);
  margin-inline: auto;
}

/* Near enough to square that the shared 72% would stand it much taller than the
   other drawings on the page, so it runs narrower. Scoped to the archive drawing —
   the network one below is wide and keeps the shared width. */
body[data-project="ask-ai"] .pc-sketch:not(.pc-sketch--network) img {
  width: 54%;
}

/* Extra air between the hero and the archive drawing — the shared 8px reads as
   crowded now the drawing is narrow enough to sit clear of the hero's edges. */
body[data-project="ask-ai"] .pc-sketch:not(.pc-sketch--network) {
  margin-top: 56px;
}

/* Sits between two blocks of copy rather than under the hero image, so it takes
   more air above than the shared 8px — and more between the drawing and its own
   caption. */
body[data-project="ask-ai"] .pc-sketch--network {
  margin-top: 56px;
}

body[data-project="ask-ai"] .pc-sketch--network .pc-sketch-caption {
  margin-top: 40px;
}

/* The hero above it runs to 175%, so it needs real air to separate from it. */
body[data-project="navigation"] .pc-sketch--problem {
  margin-top: 56px;
}

body[data-project="navigation"] .pc-sketch--problem .pc-sketch-caption {
  margin-top: 40px;
}

/* Wide landscape drawing, so it runs to the full content column rather than the
   86% the square sketches use. Its caption is re-derived from that width to stay
   on the same 82% measure as the others. */
body[data-project="customer-insights"] .pc-sketch {
  width: 100%;
  /* Extra air between the hero image and the drawing below it. */
  margin-top: 48px;
}

body[data-project="customer-insights"] .pc-sketch .pc-sketch-caption {
  width: 82%;
}

/* Busier and wider than its pair below, so it runs a touch narrower to keep the
   linework at a similar weight. */
body[data-project="customer-insights"] .pc-sketch--inputs img {
  width: 56%;
}

body[data-project="customer-insights"] .pc-sketch--inputs .pc-sketch-caption {
  margin-top: 40px;
}

/* More air above the plant, and the caption pulled in closer beneath it.
   Narrower than the 86% default too: cropping the drawing's empty margins left
   the artwork filling the figure. */
body[data-project="custom-stickers"] .pc-sketch {
  width: 78%;
  margin-top: 56px;
}

/* A tall portrait subject, so it runs far narrower than the shared 72% — that
   width would make it about as tall as the content column is wide. */
body[data-project="custom-stickers"] .pc-sketch img {
  width: 40%;
}

body[data-project="custom-stickers"] .pc-sketch .pc-sketch-caption {
  width: calc(100% * 82 / 78);
  margin-inline: calc((100% - 100% * 82 / 78) / 2);
}

/* Wide landscape drawing, so it runs to the full content column like the
   Canvas Insights one rather than the 86% the square sketches use. */
body[data-project="automations"] .pc-sketch {
  width: 100%;
  margin-top: 48px;
}

/* Runs a little narrower than the shared 72% — the plug is a long, thin subject
   and fills its width more than the other drawings do. */
body[data-project="automations"] .pc-sketch img {
  width: 62%;
}

body[data-project="automations"] .pc-sketch .pc-sketch-caption {
  width: 82%;
  margin-top: 40px;
  margin-inline: auto;
}

/* Pulled in from the shared 115% bleed. The captions are re-derived from the new
   figure width so they stay on the same 82% measure as every other caption. */
body[data-project="automations"] .pc-diagram,
body[data-project="custom-stickers"] .pc-diagram {
  width: 100%;
}

body[data-project="automations"] .pc-diagram .pc-sketch-caption,
body[data-project="custom-stickers"] .pc-diagram .pc-sketch-caption {
  width: 82%;
  margin-inline: auto;
}

/* The hero above it runs to 175%, so it needs real air to separate from it. */
body[data-project="visualisations"] .pc-sketch--ledger {
  margin-top: 56px;
}

body[data-project="visualisations"] .pc-sketch--ledger .pc-sketch-caption {
  margin-top: 40px;
}

body[data-project="developer-tools"] .pc-sketch--ide {
  margin-top: 56px;
}

body[data-project="developer-tools"] .pc-sketch--ide img {
  width: 84%;
}

body[data-project="developer-tools"] .pc-sketch--ide .pc-sketch-caption {
  margin-top: 40px;
}

/* Sits between two blocks of copy, so it takes the same air as the other
   mid-page drawings. */
body[data-project="visualisations"] .pc-sketch--graph {
  margin-top: 56px;
}

body[data-project="visualisations"] .pc-sketch--graph img {
  width: 86%;
}

body[data-project="visualisations"] .pc-sketch--graph .pc-sketch-caption {
  margin-top: 40px;
}

body[data-project="custom-stickers"] .pc-sketch-caption {
  margin-top: 34px;
}

/* Coloured artwork: a straight invert would swing the yellow wash to blue, so the
   hue is rotated back afterwards — that keeps the ink readable on the dark canvas
   and the leaves roughly their own colour. */
[data-theme="dark"] .pc-sketch .pc-sketch-img--colour {
  filter: invert(1) hue-rotate(180deg);
  opacity: 0.82;
}

[data-theme="dark"] .pc-sketch img {
  /* Inverting puts the linework at full white, which shouts against the dark
     canvas — pull it back so it sits at a similar weight to the light theme. */
  filter: invert(1);
  opacity: 0.7;
}

/* Matches the hero images' bleed past the content column. No auto side margins:
   once the width exceeds the column they resolve to 0 and align-self can't
   centre, so the whole overhang lands on one side. */
.pc-diagram {
  width: 115%;
  align-self: center;
  margin: 56px 0 48px;
  line-height: 0;
}

.pc-diagram img {
  display: block;
  width: 100%;
  height: auto;
}

/* The frame diagram is a wide, sparse subject, so it reads fine well inside the
   shared 115% — the caption keeps that full measure so it still lines up with the
   captions on the other pages. */
body[data-project="navigation"] .pc-diagram img {
  width: 78%;
  margin-inline: auto;
}

/* One drawing per canvas — each file is inked for the theme it's named after.
   Scoped under .pc-diagram so these outrank the `.pc-diagram img` rule above. */
.pc-diagram .pc-diagram-img--dark {
  display: none;
}

[data-theme="dark"] .pc-diagram .pc-diagram-img--light {
  display: none;
}

[data-theme="dark"] .pc-diagram .pc-diagram-img--dark {
  display: block;
}

/* Headline stat under the quote. The value counts up when it scrolls into view. */
/* A wash of the project's own colour along the bottom edge, fading up once the
   next-project pill comes into view. Fixed, so it stays put while the last of the
   page scrolls over it. It sits above the grain (z-index 2) rather than under it —
   the texture's blend mode washed a tint this faint straight out — but below the
   fixed chrome at 300. */
.pc-next-glow {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: 300px;
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  background-image: radial-gradient(
    ellipse 70% 100% at 50% 100%,
    color-mix(in srgb, var(--project-ink, var(--text)) 34%, transparent) 0%,
    color-mix(in srgb, var(--project-ink, var(--text)) 12%, transparent) 45%,
    transparent 78%);
  transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

body.next-glow-visible .pc-next-glow {
  opacity: 1;
}

/* Hovering the pill blooms a second wash in the colour of the project it leads
   to, so the bottom of the screen previews where you're about to go. Same
   groupings as the badge and the home page's row hovers. */
body[data-next-project="custom-stickers"],
body[data-next-project="navigation"] {
  --next-ink: var(--ink-amber);
}

body[data-next-project="automations"],
body[data-next-project="visualisations"] {
  --next-ink: var(--ink-teal);
}

body[data-next-project="developer-tools"] {
  --next-ink: var(--ink-blue);
}

body[data-next-project="ask-ai"] {
  --next-ink: var(--ink-violet);
}

body[data-next-project="customer-insights"],
body[data-next-project="design-systems"] {
  --next-ink: var(--ink-green);
}

/* Its own layer rather than a child of .pc-next-glow: that element sits at
   opacity 0 until the ambient wash is called for, and a parent's opacity
   multiplies down onto anything inside it. */
.pc-next-hover-glow {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: 180px;
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  background-image: radial-gradient(
    ellipse 18% 100% at 50% 100%,
    color-mix(in srgb, var(--next-ink, var(--text)) 18%, transparent) 0%,
    color-mix(in srgb, var(--next-ink, var(--text)) 6%, transparent) 45%,
    transparent 78%);
  transition: opacity 0.4s cubic-bezier(0.65, 0, 0.35, 1);
}

body.next-pill-hover .pc-next-hover-glow {
  opacity: 1;
}

/* The matching wash in the top-right corner, tied to the close button's hover. It's
   a sibling rather than a pseudo-element because the button's backdrop-filter makes
   it a containing block — a fixed child would anchor to the button, not the viewport. */
.pc-close-glow {
  position: fixed;
  top: 0;
  right: 0;
  width: 300px;
  height: 240px;
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  background-image: radial-gradient(
    ellipse 100% 100% at 100% 0%,
    color-mix(in srgb, var(--project-ink, var(--text)) 17%, transparent) 0%,
    color-mix(in srgb, var(--project-ink, var(--text)) 6%, transparent) 45%,
    transparent 76%);
  transition: opacity 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.pc-close:hover ~ .pc-close-glow,
.pc-close:focus-visible ~ .pc-close-glow {
  opacity: 1;
}

[data-theme="dark"] .pc-close-glow {
  background-image: radial-gradient(
    ellipse 100% 100% at 100% 0%,
    color-mix(in srgb, var(--project-ink, var(--text)) 22%, transparent) 0%,
    color-mix(in srgb, var(--project-ink, var(--text)) 8%, transparent) 45%,
    transparent 76%);
}

@media (prefers-reduced-motion: reduce) {
  .pc-close-glow {
    transition: none;
  }
}

/* The close button is hidden on mobile, so the wash it drives goes with it. */
@media (max-width: 768px) {
  .pc-close-glow {
    display: none;
  }
}

/* The same wash reads weaker against the dark canvas, so it carries a little more
   of the ink to land at the same strength. */
[data-theme="dark"] .pc-next-glow {
  background-image: radial-gradient(
    ellipse 70% 100% at 50% 100%,
    color-mix(in srgb, var(--project-ink, var(--text)) 40%, transparent) 0%,
    color-mix(in srgb, var(--project-ink, var(--text)) 14%, transparent) 45%,
    transparent 78%);
}

@media (prefers-reduced-motion: reduce) {
  .pc-next-glow {
    transition: none;
  }
}

/* Full-width detail shot between the copy and the quote. Framed like the hero
   images so it reads as part of the same set. */
.pc-detail {
  width: 115.5%;
  /* Kept in case a narrow window would otherwise let it force a horizontal
     scrollbar. */
  max-width: calc(100vw - 64px);
  height: auto;
  align-self: center;
  /* Extra air below: the divider that used to separate this from the quote is
     gone, so the gap has to do that work on its own. */
  margin: 8px 0 72px;
  border: 2px solid var(--frame-border);
  border-radius: 10px;
  overflow: hidden;
}

@media (max-width: 640px) {
  .pc-detail {
    width: 100%;
  }
}

.pc-stat {
  align-self: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin: 0;
  text-align: center;
}

.pc-stat-label {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--text-light);
}

.pc-stat-value {
  font-family: var(--serif);
  font-size: clamp(42px, 6vw, 66px);
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.01em;
  color: var(--text-body);
  /* Fixed-width digits, so the number doesn't jitter as it counts. Lining too:
     the serif defaults to old-style figures, where 3 and 4 sit taller and drop
     below the baseline while 1 and 0 stay at x-height — which made "343" look
     bigger than "110". */
  font-variant-numeric: lining-nums tabular-nums;
}

.pc-rule {
  width: 100%;
  /* Same measure as .pc-desc, so the rules line up with the copy. */
  max-width: 66%;
  align-self: center;
  margin: 0 0 80px;
  border: 0;
  /* Drawn as a gradient rather than `border-style: dashed`, which gives no control
     over dash length or gap. */
  height: 1px;
  background-image: repeating-linear-gradient(to right,
    var(--resume-paper-border) 0 3px,
    transparent 3px 9px);
}

/* Stronger rules on the light canvas — the shared border tone is too faint against
   paper. Overriding the property locally keeps the resume sheet and the homepage
   rules on the original value. */
html:not([data-theme]) .pc-rule,
[data-theme="normal"] .pc-rule,
html:not([data-theme]) .pc-divider,
[data-theme="normal"] .pc-divider {
  --resume-paper-border: rgba(0, 0, 0, 0.16);
}

/* One rhythm down the closing section: 80px between the caption, each rule, the
   quote and the stat. A plain rule carries its gap below it only, so the one that
   follows the quote has to supply its own gap above. */
.pc-quote-reveal + .pc-rule {
  margin-top: 80px;
}

.pc-quote-reveal {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.pc-quote {
  max-width: 86%;
  align-self: center;
  margin: 0;
  text-align: center;
}

.pc-quote-text {
  margin: 0 0 14px;
  font-family: var(--serif);
  font-size: clamp(17px, 2.3vw, 23px);
  font-weight: 400;
  font-style: italic;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: var(--text-body);
}

.pc-quote-by {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  font-style: normal;
  letter-spacing: -0.01em;
  color: var(--text-light);
}

/* Team credit shown under the quote block at the end of a project page */
.pc-team {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  margin: 0 auto;
  max-width: 92%;
}

.pc-team-divider {
  margin: 80px 0 56px;
}

/* No quote above it — the last paragraph already supplies the top gap. */
.pc-team-divider--no-quote {
  margin-top: 0;
}

.pc-team-label {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--text-light);
}

.pc-team-pills {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  /* Roomier row gap than column gap — the rows read as separate lines of names */
  gap: 14px 12px;
}

.pc-team-break {
  flex-basis: 100%;
  height: 0;
}

/* Each member is separated from the last by a hairline. The 12px column gap plus
   12px of left padding puts the rule midway between them. */
.pc-team-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding-left: 12px;
  border-left: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--text-body);
  white-space: nowrap;
}

/* Nothing to divide from at the start of a row. The first two cases are static;
   is-row-start is set by JS for rows created by a natural flex wrap. */
.pc-team-pill:first-child,
.pc-team-break + .pc-team-pill,
.pc-team-pill.is-row-start {
  padding-left: 0;
  border-left: 0;
}

.pc-team-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  font-size: 8px;
  font-weight: 600;
  letter-spacing: 0;
  color: #fff;
  background: hsl(var(--avatar-hue, 220), 55%, 58%);
}

.pc-team-avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Project detail page — alternating image + description sections */
.project-page {
  width: 100%;
  max-width: var(--content-mid);
  display: flex;
  flex-direction: column;
}

.project-shot {
  width: 100%;
  aspect-ratio: 16 / 10;
  margin-bottom: 28px;
  background: var(--surface-muted);
  border: 1px solid var(--border-color);
  border-radius: 12px;
}

.project-shot--main {
  aspect-ratio: 16 / 9;
}

.project-about {
  width: 100%;
  margin-bottom: 64px;
}

.project-about:last-child {
  margin-bottom: 0;
}

.project-about-row {
  display: grid;
  grid-template-columns: 108px minmax(0, 1fr);
  column-gap: 72px;
  align-items: start;
}

.project-about-label {
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.55;
  color: var(--text);
}

.project-about-copy {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1em;
}

@media (max-width: 640px) {
  .project-about-row {
    grid-template-columns: 1fr;
    row-gap: 10px;
  }
}

/* Project overlay modal */
body.overlay-open {
  overflow: hidden;
}

.project-overlay {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s ease;
}

.project-overlay.is-open {
  opacity: 1;
  visibility: visible;
}

.project-overlay-backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--bg) 55%, transparent);
  backdrop-filter: blur(18px) saturate(1.2);
  -webkit-backdrop-filter: blur(18px) saturate(1.2);
}

.project-overlay-panel {
  position: relative;
  width: clamp(340px, 52vw, 760px);
  max-width: 92vw;
  height: 82vh;
  background: color-mix(in srgb, var(--surface) 68%, transparent);
  backdrop-filter: blur(30px) saturate(1.4);
  -webkit-backdrop-filter: blur(30px) saturate(1.4);
  border: 1px solid var(--nav-glass-border);
  border-radius: 20px;
  box-shadow:
    0 40px 100px rgba(0, 0, 0, 0.32),
    0 12px 30px rgba(0, 0, 0, 0.18);
  overflow: hidden;
  transform: scale(0.96) translateY(10px);
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

.project-overlay.is-open .project-overlay-panel {
  transform: scale(1) translateY(0);
}

.project-overlay-close {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 11px;
  background: var(--surface-muted);
  border: 1px solid var(--border-color);
  color: var(--text);
  cursor: pointer;
  transition: transform 0.2s ease, background-color 0.2s ease;
}

.project-overlay-close:hover {
  transform: translateY(-1px);
}

.project-overlay-close svg {
  width: 20px;
  height: 20px;
}

.project-overlay-content {
  height: 100%;
  overflow-y: auto;
  padding: 60px 40px 40px;
}

.project-ov-title {
  margin: 0 0 26px;
  text-align: center;
  font-family: var(--sans);
  font-size: 23px;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--text);
}

.project-ov-text {
  max-width: 460px;
  margin: 0 auto 44px;
  display: flex;
  flex-direction: column;
  gap: 1em;
}

.project-ov-text p {
  margin: 0;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  line-height: 1.7;
  letter-spacing: -0.01em;
  color: var(--text-light);
  text-align: justify;
  text-justify: inter-word;
}

@media (max-width: 640px) {
  .project-overlay-panel {
    width: 92vw;
    height: 88vh;
  }

  .project-overlay-content {
    padding: 56px 22px 28px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .project-overlay,
  .project-overlay-panel {
    transition: none;
  }
}

.project-top-bar {
  position: fixed;
  top: var(--nav-offset);
  left: 24px;
  z-index: 300;
  pointer-events: none;
  opacity: 0;
  transform: translateX(-24px);
  filter: blur(5px);
}

body[data-page="project"] .project-top-bar,
body.project-is-entering .project-top-bar {
  pointer-events: auto;
  animation: fadeInProjectBar 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.08s both;
}

.project-top-bar-inner {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: var(--nav-toolbar-height);
  padding: 0 14px 0 6px;
}

.project-back-btn {
  flex-shrink: 0;
}

.project-top-bar-title {
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--text-muted);
  white-space: nowrap;
}

.page--project {
  width: 100%;
  max-width: var(--content-mid);
}

body.project-is-entering .page--project {
  animation: fadeUp 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.04s both;
}

.project-detail {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 40px;
}

.project-hero-media {
  width: 100%;
  min-height: min(52vh, 420px);
  border-radius: 18px;
  border: 1px solid var(--resume-paper-border);
  background-color: color-mix(in srgb, var(--text) 4%, var(--bg));
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.project-detail-content {
  width: 100%;
  max-width: 600px;
  margin: 0 auto;
  padding: 0 var(--home-content-padding-x);
}

.project-detail-intro {
  margin: 0 0 28px;
  font-family: var(--serif);
  font-size: clamp(21px, 3vw, 27px);
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: -0.03em;
  color: var(--text-body);
}

.project-detail-body {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.project-detail-paragraph {
  margin: 0;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: -0.01em;
  color: var(--text-subtle);
}

/* Project page bottom nav pills */
.project-nav-pill {
  position: fixed;
  bottom: var(--nav-offset);
  z-index: 300;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: var(--nav-toolbar-height);
  padding: 0 16px;
  box-sizing: border-box;
  max-width: min(34vw, 240px);
  background: var(--nav-bg);
  backdrop-filter: blur(18px) saturate(1.25);
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
  border: var(--nav-border-width) solid var(--nav-glass-border);
  border-radius: var(--nav-radius);
  box-shadow: var(--nav-shadow);
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--nav-text-inactive);
  text-decoration: none;
  opacity: 0;
  transition: color 0.2s ease, background-color 0.2s ease, transform 0.2s ease;
}

body[data-page="project"] .project-nav-pill {
  animation: projPillFade 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.14s both;
}

@keyframes projPillFade {
  from { opacity: 0; }
  to { opacity: 1; }
}

.project-nav-pill:hover {
  color: var(--nav-text-active);
  background: var(--nav-active-bg);
}

.project-nav-pill .nav-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.project-nav-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.project-back {
  left: 50%;
  transform: translateX(-50%);
  max-width: none;
}

.project-back:hover {
  transform: translateX(-50%) translateY(-2px);
}

.project-prev,
.project-next {
  height: auto;
  padding: 0;
  gap: 6px;
  max-width: min(30vw, 220px);
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  color: var(--text-muted);
}

.project-prev {
  left: 24px;
}

.project-next {
  right: 24px;
}

.project-prev:hover,
.project-next:hover {
  background: none;
  color: var(--text);
}

.project-prev .nav-icon,
.project-next .nav-icon {
  opacity: 0;
  transition: opacity 0.2s ease;
}

.project-prev:hover .nav-icon,
.project-next:hover .nav-icon {
  opacity: 1;
}

body.page-is-leaving .project-nav-pill {
  opacity: 0;
  transition: opacity 0.3s ease;
}

@media (prefers-reduced-motion: reduce) {
  body[data-page="project"] .project-nav-pill {
    animation: none;
    opacity: 1;
  }
}

/* Work overlay slideshow */
.work-overlay {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition:
    opacity 0.32s cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0.32s cubic-bezier(0.22, 1, 0.36, 1);
}

.work-overlay.is-visible {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

.work-overlay-backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: blur(20px) saturate(1.1);
  -webkit-backdrop-filter: blur(20px) saturate(1.1);
}

.work-overlay-shell {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: min(1120px, calc(100% - 48px));
  height: 100%;
  padding: calc(var(--nav-offset) + 20px) 0 calc(var(--nav-offset) + 88px);
  box-sizing: border-box;
  gap: 20px;
}

.work-slideshow-stage {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 16px;
  width: 100%;
  flex: 1;
  min-height: 0;
}

.work-slideshow-side-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  color: var(--text-body);
  background: color-mix(in srgb, var(--bg) 92%, white);
  border: 1px solid color-mix(in srgb, var(--text) 8%, transparent);
  border-radius: 12px;
  box-shadow:
    0 1px 2px color-mix(in srgb, var(--text) 6%, transparent),
    0 8px 24px color-mix(in srgb, var(--text) 8%, transparent);
  cursor: pointer;
  transition:
    transform 0.2s ease,
    box-shadow 0.2s ease,
    background-color 0.2s ease;
  flex-shrink: 0;
}

.work-slideshow-side-btn:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow:
    0 2px 4px color-mix(in srgb, var(--text) 8%, transparent),
    0 12px 28px color-mix(in srgb, var(--text) 10%, transparent);
}

.work-slideshow-side-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.work-slideshow-chevron {
  display: block;
  width: 20px;
  height: 20px;
}

.work-slideshow-viewport {
  width: 100%;
  height: 100%;
  min-height: min(58vh, 520px);
  overflow: hidden;
  border-radius: 24px;
}

.work-slideshow-track {
  display: flex;
  height: 100%;
  will-change: transform;
}

.work-slide {
  flex: 0 0 100%;
  min-width: 0;
  height: 100%;
  padding: 0;
  box-sizing: border-box;
}

.work-slide-media {
  width: 100%;
  height: 100%;
  min-height: min(58vh, 520px);
  border-radius: 24px;
  border: 1px solid color-mix(in srgb, var(--text) 8%, transparent);
  background: color-mix(in srgb, var(--bg) 96%, white);
  box-shadow:
    0 1px 2px color-mix(in srgb, var(--text) 4%, transparent),
    0 24px 64px color-mix(in srgb, var(--text) 10%, transparent);
}

.work-slideshow-thumbs {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  max-width: 720px;
  overflow-x: auto;
  padding: 4px 8px;
  scrollbar-width: none;
}

.work-slideshow-thumbs::-webkit-scrollbar {
  display: none;
}

.work-slideshow-thumb {
  position: relative;
  flex: 0 0 auto;
  width: 72px;
  height: 48px;
  padding: 0;
  border: none;
  border-radius: 10px;
  background: transparent;
  cursor: pointer;
  opacity: 0.42;
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.work-slideshow-thumb:hover {
  opacity: 0.72;
}

.work-slideshow-thumb.is-active {
  opacity: 1;
  transform: translateY(-2px);
}

.work-slideshow-thumb-media {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 10px;
  border: 1px solid color-mix(in srgb, var(--text) 10%, transparent);
  background: color-mix(in srgb, var(--bg) 90%, white);
  box-shadow: 0 6px 18px color-mix(in srgb, var(--text) 8%, transparent);
}

.work-slideshow-thumb-badge {
  position: absolute;
  right: 4px;
  bottom: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  font-family: var(--sans);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: white;
  background: var(--text-body);
  border-radius: 999px;
  opacity: 0;
  transform: scale(0.85);
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.work-slideshow-thumb.is-active .work-slideshow-thumb-badge {
  opacity: 1;
  transform: scale(1);
}

.work-slideshow-pagination {
  margin: 0;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  text-align: center;
}

.work-overlay-nav {
  position: fixed;
  bottom: var(--nav-offset);
  left: 50%;
  transform: translateX(-50%);
  z-index: 401;
  pointer-events: none;
}

.work-overlay-nav-inner {
  pointer-events: auto;
}

.work-overlay-nav .nav-link,
.work-overlay-nav .nav-icon-btn {
  cursor: pointer;
}

.work-overlay-nav .nav-link:hover,
.work-overlay-nav .nav-icon-btn:hover:not(:disabled) {
  background: var(--nav-hover-bg);
  color: var(--nav-text-active);
}

.work-overlay-nav .nav-icon-btn:disabled,
.work-slideshow-side-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

body.work-overlay-open {
  overflow: hidden;
}

body.work-overlay-open .nav-primary {
  opacity: 0;
  pointer-events: none;
  transform: translateY(28px);
  filter: blur(4px);
  transition:
    opacity 0.28s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.28s cubic-bezier(0.22, 1, 0.36, 1),
    filter 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}

body.work-overlay-open .page {
  filter: blur(3px);
  transform: scale(0.995);
  transition:
    filter 0.32s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.32s cubic-bezier(0.22, 1, 0.36, 1);
}

@media (prefers-reduced-motion: reduce) {
  .work-overlay,
  .work-slideshow-track,
  .work-slideshow-thumb,
  body.work-overlay-open .nav-primary,
  body.work-overlay-open .page {
    transition: none;
  }
}

body.page-is-leaving .page {
  opacity: 0;
  transform: translateY(-10px);
  filter: blur(4px);
  transition:
    opacity 0.32s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.32s cubic-bezier(0.22, 1, 0.36, 1),
    filter 0.32s cubic-bezier(0.22, 1, 0.36, 1);
}

body.page-is-leaving .nav-primary,
body.page-is-leaving .pc-back,
body.page-is-leaving .pc-close {
  opacity: 0;
  transform: translateY(-22px);
  transition:
    opacity 0.3s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

body.page-is-leaving .pc-next {
  opacity: 0;
  transform: translateY(22px);
  transition:
    opacity 0.3s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

body.page-is-leaving .top-blur {
  opacity: 0;
  transition: opacity 0.3s ease;
}

/* Keyed on [data-project] rather than the old role="button" — the rows are
   real links now, and the in-progress ones carry no slug. */
.work-column--experience .work-row-main[data-project] {
  cursor: pointer;
}

.work-column--experience .work-row-main[data-project]:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--text) 30%, transparent);
  outline-offset: 2px;
}

@keyframes fadeInProjectBar {
  from {
    opacity: 0;
    transform: translateX(-24px);
    filter: blur(5px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
    filter: blur(0);
  }
}

/* Projects */
.projects {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.projects-list {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 100px;
  width: 100%;
  max-width: var(--content-narrow);
}

.project-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
  width: 100%;
  max-width: 433px;
  cursor: pointer;
  transition: transform 0.3s ease;
  padding: 8px 0;
}

.project-item:hover {
  transform: scale(0.98);
}

.project-image-wrap {
  position: relative;
  width: 100%;
  border: var(--border-white);
  border-radius: 16px;
  overflow: hidden;
  background: var(--surface);
  transition: background 0.3s ease, border-color 0.3s ease;
}

.project-image-wrap img {
  width: 100%;
  height: auto;
  display: block;
  vertical-align: middle;
}

.project-image-wrap.contain {
  padding: 16px;
}

.project-image-wrap.contain img {
  object-fit: contain;
  max-height: 280px;
  margin: 0 auto;
}

.project-scallop {
  position: absolute;
  top: -7px;
  left: -27px;
  right: -35px;
  height: 19px;
  overflow: hidden;
  pointer-events: none;
  z-index: 2;
}

.project-scallop svg {
  width: 100%;
  height: 19px;
  display: block;
}

.project-item h3 {
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 1.3;
  color: var(--text-muted);
  text-align: center;
  width: 100%;
}

/* About */
.about-main {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 8px;
}

.about-content {
  width: 100%;
  max-width: var(--about-content);
}

.about-intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  margin-bottom: 48px;
  text-align: center;
  position: relative;
  overflow: visible;
}

.about-intro-content {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  width: 100%;
}

.about-line-art {
  display: flex;
  justify-content: center;
  width: 100%;
  padding: 4px 0 12px;
}

.about-line-art-group {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 2px;
}

.about-line-art-image {
  display: block;
  width: min(180px, 42vw);
  /* Matches the padded artwork. Both drawings carry a 12px transparent margin so
     the ink never sits on the box edge — with mask-size: contain, the fractional
     height that min(180px, 42vw) produces used to shave the last row off. */
  aspect-ratio: 541 / 682;
  flex-shrink: 0;
  background-color: var(--line-art-stroke);
  -webkit-mask-image: url('../images/richard-line-art.png?v=2');
  mask-image: url('../images/richard-line-art.png?v=2');
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  transition: background-color 0.3s ease;
}

.about-line-art-dog {
  width: calc(min(180px, 42vw) * 0.5);
  flex-shrink: 0;
  background-color: var(--line-art-stroke);
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center bottom;
  mask-position: center bottom;
  transform-origin: center bottom;
  scale: 1;
  transition:
    background-color 0.3s ease,
    opacity 0.3s ease,
    scale 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}

.about-line-art-dog:hover {
  scale: 0.78;
}

.about-line-art-dog--berner {
  aspect-ratio: 338 / 386;
  cursor: none;
  animation: fadeInDogFromLeft 2s cubic-bezier(0.22, 1, 0.36, 1) 0.55s both;
  -webkit-mask-image: url('../images/dog-line-art.png');
  mask-image: url('../images/dog-line-art.png');
}

.about-line-art-dog--setter {
  aspect-ratio: 289 / 324;
  margin-right: -24px;
  cursor: none;
  translate: 0 4px;
  animation: fadeInDogFromRight 2s cubic-bezier(0.22, 1, 0.36, 1) 0.55s both;
  -webkit-mask-image: url('../images/setter-line-art.png');
  mask-image: url('../images/setter-line-art.png');
}

/* Project hero preview — floats directly above the hovered project title. JS sets
   left/bottom (or top, when it has to flip below) from the title's own rect, and
   --px/--py drift the frame a little with the cursor without unparking it. */
/* The wrapper only carries the cursor drift, on a short transition so it keeps up
   with the pointer. The reveal (scale/slide/rotate) lives on the frame inside, so
   the two can be timed independently. */
.project-preview {
  position: fixed;
  left: 0;
  bottom: 0;
  width: min(340px, 42vw);
  z-index: 300;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  /* Blurs out as it goes, so it dissolves rather than just dimming */
  filter: blur(9px);
  transform: translate(var(--px, 0px), var(--py, 0px));
  transition:
    opacity 0.24s cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0.24s cubic-bezier(0.22, 1, 0.36, 1),
    filter 0.3s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.08s linear;
}

.project-preview.is-visible {
  opacity: 1;
  visibility: visible;
  filter: blur(0);
  transition:
    opacity 0.2s cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0.2s cubic-bezier(0.22, 1, 0.36, 1),
    filter 0.16s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.08s linear;
}

/* Matches the framing of .pc-image--main on the project pages */
.project-preview-frame {
  width: 100%;
  aspect-ratio: 16 / 9;
  transform: translateY(6px) scale(0.9) rotate(3deg);
  transform-origin: bottom left;
  transition: transform 0.24s cubic-bezier(0.22, 1, 0.36, 1);
  background-color: color-mix(in srgb, var(--text) 4%, var(--bg));
  border: 2px solid var(--preview-frame-border, #fff);
  border-radius: 14px;
  box-shadow: var(--preview-frame-shadow, 0 6px 18px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.06));
  overflow: hidden;
}

/* An img rather than a background so gif previews can be restarted on hover */
.project-preview-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Top-anchored: taller previews are UI screenshots that read from the top down */
  object-position: top center;
}

.project-preview.is-below .project-preview-frame {
  transform-origin: top left;
  transform: translateY(-6px) scale(0.9) rotate(3deg);
}

.project-preview.is-visible .project-preview-frame,
.project-preview.is-below.is-visible .project-preview-frame {
  transform: translateY(0) scale(1) rotate(3deg);
}

/* No real hover, or too little room to float a preview — drop it entirely */
@media (max-width: 700px), (hover: none) {
  .project-preview {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .project-preview,
  .project-preview.is-visible {
    transition: opacity 0.2s linear, visibility 0.2s linear, filter 0.2s linear;
    transform: none;
  }

  .project-preview-frame,
  .project-preview.is-below .project-preview-frame,
  .project-preview.is-visible .project-preview-frame {
    transition: none;
    transform: rotate(3deg);
  }
}

.dog-photo-popover {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 400;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, -50%) scale(0.78);
  transform-origin: center center;
  /* Defocused on the way in, resolving as it settles — the photo reads as coming
     into focus rather than simply appearing. */
  filter: blur(8px);
  transition:
    opacity 0.34s cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0.34s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.34s cubic-bezier(0.22, 1, 0.36, 1),
    filter 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}

.dog-photo-popover.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, -50%) scale(1);
  filter: blur(0);
}

#eddie-photo-popover {
  transform: translate(-50%, -50%) scale(0.78) rotate(-15deg);
}

#eddie-photo-popover.is-visible {
  transform: translate(-50%, -50%) scale(1) rotate(-15deg);
}

#berner-photo-popover {
  transform: translate(-50%, -50%) scale(0.78) rotate(15deg);
}

#berner-photo-popover.is-visible {
  transform: translate(-50%, -50%) scale(1) rotate(15deg);
}

.dog-photo-polaroid {
  width: min(126px, 30vw);
  margin: 0;
  padding: 8px 8px 12px;
  background: var(--dog-polaroid-bg, #ffffff);
  border-radius: 2px;
  box-shadow: var(--dog-polaroid-shadow, 0 10px 28px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.06));
}

.dog-photo-polaroid-photo {
  overflow: hidden;
  background: var(--dog-polaroid-photo-bg, #eceae6);
}

.dog-photo-polaroid-photo img,
.dog-photo-polaroid-photo video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 3.4;
  object-fit: cover;
  object-position: top center;
}

.dog-photo-polaroid-caption {
  margin-top: 6px;
  font-family: 'Caveat', cursive;
  font-size: 13px;
  line-height: 1;
  text-align: center;
  color: var(--dog-polaroid-caption, #3b3b3b);
}

@media (prefers-reduced-motion: reduce) {
  .dog-photo-popover {
    transition: none;
    filter: none;
  }

  .dog-photo-popover.is-visible {
    transform: translate(-50%, -50%);
  }

  #eddie-photo-popover.is-visible {
    transform: translate(-50%, -50%) rotate(-15deg);
  }

  #berner-photo-popover.is-visible {
    transform: translate(-50%, -50%) rotate(15deg);
  }
}

[data-theme="dark"] .about-line-art-image {
  -webkit-mask-image: url('../images/richard-line-art-dark.png?v=3');
  mask-image: url('../images/richard-line-art-dark.png?v=3');
  /* The two drawings are the same height to the pixel; the dark one is just inked
     ~3% narrower, which is what makes it read smaller. So the correction is
     horizontal only — scaling both axes would make him taller than his light
     counterpart and look like he'd risen. Scale rather than width keeps the box's
     layout size, so the dogs either side stay put, and `scale` is its own property
     so the fade-up animation (`forwards`, owns `transform`) can't clobber it. */
  scale: 1.03 1;
}

[data-theme="dark"] .about-line-art-dog--berner {
  -webkit-mask-image: url('../images/dog-line-art-dark.png?v=3');
  mask-image: url('../images/dog-line-art-dark.png?v=3');
}

[data-theme="dark"] .about-line-art-dog--setter {
  -webkit-mask-image: url('../images/setter-line-art-dark.png?v=3');
  mask-image: url('../images/setter-line-art-dark.png?v=3');
}

.about-greeting {
  width: 100%;
  text-align: center;
}

.about-greeting h1,
.about-greeting-title {
  margin: 0 0 16px;
  font-family: var(--serif);
  font-size: clamp(33px, calc(7vw - 6px), 51px);
  font-weight: 400;
  line-height: 0.96;
  letter-spacing: -0.06em;
  color: var(--text);
}

.pronunciation-group {
  display: flex;
  justify-content: center;
  width: 100%;
}

.pronunciation-line {
  font-family: var(--adamina);
  font-size: 13px;
  letter-spacing: -0.04em;
  line-height: 1.3;
  color: var(--text-light);
  text-align: center;
}

.pronunciation {
  display: inline-block;
  transform: rotate(-2deg);
}

.about-section {
  margin-bottom: 0;
}

.about-section + .about-section {
  margin-top: 44px;
}

.about-section-rule {
  margin: 0 0 20px;
  border-top-style: dashed;
}

.about-section h2 {
  font-family: var(--serif);
  font-size: 17px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.3;
  color: var(--text-muted);
  margin: 0 0 0;
}

.about-section h2 + p,
.about-section h2 + .passion-block,
.about-section h2 + .albums-grid,
.about-section h2 + .books-grid {
  margin-top: 20px;
}

.about-section p,
.passion-block,
.location-line {
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.5;
  color: var(--text-body);
  text-align: left;
}

.about-section p + p,
.passion-block + .location-line,
.location-line + .location-line {
  margin-top: 12px;
}

.about-section .albums-grid {
  margin-top: 20px;
}

.location-polaroids {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: center;
  width: 100%;
  margin-top: 24px;
  padding: 4px 0 2px;
}

.location-polaroid {
  width: 100%;
  margin: 0;
  padding: 12px 12px 34px;
  background: var(--location-polaroid-bg);
  border: 1px solid var(--location-polaroid-border);
  border-radius: 2px;
  box-shadow: var(--location-polaroid-shadow);
}

.location-polaroid--amsterdam {
  position: relative;
  z-index: 1;
  transform: rotate(-5deg);
  margin-right: -18px;
}

.location-polaroid--limerick {
  position: relative;
  z-index: 2;
  transform: rotate(5deg);
  margin-left: -18px;
  margin-top: -12px;
}

.location-polaroid-photo {
  overflow: hidden;
  background: var(--location-polaroid-photo-bg);
}

.location-polaroid-photo img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 128 / 118;
  object-fit: cover;
}

.location-polaroid-caption {
  margin-top: 10px;
  font-family: 'Caveat', cursive;
  font-size: 15px;
  line-height: 1.1;
  text-align: center;
}

.location-polaroid--amsterdam .location-polaroid-caption {
  color: var(--location-polaroid-caption-amsterdam);
}

.location-polaroid--limerick .location-polaroid-caption {
  color: var(--location-polaroid-caption-limerick);
}

.media-block {
  margin-top: 16px;
}

.location-image {
  width: 100%;
  max-width: var(--content-text);
  height: auto;
  display: block;
}

.books-grid {
  display: flex;
  gap: 28px;
  align-items: flex-end;
  flex-wrap: wrap;
}

.book-item {
  flex: 0 0 auto;
  margin: 0;
}

.book-cover {
  position: relative;
  width: 108px;
  padding-left: 10px;
  filter: drop-shadow(6px 8px 14px rgba(0, 0, 0, 0.16));
}

.book-cover::before {
  content: '';
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 0;
  width: 10px;
  border-radius: 2px 0 0 2px;
  background: linear-gradient(90deg, #d8d8d8 0%, #f4f4f4 55%, #ffffff 100%);
  box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.08);
}

.book-cover img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 148px;
  object-fit: contain;
  border-radius: 0 3px 3px 0;
  background: #ffffff;
}

.albums-grid {
  display: flex;
  gap: 36px;
  align-items: flex-start;
  flex-wrap: wrap;
  overflow: visible;
}

.album-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  margin: 0;
  flex: 0 0 auto;
}

.album-artwork {
  position: relative;
  width: 172px;
  height: 172px;
  overflow: visible;
}

.album-vinyl {
  position: absolute;
  top: 50%;
  left: 30%;
  z-index: 0;
  width: 92%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  transition: left 0.5s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
}

.album-vinyl-disc {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background:
    repeating-radial-gradient(
      circle at center,
      rgba(255, 255, 255, 0.05) 0 1px,
      transparent 1px 3px
    ),
    radial-gradient(circle at center, #242424 0%, #101010 58%, #050505 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.08),
    0 6px 16px rgba(0, 0, 0, 0.18);
}

.album-vinyl-label {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 1;
  width: 36%;
  aspect-ratio: 1;
  overflow: hidden;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  border: 2px solid rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25);
}

.album-vinyl-label img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.album-cover {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border: 2px solid #ffffff;
  border-radius: 8px;
  background: #ffffff;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.14);
  transform-origin: left center;
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

.album-cover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.album-item:hover .album-vinyl,
.album-item:focus-within .album-vinyl {
  left: 62%;
}

.album-item:hover .album-cover,
.album-item:focus-within .album-cover {
  transform: rotate(-5deg);
}

.album-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
}

.album-artist {
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.3;
  color: var(--text-body);
}

.album-title {
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: -0.03em;
  line-height: 1.3;
  color: var(--text-muted);
}

@media (prefers-reduced-motion: reduce) {
  .album-vinyl,
  .album-cover {
    transition: none;
  }
}

/* Resume */
.resume-main {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 24px 0 80px;
}

.resume-sheet {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: calc(var(--content-resume) + 72px);
  background: var(--resume-paper);
  border: 1px solid var(--resume-paper-border);
  border-radius: 6px;
  box-shadow: var(--resume-paper-shadow);
  padding: 52px 56px 60px;
  transform: translateY(-2px);
}

.resume-sheet::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  border-radius: 6px 6px 0 0;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.65) 50%,
    transparent
  );
  pointer-events: none;
}

[data-theme="dark"] .resume-sheet::before {
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.1) 50%,
    transparent
  );
}

.resume-content {
  width: 100%;
  max-width: var(--content-resume);
  margin: 0 auto;
}

.resume-header {
  margin-bottom: 40px;
}

.resume-header h1 {
  font-family: var(--serif);
  font-size: 19px;
  font-weight: 400;
  letter-spacing: -0.15px;
  line-height: 1.4;
  color: var(--text-resume-header);
  margin-bottom: 4px;
}

.resume-header p {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.04em;
  color: var(--text-subtle);
}

.resume-section {
  margin-bottom: 48px;
}

.resume-section > h2 {
  font-size: 19px;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.3;
  color: var(--text);
  margin-bottom: 28px;
}

.experience-item {
  margin-bottom: 40px;
}

.experience-item:last-child {
  margin-bottom: 0;
}

.experience-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 4px;
}

.experience-meta h3 {
  font-size: 19px;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.3;
  color: var(--text);
  flex: 1 1 auto;
  min-width: 0;
}

.experience-date {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.04em;
  color: var(--text-subtle);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.experience-role {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.04em;
  color: var(--text-subtle);
  margin-bottom: 12px;
}

.experience-desc {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.5;
  color: var(--text-detail);
}

.experience-desc + .experience-desc {
  margin-top: 10px;
}

.education-item .experience-meta h3 {
  font-size: 19px;
}

.education-school {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.04em;
  color: var(--text-subtle);
}

.skills-grid {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.skill-group h3 {
  font-size: 19px;
  font-weight: 500;
  letter-spacing: -0.03em;
  color: var(--text);
  margin-bottom: 12px;
}

.skill-group p {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.5;
  color: var(--text-detail);
}

.languages-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.language-item {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-detail);
  display: flex;
  justify-content: space-between;
  max-width: 240px;
}

.language-level {
  color: var(--text-subtle);
}

/* Animations */
@keyframes fadeUpNavPrimaryRight {
  from {
    opacity: 0;
    transform: translateY(20px);
    filter: blur(5px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
    filter: blur(0);
  }
}

@keyframes fadeInNavUtils {
  from {
    opacity: 0;
    transform: translateY(-16px);
    filter: blur(5px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
    filter: blur(0);
  }
}

@keyframes fadeUp {
  from {
    opacity: 0;
    transform: translateY(24px);
    filter: blur(var(--fade-blur, 6px));
  }
  to {
    opacity: 1;
    transform: none;
    filter: none;
  }
}

/* Filter-free fade-up: used by the about title lines so they don't become a
   backdrop root (an animated `filter` would stop the nested Ireland/Dutch
   tooltips' backdrop-filter from blurring the line-art behind them). */
@keyframes fadeUpNoBlur {
  from {
    opacity: 0;
    transform: translateY(24px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes fadeInDogFromRight {
  from {
    opacity: 0;
    filter: blur(5px);
    translate: 20px 4px;
  }
  to {
    opacity: 0.5;
    filter: blur(0);
    translate: 0 4px;
  }
}

@keyframes fadeInDogFromLeft {
  from {
    opacity: 0;
    filter: blur(5px);
    translate: -20px 0;
  }
  to {
    opacity: 0.5;
    filter: blur(0);
    translate: 0 0;
  }
}

.animate-in {
  animation: fadeUp var(--fade-dur, 1.25s) cubic-bezier(0.22, 1, 0.36, 1) forwards;
  overflow: visible;
}

/* First homepage view of the session — the flag theme-init.js sets in the head.
   Slower, and out of a deeper blur. */
.hero-intro {
  --fade-dur: 1.6s;
  --fade-blur: 9px;
  --fade-step: 0.145s;
}

/* Only what is on screen at load gets the slow treatment. The flag above sits on
   <html>, so without this every section revealed further down the same first visit
   would inherit it too — and a reveal you scroll to should feel as brisk as it does
   on any later load. */
.animate-on-scroll-root {
  --fade-dur: 1.25s;
  --fade-blur: 6px;
  --fade-step: 0.115s;
}

.animate-in-delay-1 { animation-delay: calc(var(--fade-step, 0.115s) * 1); opacity: 0; }
.animate-in-delay-2 { animation-delay: calc(var(--fade-step, 0.115s) * 2); opacity: 0; }
.animate-in-delay-3 { animation-delay: calc(var(--fade-step, 0.115s) * 3); opacity: 0; }
.animate-in-delay-4 { animation-delay: calc(var(--fade-step, 0.115s) * 4); opacity: 0; }
.animate-in-delay-5 { animation-delay: calc(var(--fade-step, 0.115s) * 5); opacity: 0; }

/* Matches the keyframe's start exactly, or the element jumps depth the instant
   it begins. */
.animate-on-scroll-root:not(.is-in-view) .animate-in {
  animation: none;
  opacity: 0;
  transform: translateY(24px);
  filter: blur(var(--fade-blur, 6px));
}

.home-about-intro.animate-on-scroll-root:not(.is-in-view) .about-line-art-dog {
  animation: none;
  opacity: 0;
}

.home-about-intro.animate-on-scroll-root:not(.is-in-view) .about-line-art-dog--setter {
  translate: 20px 4px;
}

.home-about-intro.animate-on-scroll-root:not(.is-in-view) .about-line-art-dog--berner {
  translate: -20px 0;
}

@media (prefers-reduced-motion: reduce) {
  .nav-primary,
  .pc-back,
  .pc-close {
    animation: none;
    opacity: 1;
    transform: none;
  }

  .pc-close:hover {
    scale: 1;
  }

  body.project-is-entering .page--project {
    animation: none;
    opacity: 1;
    transform: none;
    filter: none;
  }

  body.page-is-leaving .page,
  body.page-is-leaving .nav-primary,
  body.page-is-leaving .pc-back,
  body.page-is-leaving .pc-close {
    transition: none;
  }

  .nav-primary {
    right: 16px;
    transform: none;
  }

  .about-line-art-dog--setter {
    animation: none;
    opacity: 0.5;
    filter: none;
    translate: 0 4px;
    scale: 1;
    transition: background-color 0.3s ease, opacity 0.3s ease;
  }

  .about-line-art-dog--berner {
    animation: none;
    opacity: 0.5;
    filter: none;
    translate: 0 0;
    scale: 1;
    transition: background-color 0.3s ease, opacity 0.3s ease;
  }

  .about-line-art-dog:hover {
    scale: 1;
  }
}

/* Responsive */
@media (max-width: 768px) {
  :root,
  [data-theme="normal"],
  [data-theme="dark"],
  [data-theme="pastel-blue"],
  [data-theme="pastel-pink"],
  [data-theme="pastel-yellow"],
  [data-theme="pastel-green"] {
    --nav-offset: 27px;
  }

  .page {
    padding-top: calc(var(--nav-offset) + 8px);
    padding-bottom: calc(var(--nav-offset) + var(--nav-height) + 20px);
    padding-left: 16px;
    padding-right: 16px;
  }

  /* Narrow screens have little room for the 78% column, so the copy, rules and
     quote open up — just shy of the full width inside the page's 16px gutters. */
  .pc-desc,
  .pc-rule,
  .pc-quote {
    max-width: 90%;
  }

  body[data-page="home"] .page {
    padding-bottom: 0;
  }

  .project-top-bar {
    left: 16px;
  }

  .project-hero-media {
    min-height: min(40vh, 300px);
    border-radius: 14px;
  }

  .project-detail-content {
    padding: 0 20px;
  }

  .work-overlay-shell {
    width: calc(100% - 24px);
    padding: calc(var(--nav-offset) + 12px) 0 calc(var(--nav-offset) + 80px);
    gap: 14px;
  }

  .work-slideshow-stage {
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
  }

  .work-slideshow-side-btn {
    display: none;
  }

  .work-slideshow-viewport,
  .work-slide-media {
    min-height: min(44vh, 320px);
    border-radius: 18px;
  }

  .work-slideshow-thumbs {
    max-width: 100%;
    justify-content: flex-start;
    padding-inline: 4px;
  }

  .work-slideshow-thumb {
    width: 60px;
    height: 40px;
  }

  .work-overlay-close {
    min-width: 60px;
  }

  .nav-inner {
    height: var(--nav-toolbar-height);
    padding: 0 5px;
    border-radius: var(--nav-radius);
  }

  .nav-primary {
    right: 16px;
  }

  .home-main {
    padding-top: 8px;
  }

  /* nav-offset + 8 + 8 is exactly the space above the hero, which lands the canvas
     edge on the viewport edge. Glyphs are drawn at cell centres, though, so a row
     centre sitting exactly on the edge clips the small characters in half and they
     vanish — reading as a whole empty cell. Bleeding most of a half-cell keeps the
     top row whole and just below the edge. */
  body[data-page="home"] {
    --ascii-bleed-top: calc(var(--nav-offset) + 8px + 8px + 7px);
  }

  body[data-page="about"] {
    --ascii-bleed-top: calc(var(--nav-offset) + 8px + 8px + 7px);
  }

  .home-hero {
    margin-bottom: var(--work-divider-space);
  }

  .hero-title-wrap {
    min-height: auto;
  }

  .resume-sheet {
    padding: 36px 28px 44px;
    border-radius: 4px;
  }

  .work-column-inner {
    max-width: 100%;
    padding: 0 20px 64px;
  }

  .home-content-shell {
    max-width: 100%;
    /* The hero section is full-bleed (100vw), so it escapes .page's 16px gutter
       while the work column below sits inside it. Adding the gutter here lines
       the title and bio up with the project rows. */
    padding: 0 calc(16px + 20px);
  }

  .work-row {
    grid-template-columns: 88px minmax(0, 1fr) 44px;
    column-gap: 28px;
    min-height: 32px;
  }

  .work-column--interactive .work-row {
    grid-template-columns: 88px 1fr;
  }

  /* Stack the label over its copy — an 88px gutter leaves too little room for
     the paragraphs at this width. */
  .work-column--about .work-row--about {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 10px;
  }

  .work-row-main {
    grid-template-columns: minmax(0, 1fr) 44px;
    column-gap: 28px;
    padding: 3px 8px;
    margin: -1px -8px;
  }

  .about-section h2 {
    font-size: 15px;
  }

  .about-section p,
  .passion-block,
  .location-line {
    font-size: 13px;
  }

  .location-polaroid {
    padding: 10px 10px 28px;
  }

  .location-polaroid--amsterdam {
    margin-right: -14px;
  }

  .location-polaroid--limerick {
    margin-left: -14px;
    margin-top: -10px;
  }

  .location-polaroid-caption {
    font-size: 13px;
  }

  .work-group + .work-group {
    margin-top: 40px;
  }

  .work-col--company,
  .work-col--project,
  .work-col--year {
    font-size: 13px;
  }

  .hero-title {
    font-size: 41px;
  }

  /* Keep the homepage hero title on two lines at mobile widths */
  .hero-name {
    font-size: 30px;
  }

  /* Shrink the about ("Sustained by my love for…") title so it fits on mobile */
  .home-about-intro .about-hero-title {
    font-size: 32px;
  }

  /* The three lines are hard-broken for desktop; at mobile widths each one is
     wider than the screen and wraps again, which leaves a ragged five-line
     stack. Let them run as one sentence instead and balance the wrap so the
     lines come out even. */
  .home-about-intro .about-hero-title .hero-title-line {
    display: inline;
  }

  .home-about-intro .about-hero-title {
    text-wrap: balance;
  }

  .hero-subtitle {
    font-size: 13px;
  }

  .projects-list {
    gap: 64px;
  }

  .albums-grid {
    flex-wrap: wrap;
  }

  .books-grid {
    flex-wrap: wrap;
  }

  .footer-bar {
    padding: 0;
    margin-top: 32px;
  }

  .nav-link {
    font-size: 11px;
    height: var(--nav-toolbar-item-height);
    padding: 0 12px;
  }

  .home-main {
    flex-direction: column;
    align-items: center;
  }

  :root,
  [data-theme="normal"],
  [data-theme="dark"],
  [data-theme="pastel-blue"],
  [data-theme="pastel-pink"],
  [data-theme="pastel-yellow"],
  [data-theme="pastel-green"] {
    --work-divider-space: 36px;
  }

  .work-column + .work-column {
    margin-top: 48px;
  }
}

@media (max-width: 520px) {
  .hero-title {
    font-size: 33px;
  }

  .about-line-art-image {
    width: min(140px, 38vw);
  }

  .about-line-art-dog {
    width: calc(min(140px, 38vw) * 0.5);
  }

  .album-artwork {
    width: 148px;
    height: 148px;
  }

  .album-item {
    flex-basis: 148px;
  }
}

/* "in sunny Amsterdam" — the word reflects the real weather there, with the
   reading behind a hover. The dotted rule is the only hint that it's live. */
.hero-weather {
  position: relative;
  border-bottom: 1px dotted color-mix(in srgb, var(--text-light) 55%, transparent);
  cursor: help;
}

.hero-weather-tip {
  position: absolute;
  top: calc(100% + 10px);
  left: 50%;
  translate: -50% 4px;
  z-index: 20;
  padding: 6px 10px;
  border-radius: 8px;
  background: var(--nav-bg);
  border: var(--nav-border-width) solid var(--nav-glass-border);
  box-shadow: var(--nav-shadow);
  backdrop-filter: blur(18px) saturate(1.25);
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
  font-family: var(--sans);
  font-size: 12px;
  font-style: normal;
  letter-spacing: -0.01em;
  line-height: 1;
  color: var(--text-nav);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s ease, translate 0.22s cubic-bezier(0.22, 1, 0.36, 1);
}

.hero-weather:hover .hero-weather-tip,
.hero-weather:focus-visible .hero-weather-tip {
  opacity: 1;
  translate: -50% 0;
}


/* Keyboard escape hatch past the fixed toolbar — off-screen until focused. */
.skip-link {
  position: fixed;
  top: 8px;
  left: 8px;
  z-index: 400;
  padding: 10px 14px;
  border-radius: 10px;
  background: var(--nav-bg);
  border: var(--nav-border-width) solid var(--nav-glass-border);
  box-shadow: var(--nav-shadow);
  backdrop-filter: blur(18px) saturate(1.25);
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  transform: translateY(-150%);
  transition: transform 0.2s ease;
}

.skip-link:focus-visible {
  transform: translateY(0);
  outline: 2px solid color-mix(in srgb, var(--text) 30%, transparent);
  outline-offset: 2px;
}
