/* ═══════════════════════════════════════════════════════════════════════
   Loc Phan — portfolio
   1. Tokens        4. Layout        7. Work        10. Contact
   2. Reset         5. Chrome        8. Stack       11. Footer
   3. Type          6. Hero          9. About       12. Motion & media
   ═══════════════════════════════════════════════════════════════════ */

/* ── 0. Fonts (self-hosted, latin subset) ───────────────────────────── */

@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces-latin.woff2") format("woff2-variations");
  font-weight: 300 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces-italic-latin.woff2") format("woff2-variations");
  font-weight: 300 800;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Instrument Sans";
  src: url("../fonts/instrument-sans-latin.woff2") format("woff2-variations");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

/* ── 1. Tokens ──────────────────────────────────────────────────────── */

:root {
  /* Brand — identical in both themes so the accent never drifts */
  --ember: #ff6a3d;
  --amber: #ffb454;
  --iris:  #7c6bff;
  --mint:  #37e0b0;

  --sweep: linear-gradient(100deg, var(--ember), var(--amber) 55%, var(--iris));

  /* Type */
  --sans: "Instrument Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --serif: "Fraunces", ui-serif, Georgia, "Times New Roman", serif;

  /* Roles, not families. Components ask for a role and never name a face, so
     the whole page re-points from this block alone. */
  --display: var(--serif);
  --body: var(--sans);
  --label: var(--sans);
  --accentface: var(--serif);
  --display-weight: 400;
  --display-track: -0.028em;
  --head-weight: 400;
  --head-track: -0.02em;
  --label-track: .15em;
  --accent-size: 1em;
  --accent-style: italic;
  --accent-weight: 400;

  /* Fluid scale — 360px → 1600px */
  --t-xs:   0.75rem;
  --t-sm:   0.8125rem;
  --t-base: clamp(0.98rem, 0.93rem + 0.22vw, 1.09rem);
  --t-lg:   clamp(1.12rem, 1.02rem + 0.5vw, 1.45rem);
  --t-xl:   clamp(1.5rem, 1.2rem + 1.5vw, 2.4rem);
  --t-2xl:  clamp(2.1rem, 1.4rem + 3.4vw, 4.6rem);
  --t-3xl:  clamp(2.9rem, 24vw, 19rem);

  /* Rhythm */
  --shell: 1240px;
  --gut: clamp(1.25rem, 4vw, 3.5rem);
  --sec: clamp(5.5rem, 11vw, 10rem);
  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 26px;

  /* Easing */
  --ease: cubic-bezier(.22, .61, .36, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --ease-io: cubic-bezier(.65, .05, .36, 1);
  --spring: cubic-bezier(.34, 1.56, .64, 1);

  --nav-h: 74px;
  color-scheme: dark;
}

/* Dark — the default */
/* Dark — warm ink, the accent lifted so it glows rather than bleeds. */
[data-theme="dark"] {
  --ink:    #16130f;
  --ink-2:  #1d1915;
  --ink-3:  #26211b;
  --text:   #f3ede2;
  --text-2: #b3a795;
  --text-3: #a2957f;
  --line:   rgb(255 240 214 / .12);
  --line-2: rgb(255 240 214 / .22);
  --glass:  rgb(22 19 15 / .7);
  --card:   rgb(255 240 214 / .03);
  --card-2: rgb(255 240 214 / .06);
  --shadow: 0 30px 70px -30px rgb(0 0 0 / .85);
  --ember: #52c6d8;
  --amber: #6fa0e0;
  --iris:  #4fcfa6;
  --mint:  #c9c066;
  --ink-rgb: 82 198 216;
  --grain: .05;
  --aurora: .5;
  --grid: .05;
  --vignette: .86;
  color-scheme: dark;
}

/* Light — warm bone paper. The home theme: cool teal on warm stock is what
   makes the accent read as ink rather than as UI color. */
[data-theme="light"] {
  --ink:    #fbf8f1;
  --ink-2:  #ffffff;
  --ink-3:  #f1eade;
  --text:   #1b1813;
  --text-2: #544d42;
  --text-3: #6d6458;
  --line:   rgb(40 30 16 / .16);
  --line-2: rgb(40 30 16 / .3);
  --glass:  rgb(251 248 241 / .82);
  --card:   rgb(255 255 255 / .6);
  --card-2: rgb(255 255 255 / .95);
  --shadow: 0 26px 60px -30px rgb(60 42 20 / .34);
  --ember: #0e5560;
  --amber: #1e4c7a;
  --iris:  #16624a;
  --mint:  #6a6317;
  --ink-rgb: 14 85 96;
  --grain: .05;
  --aurora: .42;
  --grid: .03;
  --vignette: .24;
  color-scheme: light;
}

/* Fraunces carries the display face; SOFT and WONK are what give the wordmark
   its character. It also gets proportionally wider as it gets smaller, so the
   one vw term that fills a desktop measure overflows a phone — ease it off
   below 640px. */
.hero__title,
.secHead__title,
.cta,
.loader__name { font-variation-settings: "SOFT" 0, "WONK" 1; }

@media (max-width: 640px) {
  :root { --t-3xl: clamp(2.9rem, 20.4vw, 19rem); }
}

/* ── 2. Reset ───────────────────────────────────────────────────────── */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 24px);
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--text);
  font: 400 var(--t-base)/1.65 var(--body);
  font-synthesis-weight: none;
  letter-spacing: -0.006em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
  transition: background-color .5s var(--ease), color .5s var(--ease);
}

body.is-locked { overflow: hidden; }

h1, h2, h3, h4, p, figure, dl, dd, ul, ol { margin: 0; padding: 0; }
ul, ol { list-style: none; }
[hidden] { display: none !important; }
img, svg, picture { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
::selection { background: var(--ember); color: #0b0b0e; }

:focus-visible {
  outline: 2px solid var(--ember);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip-link {
  position: fixed;
  top: 12px; left: 12px;
  z-index: 999;
  padding: .7rem 1.1rem;
  background: var(--text);
  color: var(--ink);
  border-radius: 999px;
  font: 500 var(--t-sm)/1 var(--label);
  transform: translateY(-160%);
  transition: transform .3s var(--ease-out);
}
.skip-link:focus-visible { transform: none; }

/* ── 3. Type ────────────────────────────────────────────────────────── */

.mono, .secHead__idx, .nav__idx, .tags li, .status,
.loader__count, .scrollcue__text, .contact__k, .stack__label, .foot__note,
.rail i, .portrait figcaption, .menu__links i, .work__eyebrow,
.workGroup__meta, .workGroup__co {
  font-family: var(--label);
  font-weight: 500;
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  font-size: var(--t-xs);
}

em { font-family: var(--accentface); font-style: var(--accent-style); font-weight: var(--accent-weight); }

/* Serif italics sit optically small next to Inter — nudge them up. */
h1 em, h2 em, h3 em { font-size: var(--accent-size); letter-spacing: 0; }
.hero__lead em { font-size: var(--accent-size); letter-spacing: 0; }

.ulink {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: .3em;
  color: var(--text);
}
.ulink::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .45s var(--ease-out);
}
.ulink:hover::after { transform: scaleX(1); transform-origin: left; }
.ulink svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }

.status {
  display: inline-flex;
  align-items: center;
  gap: .6em;
  padding: .5em 1em .5em .85em;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  color: var(--text-2);
  backdrop-filter: blur(10px);
}
.status i {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--mint);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--mint) 70%, transparent);
  animation: pulse 2.6s var(--ease-out) infinite;
}
.status--inline { padding: .35em .8em .35em .65em; font-size: 11px; }

@keyframes pulse {
  0%        { box-shadow: 0 0 0 0 color-mix(in srgb, var(--mint) 60%, transparent); }
  60%, 100% { box-shadow: 0 0 0 9px color-mix(in srgb, var(--mint) 0%, transparent); }
}

/* ── 4. Layout ──────────────────────────────────────────────────────── */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gut);
}

.section { position: relative; padding-block: var(--sec); }
/* A pinned section is already a screen with its own padding. Section padding
   on top of that only pushes the composed view off the bottom of the viewport,
   and the negative scroll margin cancels the page's nav offset so a jump to
   the section lands on the whole of it rather than a screen's worth above. */
.section--rail { padding-block: 0; scroll-margin-top: calc(-1 * (var(--nav-h) + 24px)); }

.secHead { max-width: 46ch; margin-bottom: clamp(2.75rem, 5vw, 4.5rem); }
.secHead__idx {
  display: flex;
  align-items: center;
  gap: 1rem;
  color: var(--text-3);
  margin-bottom: 1.6rem;
}
.secHead__idx::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--line-2), transparent);
  transform: scaleX(var(--rule, 0));
  transform-origin: left;
  transition: transform 1.1s var(--ease-out) .2s;
}
.reveal.is-in .secHead__idx { --rule: 1; }

.secHead__title {
  text-wrap: balance;
  font-family: var(--display);
  font-size: var(--t-2xl);
  font-weight: var(--head-weight);
  line-height: 1.02;
  letter-spacing: var(--head-track);
}
.secHead__title em { color: var(--ember); }
.secHead__note {
  margin-top: 1.4rem;
  max-width: 42ch;
  color: var(--text-2);
  font-size: var(--t-lg);
  line-height: 1.5;
  letter-spacing: -0.014em;
}

/* Buttons */
.btn {
  --btn-fg: var(--text);
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: .7em;
  padding: 1.02em 1.7em;
  border-radius: 999px;
  font-size: var(--t-sm);
  font-weight: 500;
  letter-spacing: .01em;
  color: var(--btn-fg);
  isolation: isolate;
  overflow: hidden;
  white-space: nowrap;
  transition: color .4s var(--ease), transform .5s var(--spring), border-color .4s var(--ease);
}
.btn > span { position: relative; z-index: 2; }
.btn svg {
  position: relative; z-index: 2;
  width: 16px; height: 16px;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .45s var(--ease-out);
}
.btn:hover svg { transform: translateX(4px); }
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--sweep);
  transform: translateY(101%);
  transition: transform .55s var(--ease-out);
}
.btn:hover::before { transform: none; }

.btn--solid { background: var(--text); color: var(--ink); }
.btn--solid:hover { color: #0b0b0e; }

.btn--ghost {
  border: 1px solid var(--line-2);
  background: color-mix(in srgb, var(--ink) 74%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.btn--ghost:hover { color: #0b0b0e; border-color: transparent; }

/* Tag chips */
.tags { display: flex; flex-wrap: wrap; gap: .45rem; }
.tags li {
  padding: .42em .78em;
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--text-3);
  font-size: 10.5px;
  letter-spacing: .09em;
  background: var(--card);
  transition: color .4s var(--ease), border-color .4s var(--ease);
}
.card__link:hover .tags li { color: var(--text-2); border-color: var(--line-2); }

/* ── 5. Chrome: ambient, cursor, nav, loader ────────────────────────── */

.ambient {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}

.ink {
  position: absolute;
  inset: 0;
  z-index: 1;
  /* Multiply is ink into paper; on a dark ground the same pigment glows. */
  mix-blend-mode: multiply;
}
[data-theme="dark"] .ink { mix-blend-mode: screen; }

.ambient__aurora { position: absolute; inset: -25%; opacity: var(--aurora); }
.blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  will-change: transform;
}
.blob--1 {
  width: 48vw; height: 48vw; top: -6%; left: -8%;
  background: radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--ember) 62%, transparent), transparent 68%);
  animation: drift1 24s var(--ease-io) infinite alternate;
}
.blob--2 {
  width: 42vw; height: 42vw; top: 12%; right: -6%;
  background: radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--iris) 60%, transparent), transparent 68%);
  animation: drift2 31s var(--ease-io) infinite alternate;
}
.blob--3 {
  width: 38vw; height: 38vw; bottom: -12%; left: 32%;
  background: radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--amber) 44%, transparent), transparent 70%);
  animation: drift3 27s var(--ease-io) infinite alternate;
}
@keyframes drift1 { to { transform: translate3d(14vw, 10vh, 0) scale(1.18); } }
@keyframes drift2 { to { transform: translate3d(-12vw, 16vh, 0) scale(.85); } }
@keyframes drift3 { to { transform: translate3d(9vw, -14vh, 0) scale(1.12); } }

/* Static dot lattice + a brighter one revealed under the cursor */
.ambient__grid,
.ambient__spot {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle at center, currentColor .9px, transparent 1.3px);
  background-size: 34px 34px;
  /* Fade the lattice at the edges so it reads as texture, not graph paper. */
  -webkit-mask-image: radial-gradient(130% 100% at 50% 0%, #000 12%, transparent 78%);
  mask-image: radial-gradient(130% 100% at 50% 0%, #000 12%, transparent 78%);
}
.ambient__grid { color: var(--text); opacity: var(--grid); z-index: 2; }
.ambient__spot { z-index: 2; }
.ambient__grain { z-index: 3; }
.ambient__spot {
  color: var(--ember);
  opacity: .6;
  -webkit-mask-image: radial-gradient(210px circle at var(--mx, -300px) var(--my, -300px), #000 0%, transparent 70%);
  mask-image: radial-gradient(210px circle at var(--mx, -300px) var(--my, -300px), #000 0%, transparent 70%);
}

.ambient__grain {
  position: absolute;
  inset: -200%;
  opacity: var(--grain);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: grain 6s steps(6) infinite;
}
@keyframes grain {
  0%   { transform: translate(0, 0); }
  20%  { transform: translate(-4%, 3%); }
  40%  { transform: translate(3%, -5%); }
  60%  { transform: translate(-2%, -3%); }
  80%  { transform: translate(5%, 2%); }
  100% { transform: translate(0, 0); }
}

/* A soft vignette pins the content to the center of the frame */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(122% 80% at 50% 40%, transparent 45%,
              color-mix(in srgb, var(--ink) calc(var(--vignette) * 100%), transparent) 100%);
}

main, .nav, .foot, .menu { position: relative; z-index: 2; }

.notice {
  position: fixed;
  left: 50%;
  bottom: 20px;
  transform: translateX(-50%);
  z-index: 55;
  display: flex;
  align-items: center;
  gap: .35rem;
  max-width: calc(100vw - 2 * var(--gut));
  padding: .55rem .55rem .55rem 1.05rem;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 92%, transparent);
  backdrop-filter: blur(16px) saturate(1.3);
  -webkit-backdrop-filter: blur(16px) saturate(1.3);
  box-shadow: 0 14px 40px -16px rgb(0 0 0 / .4);
  font-size: var(--t-sm);
  color: var(--text-2);
}
.notice p { margin: 0; }
.notice button {
  flex: none;
  padding: .5em .9em;
  border-radius: 999px;
  font: 500 var(--t-sm)/1 var(--body);
  color: var(--ink);
  background: var(--text);
}
.notice__x {
  display: grid;
  place-items: center;
  width: 30px; height: 30px;
  padding: 0;
  background: none;
  color: var(--text-3);
}
.notice__x svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.notice__x:hover { color: var(--text); }
@media (max-width: 620px) {
  .notice { flex-wrap: wrap; justify-content: center; border-radius: var(--r-md); padding-left: 1rem; text-align: center; }
}

/* Scroll progress */
.progress {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 2px;
  z-index: 60;
  pointer-events: none;
}
.progress i {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--sweep);
  transform: scaleX(var(--p, 0));
  transform-origin: left;
}

/* Custom cursor — pointer devices only, wired up in JS */
.cursor { display: none; }
@media (hover: hover) and (pointer: fine) {
  html.js.has-cursor, html.js.has-cursor * { cursor: none !important; }

  .cursor {
    display: block;
    opacity: 0;
    transition: opacity .3s var(--ease);
    position: fixed;
    top: 0; left: 0;
    z-index: 200;
    pointer-events: none;
  }
  .cursor__dot,
  .cursor__ring {
    position: absolute;
    top: 0; left: 0;
    border-radius: 50%;
    transform: translate(-50%, -50%);
  }
  .cursor__dot {
    width: 7px; height: 7px;
    background: var(--text);
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--ink) 45%, transparent);
    transition: opacity .3s var(--ease), width .35s var(--spring), height .35s var(--spring);
  }
  .cursor__ring {
    width: 38px; height: 38px;
    border: 1px solid color-mix(in srgb, var(--text) 48%, transparent);
    display: grid;
    place-items: center;
    transition: width .45s var(--spring), height .45s var(--spring),
                background-color .35s var(--ease), border-color .35s var(--ease);
  }
  .cursor__label {
    font: 500 9.5px/1 var(--label);
    letter-spacing: .12em;
    text-transform: uppercase;
    color: #14100c;
    opacity: 0;
    transform: scale(.6);
    transition: opacity .3s var(--ease), transform .4s var(--spring);
  }

  .cursor.is-link .cursor__ring {
    width: 56px; height: 56px;
    border-color: color-mix(in srgb, var(--text) 80%, transparent);
    background: color-mix(in srgb, var(--text) 7%, transparent);
    backdrop-filter: blur(2px);
  }
  .cursor.is-link .cursor__dot  { width: 0; height: 0; }

  .cursor.is-view .cursor__ring {
    width: 78px; height: 78px;
    background: var(--ember);
    border-color: var(--ember);
    backdrop-filter: none;
    box-shadow: 0 10px 30px -8px color-mix(in srgb, var(--ember) 60%, transparent);
  }
  .cursor.is-view .cursor__dot  { width: 0; height: 0; }
  .cursor.is-view .cursor__label { opacity: 1; transform: none; }

  .cursor.is-live { opacity: 1; }
  .cursor.is-live.is-hidden { opacity: 0; }
  .cursor.is-down .cursor__ring { width: 26px; height: 26px; }
}

/* Loader */
.loader {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  align-content: end;
  gap: 1.6rem;
  padding-bottom: clamp(2.4rem, 6vw, 4rem);
  background: var(--ink);
  transition: transform 1s var(--ease-io), visibility 1s;
}
.loader.is-done { transform: translateY(-101%); visibility: hidden; }
html:not(.js) .loader, .loader[data-off] { display: none; }

.loader__inner,
.loader__bar {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gut);
}
.loader__inner {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 2rem;
}
.loader__name {
  font-family: var(--display);
  font-size: clamp(1.6rem, 7vw, 4.6rem);
  font-weight: var(--head-weight);
  letter-spacing: -0.05em;
  line-height: 1;
  background: var(--sweep);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.loader__count { color: var(--text-3); font-style: normal; }
.loader__count i { font-style: normal; color: var(--text); }
.loader__bar {
  height: 1px;
  padding-inline: 0;
  max-width: calc(var(--shell) - var(--gut) * 2);
  background: var(--line);
  overflow: hidden;
}
.loader__bar i {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--sweep);
  transform: scaleX(0);
  transform-origin: left;
}

/* Header */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 50;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  transition: transform .55s var(--ease-out), background-color .4s var(--ease),
              border-color .4s var(--ease), backdrop-filter .4s var(--ease);
  border-bottom: 1px solid transparent;
}
.nav.is-stuck {
  background: var(--glass);
  backdrop-filter: blur(20px) saturate(1.5);
  -webkit-backdrop-filter: blur(20px) saturate(1.5);
  border-bottom-color: var(--line);
}
.nav.is-up { transform: translateY(-100%); }

.nav__inner {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gut);
  display: flex;
  align-items: center;
  gap: 1.5rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  font-weight: 600;
  letter-spacing: -0.025em;
  font-size: .95rem;
  margin-right: auto;
}
.brand__mark {
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--ember);
  transition: transform .6s var(--spring), border-color .4s var(--ease);
}
.brand:hover .brand__mark { transform: rotate(-8deg) scale(1.06); border-color: var(--line-2); }
.brand__text { transition: opacity .3s var(--ease); }

.nav__links {
  position: relative;
  display: flex;
  align-items: center;
  gap: .3rem;
}
.nav__links a {
  position: relative;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: .5em;
  padding: .55rem .9rem;
  border-radius: 999px;
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--text-2);
  transition: color .35s var(--ease);
}
.nav__links a:hover, .nav__links a.is-active { color: var(--text); }
.nav__idx {
  color: var(--text-3);
  font-size: 9.5px;
  transition: color .35s var(--ease);
}
.nav__links a.is-active .nav__idx { color: var(--ember); }

.nav__pill {
  position: absolute;
  z-index: 1;
  top: 0; left: 0;
  height: 100%;
  border-radius: 999px;
  background: var(--card-2);
  border: 1px solid var(--line);
  opacity: 0;
  transform: translateX(var(--pill-x, 0));
  width: var(--pill-w, 0);
  transition: transform .5s var(--ease-out), width .5s var(--ease-out), opacity .35s var(--ease);
}
.nav__links.has-pill .nav__pill { opacity: 1; }

.nav__tools { display: flex; align-items: center; gap: .55rem; }

.iconbtn {
  position: relative;
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--text-2);
  transition: color .35s var(--ease), border-color .35s var(--ease), transform .5s var(--spring);
}
.iconbtn:hover { color: var(--text); border-color: var(--line-2); transform: scale(1.06); }
.iconbtn .ico {
  grid-area: 1 / 1;
  width: 17px; height: 17px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  transition: opacity .4s var(--ease), transform .5s var(--spring);
}
.ico--still { opacity: 0; transform: scale(.4); }
html.calm .ico--motion { opacity: 0; transform: scale(.4); }
html.calm .ico--still  { opacity: 1; transform: none; }

[data-theme="dark"]  .ico--sun  { opacity: 1; transform: none; }
[data-theme="dark"]  .ico--moon { opacity: 0; transform: rotate(-70deg) scale(.4); }
[data-theme="light"] .ico--sun  { opacity: 0; transform: rotate(70deg) scale(.4); }
[data-theme="light"] .ico--moon { opacity: 1; transform: none; }

.nav__cta { padding: .68em 1.15em; }

.burger {
  display: none;
  width: 38px; height: 38px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--card);
  position: relative;
}
.burger span {
  position: absolute;
  left: 50%;
  width: 15px; height: 1.5px;
  background: currentColor;
  border-radius: 2px;
  transition: transform .45s var(--ease-out), opacity .3s var(--ease);
}
.burger span:nth-child(1) { transform: translate(-50%, -4px); }
.burger span:nth-child(2) { transform: translate(-50%, 3px); }
.burger[aria-expanded="true"] span:nth-child(1) { transform: translate(-50%, 0) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { transform: translate(-50%, 0) rotate(-45deg); }

/* Mobile menu */
.menu {
  position: fixed;
  inset: 0;
  z-index: 45;
  display: grid;
  align-content: center;
  gap: 3rem;
  padding: calc(var(--nav-h) + 2rem) var(--gut) var(--gut);
  background: color-mix(in srgb, var(--ink) 93%, transparent);
  backdrop-filter: blur(30px) saturate(1.3);
  -webkit-backdrop-filter: blur(30px) saturate(1.3);
  opacity: 0;
  pointer-events: none;
  transition: opacity .45s var(--ease);
}
.menu.is-open { opacity: 1; pointer-events: auto; }
.menu__links { display: grid; gap: .2rem; }
.menu__links a {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: .35em 0;
  font-size: clamp(2.4rem, 12vw, 4rem);
  font-weight: 600;
  letter-spacing: -0.05em;
  line-height: 1.05;
  border-bottom: 1px solid var(--line);
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .6s var(--ease-out), transform .6s var(--ease-out), color .3s var(--ease);
}
.menu.is-open .menu__links a { opacity: 1; transform: none; }
.menu__links a:nth-child(1) { transition-delay: .06s; }
.menu__links a:nth-child(2) { transition-delay: .12s; }
.menu__links a:nth-child(3) { transition-delay: .18s; }
.menu__links a:nth-child(4) { transition-delay: .24s; }
.menu__links a:nth-child(5) { transition-delay: .3s; }
.menu__links a:active { color: var(--ember); }
.menu__links i {
  font: 400 var(--t-xs)/1 var(--label);
  letter-spacing: .1em;
  color: var(--ember);
}
.menu__foot {
  display: grid;
  gap: .9rem;
  font-size: var(--t-sm);
  color: var(--text-2);
  opacity: 0;
  transition: opacity .5s var(--ease) .3s;
}
.menu.is-open .menu__foot { opacity: 1; }
.menu__social { display: flex; gap: 1.4rem; }

/* ── 6. Hero ────────────────────────────────────────────────────────── */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding-block: calc(var(--nav-h) + 5rem) clamp(2.5rem, 7vw, 5rem);
}
.hero .shell { display: grid; gap: clamp(1.5rem, 3vw, 2.3rem); }

.hero__eyebrow { display: flex; }

.hero__title {
  font-family: var(--display);
  font-size: var(--t-3xl);
  font-weight: var(--display-weight);
  line-height: .88;
  letter-spacing: var(--display-track);
  margin-block: -.06em;
}
.hero__title .line {
  display: block;
  overflow: hidden;
  padding-block: .06em;
  margin-block: -.06em;
}
html.js:not(.is-ready) .hero__title .word { transform: translateY(120%); }
.hero__title .word {
  display: inline-block;
  transition: transform 1.05s var(--ease-out);
}
.is-ready .hero__title .word { transform: none; }
.hero__title .line:nth-child(1) .word:nth-child(1) { transition-delay: .06s; }
.hero__title .line .word:nth-child(2) { transition-delay: .13s; }
.hero__title .line .word:nth-child(3) { transition-delay: .2s; }

/* The name is drawn twice: a muted base plus a saturated copy
   revealed through a radial mask that chases the pointer. */
[data-fill] {
  position: relative;
  background-image: var(--sweep);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  background-size: 190% 190%;
  background-position: var(--fx, 50%) var(--fy, 50%);
}
[data-fill]::before {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  color: var(--text);
  -webkit-mask-image: radial-gradient(300px circle at var(--lx, -300px) var(--ly, -300px), transparent 0%, #000 66%);
  mask-image: radial-gradient(300px circle at var(--lx, -300px) var(--ly, -300px), transparent 0%, #000 66%);
}

.hero__dot {
  color: var(--ember);
  font-family: var(--display);
  font-style: normal;
}

.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, .44fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: end;
  margin-top: clamp(.5rem, 2vw, 1.5rem);
}
.hero__main { display: grid; gap: clamp(1.3rem, 2.4vw, 1.9rem); }

/* Index rail — a table of contents that doubles as hero furniture */
.rail {
  display: grid;
  align-content: end;
  border-top: 1px solid var(--line);
}
.rail a {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: .9rem;
  padding: .85rem .2rem;
  border-bottom: 1px solid var(--line);
  color: var(--text-2);
  overflow: hidden;
  transition: color .35s var(--ease), padding-left .45s var(--ease-out);
}
.rail a::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: var(--sweep);
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform .45s var(--ease-out);
}
.rail a:hover { color: var(--text); padding-left: .85rem; }
.rail a:hover::before { transform: scaleY(1); transform-origin: top; }
.rail i {
  font: 400 10px/1 var(--label);
  letter-spacing: .14em;
  color: var(--text-3);
  font-style: normal;
  transition: color .35s var(--ease);
}
.rail a:hover i { color: var(--ember); }
.rail span { font-size: var(--t-sm); font-weight: 500; letter-spacing: -0.01em; }
.rail svg {
  width: 15px; height: 15px;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
  opacity: 0;
  transform: translateX(-8px);
  transition: opacity .35s var(--ease), transform .45s var(--ease-out);
}
.rail a:hover svg { opacity: 1; transform: none; }

.hero__role {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .7rem;
  font-family: var(--label);
  font-size: var(--t-sm);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-3);
}
.hero__slash { color: var(--ember); }
.scramble {
  color: var(--text);
  min-width: 15ch;
  display: inline-block;
}

.hero__lead {
  font-size: var(--t-lg);
  line-height: 1.55;
  letter-spacing: -0.018em;
  color: var(--text-2);
  max-width: 46ch;
  text-wrap: pretty;
}
.hero__lead em { color: var(--text); }

.hero__actions { display: flex; flex-wrap: wrap; gap: .75rem; }

.hero__foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 2rem;
  margin-top: clamp(1.5rem, 5vw, 3.5rem);
  padding-top: 1.6rem;
  border-top: 1px solid var(--line);
}

.scrollcue {
  display: inline-flex;
  align-items: center;
  gap: .85rem;
  color: var(--text-3);
  transition: color .35s var(--ease);
}
.scrollcue:hover { color: var(--text); }
.scrollcue__line {
  position: relative;
  width: 46px; height: 1px;
  background: var(--line-2);
  overflow: hidden;
}
.scrollcue__line i {
  position: absolute;
  inset: 0;
  background: var(--ember);
  transform-origin: left;
  animation: sweepline 2.4s var(--ease-io) infinite;
}
@keyframes sweepline {
  0%       { transform: scaleX(0); transform-origin: left; }
  45%      { transform: scaleX(1); transform-origin: left; }
  55%      { transform: scaleX(1); transform-origin: right; }
  100%     { transform: scaleX(0); transform-origin: right; }
}

.hero__social {
  display: flex;
  gap: 1.4rem;
  font-size: var(--t-sm);
  color: var(--text-2);
}
.hero__social a { position: relative; transition: color .3s var(--ease); }
.hero__social a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -3px;
  height: 1px;
  background: var(--ember);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .4s var(--ease-out);
}
.hero__social a:hover { color: var(--text); }
.hero__social a:hover::after { transform: scaleX(1); transform-origin: left; }

/* ── Marquee ────────────────────────────────────────────────────────── */

.marquee {
  display: grid;
  gap: 0;
  border-block: 1px solid var(--line);
  background: var(--card);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee__row { overflow: hidden; padding-block: .95rem; }
.marquee__row + .marquee__row { border-top: 1px solid var(--line); }
.marquee__track {
  display: flex;
  align-items: center;
  width: max-content;
  animation: slide var(--dur, 42s) linear infinite;
  will-change: transform;
}
.marquee__row--rev .marquee__track { animation-direction: reverse; }
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__track > * { margin-right: 1.8rem; }
.marquee__track span {
  font-size: clamp(.95rem, 1.5vw, 1.28rem);
  font-weight: 500;
  letter-spacing: -0.025em;
  color: var(--text-3);
  white-space: nowrap;
  transition: color .35s var(--ease);
}
.marquee__track span:hover { color: var(--text); }
.marquee__track i {
  flex: none;
  width: 6px; height: 6px;
  background: var(--ember);
  transform: rotate(45deg);
  opacity: .8;
}
@keyframes slide { to { transform: translateX(-50%); } }

/* ── 7. Work & side projects — the pinned horizontal gallery ────────── */

/* The section is tall; the stage inside it sticks while the rail slides
   sideways, so vertical scroll reads as horizontal travel. Below the
   breakpoint and under reduced motion this degrades to an ordinary
   swipeable scroller — same markup, no pinning. */

/* Six tiles, so five capabilities plus the pager land as two clean rows at
   three across and never leave a hole. No links, no shots — the copy is the
   whole card, which is the point: this is the work that cannot be shown. */
/* Each job gets a quiet label, so the numbering restarts per employer
   without the company name reading as a headline. */
/* The break between two jobs has to beat the gap between two cards inside
   one job by a clear margin, or the label reads as floating between the two
   blocks instead of heading the one under it. Generous above, tight below —
   the label binds downward, to the cards it numbers. */
.workGroup + .workGroup { margin-top: clamp(3.25rem, 6vw, 5.25rem); }
.workGroup__label {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .3rem .7rem;
  margin-bottom: clamp(1rem, 1.8vw, 1.5rem);
  padding-bottom: .9rem;
  border-bottom: 1px solid var(--line);
}
.workGroup__co { color: var(--text-2); }
.workGroup__meta { color: var(--text-3); }

.work {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr));
  gap: clamp(.9rem, 1.5vw, 1.35rem);
}
.work__item {
  display: grid;
  align-content: start;
  gap: .6rem;
  padding: clamp(1.35rem, 2.2vw, 1.85rem);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--card);
  transition: border-color .4s var(--ease), background .4s var(--ease),
              transform .5s var(--ease);
}
.work__item:hover {
  border-color: var(--line-2);
  background: var(--card-2);
  transform: translateY(-3px);
}
.work__idx,
.work__eyebrow {
  font-family: var(--label);
  font-size: var(--t-xs);
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  color: var(--text-3);
}
.work__idx { color: var(--ember); }
.work__title {
  font-family: var(--display);
  font-weight: var(--head-weight);
  letter-spacing: var(--head-track);
  font-size: var(--t-lg);
  line-height: 1.15;
}
.work__desc {
  font-size: var(--t-sm);
  line-height: 1.65;
  color: var(--text-2);
  text-wrap: pretty;
}
.work__item .tags { margin-top: .35rem; }
.work__item:hover .tags li { color: var(--text-2); border-color: var(--line-2); }

/* The pager tile is the strongest claim on the page, so it gets the accent. */
.work__item--pager {
  background: var(--card-2);
  border-color: color-mix(in srgb, var(--ember) 32%, var(--line));
}
.work__item--pager .work__eyebrow { color: var(--ember); }

.gallery { position: relative; }
.gallery__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  flex-direction: column;
  /* The stage owns a whole viewport, so the three rows have to hold it. Hint
     and counter sit against the top, the meter against the bottom, and the
     rail takes the middle at a height worth the screen it is given —
     centering the lot instead leaves a strip of cards floating in air. */
  justify-content: space-between;
  gap: clamp(1.5rem, 4vh, 2.75rem);
  overflow: hidden;
  padding-block: calc(var(--nav-h) + 1rem) clamp(1.5rem, 5vh, 3rem);
}

/* The head rides in the stage, so it has to be short: title and eyebrow in
   one column, the note beside them rather than under them. Same words as
   every other section head, a third of the height. */
.secHead--rail {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, clamp(26ch, 36%, 40ch));
  align-items: end;
  gap: clamp(1rem, 2.5vw, 2.75rem);
  width: 100%;
  max-width: var(--shell);
  margin: 0 auto;
  padding-inline: var(--gut);
}
.secHead--rail .secHead__note { margin-top: 0; font-size: var(--t-base); }

/* Context stays on screen for the whole horizontal run. */
.gallery__bar,
.gallery__meter {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gut);
  flex: none;
}
.gallery__bar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  font-family: var(--label);
  font-size: var(--t-xs);
  letter-spacing: var(--label-track);
  text-transform: uppercase;
  color: var(--text-3);
}
.gallery__count i { font-style: normal; color: var(--ember); }
.gallery__label i { font-style: normal; }
.gallery__label i::after { content: " \2192"; }
.gallery__label [data-hint="swipe"] { display: none; }

/* Text cards, so the rail is only as tall as the cards themselves: stretched
   to the tallest of them, and sitting as one band in the middle of the stage
   instead of a short card adrift in a viewport of air. */
.gallery__rail {
  display: flex;
  flex: none;
  align-items: stretch;
  height: clamp(320px, 34svh, 356px);
  gap: clamp(1.25rem, 2.4vw, 2.25rem);
  /* Full-bleed padding: the first card lines up with the shell while the rail
     itself runs to both screen edges. This is why the gallery sits outside
     .shell in the markup — inside it the inset would be applied twice. */
  padding-inline: max(var(--gut), calc((100vw - var(--shell)) / 2 + var(--gut)));
  will-change: transform;
}

.gallery__meter { height: 2px; }
.gallery__meter::before {
  content: "";
  display: block;
  height: 100%;
  background: var(--line);
  border-radius: 2px;
}
.gallery__meter { position: relative; }
.gallery__meter i {
  position: absolute;
  left: var(--gut);
  right: var(--gut);
  top: 0;
  height: 2px;
  background: var(--sweep);
  border-radius: 2px;
  transform: scaleX(var(--rail-p, 0));
  transform-origin: left;
}

/* Cards */
.card {
  position: relative;
  flex: none;
  width: clamp(280px, 26vw, 380px);
  display: flex;
}
.card--end { width: clamp(240px, 22vw, 320px); }

.card__link {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: clamp(1.35rem, 2.2vw, 1.75rem);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--ink-2) 76%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  transition: border-color .5s var(--ease), transform .6s var(--ease-out),
              background-color .5s var(--ease);
}
.card__link:hover {
  border-color: color-mix(in srgb, var(--accent) 50%, transparent);
  background: color-mix(in srgb, var(--ink-2) 92%, transparent);
}

/* The accent, bled from behind the card and picked up by its own backdrop
   blur. It used to pool behind the screenshot plate. */
.card__glow {
  position: absolute;
  inset: 6% 4%;
  z-index: 0;
  border-radius: 50%;
  background: var(--accent, var(--ember));
  filter: blur(58px);
  opacity: 0;
  transform: scale(.85);
  transition: opacity .7s var(--ease), transform .9s var(--ease-out);
}
.card:hover .card__glow { opacity: .38; transform: scale(1); }

.card__body { display: flex; flex-direction: column; gap: .55rem; flex: 1; }

.card__idx {
  display: flex;
  align-items: center;
  gap: .7rem;
  font-family: var(--label);
  font-weight: 500;
  font-size: var(--t-xs);
  letter-spacing: var(--label-track);
  color: var(--accent, var(--ember));
}
.card__idx i {
  flex: 1;
  height: 1px;
  background: currentColor;
  opacity: .35;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .6s var(--ease-out);
}
.card__link:hover .card__idx i { transform: scaleX(1); }

.card__title {
  font-family: var(--display);
  font-size: clamp(1.35rem, 2vw, 1.85rem);
  font-weight: var(--head-weight);
  letter-spacing: var(--head-track);
  line-height: 1.06;
  margin-top: .15rem;
}
.card__desc {
  display: block;
  color: var(--text-2);
  font-size: var(--t-sm);
  line-height: 1.6;
  text-wrap: pretty;
}
.card .tags { margin-top: .35rem; }

.card__cta {
  display: inline-flex;
  align-items: center;
  gap: .45em;
  margin-top: auto;
  padding-top: .9rem;
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--text);
}
.card__cta svg {
  width: 14px; height: 14px;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .45s var(--ease-out);
}
.card__link:hover .card__cta svg { transform: translate(3px, -3px); }

/* Closing card */
.card__link--end {
  justify-content: center;
  gap: .8rem;
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-style: dashed;
}
.card__link--end:hover { background: var(--card); }
.card__link--end .card__cta { margin-top: 0; }
.card__endIdx { font-family: var(--label); color: var(--text-3); letter-spacing: var(--label-track); font-size: var(--t-xs); }
.card__endTitle {
  font-family: var(--display);
  font-size: clamp(1.35rem, 2vw, 1.85rem);
  font-weight: var(--head-weight);
  letter-spacing: var(--head-track);
  line-height: 1.1;
}
.card__endTitle em { color: var(--ember); }

/* Rail falls back to a plain swipeable scroller where pinning would fight
   the browser's own scrolling. */
/* Set by the rail measurement when the cards already fit across. An ordinary
   row then, with no browse hint or progress meter for a run that is entirely
   on screen. */
.gallery.is-static .gallery__stage {
  position: static;
  height: auto;
  display: block;
  overflow: visible;
  padding-block: 0;
}
.gallery.is-static .gallery__rail {
  /* The sticky run's padding exists to line the first card up with the shell
     while the rail is clipped. Nothing clips it here, so swap that inset for
     the shell itself, drop the pinned height, and let the rows wrap. */
  flex-wrap: wrap;
  align-items: stretch;
  height: auto;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gut);
  transform: none !important;
}
.gallery.is-static .gallery__bar,
.gallery.is-static .gallery__meter { display: none; }
.gallery.is-static .secHead--rail { margin-bottom: clamp(2.75rem, 5vw, 4.5rem); }

@media (max-width: 900px), (max-height: 719px) {
  .section--rail { padding-block: var(--sec); scroll-margin-top: 0; }
  .gallery__stage { position: static; height: auto; display: block; overflow: visible; }
  .secHead--rail { display: block; margin-bottom: clamp(2.75rem, 5vw, 4.5rem); }
  .secHead--rail .secHead__lead { max-width: 46ch; }
  .secHead--rail .secHead__note { margin-top: 1.4rem; font-size: var(--t-lg); }
  .gallery__rail {
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    height: auto;
    padding-block: .5rem 1.75rem;
    scrollbar-width: thin;
    transform: none !important;
  }
  .gallery__rail > * { scroll-snap-align: center; }
  .gallery__bar { padding-inline: var(--gut); }
  .gallery__label [data-hint="scroll"] { display: none; }
  .gallery__label [data-hint="swipe"] { display: inline; }
  .gallery__meter i { transform: none; opacity: .3; }
  .card { width: min(78vw, 380px); }
  .card--end { width: min(60vw, 280px); }
}

/* ── 8. Stack ───────────────────────────────────────────────────────── */

.section--stack::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--line-2) 30%, var(--line-2) 70%, transparent);
}

.stack {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: clamp(1.75rem, 3vw, 2.75rem);
}
.stack__group { display: grid; gap: 1.15rem; align-content: start; }
.stack__label {
  display: flex;
  align-items: center;
  gap: .7rem;
  color: var(--text-3);
  padding-bottom: .9rem;
  border-bottom: 1px solid var(--line);
}
.stack__label i {
  display: grid;
  place-items: center;
  width: 20px; height: 20px;
  border-radius: 5px;
  background: var(--card-2);
  border: 1px solid var(--line);
  color: var(--ember);
  font-size: 9.5px;
  font-style: normal;
}

.chips { display: flex; flex-wrap: wrap; gap: .45rem; }
.chips li {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  isolation: isolate;
  transition: border-color .4s var(--ease), transform .5s var(--spring);
}
.chips li span {
  position: relative;
  z-index: 2;
  display: block;
  padding: .58em 1em;
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--text-2);
  white-space: nowrap;
  transition: color .35s var(--ease);
}
.chips li::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--sweep);
  transform: translateY(101%);
  transition: transform .5s var(--ease-out);
}
.chips li:hover { border-color: transparent; transform: translateY(-2px); }
.chips li:hover::before { transform: none; }
.chips li:hover span { color: #0b0b0e; }

/* ── 9. About ───────────────────────────────────────────────────────── */

.portrait {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  /* Ramped, not flat: the top of the frame is all empty studio backdrop, so
     the first stop sits on the surface color and the accent only reaches
     full strength across the subject. */
  background: linear-gradient(176deg, var(--ink-3), var(--ember) 72%, var(--iris));
  box-shadow: var(--shadow);
  isolation: isolate;
}
.portrait img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  /* Multiply over the gradient turns a white-backdrop headshot into a duotone. */
  mix-blend-mode: multiply;
  filter: grayscale(1) contrast(1.06);
  transform: scale(1.02) translateY(var(--py, 0px));
  transition: filter .8s var(--ease), opacity .8s var(--ease);
}
.portrait::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, color-mix(in srgb, var(--ink) 72%, transparent), transparent 46%);
  pointer-events: none;
}
.portrait:hover img { filter: grayscale(.15) contrast(1.02); mix-blend-mode: normal; }
.portrait figcaption {
  position: absolute;
  left: 1.4rem; bottom: 1.2rem;
  z-index: 2;
  font: 400 var(--t-xs)/1 var(--label);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text);
  mix-blend-mode: difference;
}

/* ── 10. Contact ────────────────────────────────────────────────────── */

.section--contact { padding-bottom: clamp(4rem, 8vw, 7rem); }
.section--contact .secHead { margin-bottom: clamp(1.5rem, 3vw, 2.5rem); }

.cta {
  font-family: var(--display);
  font-size: clamp(2.5rem, 8.2vw, 7.2rem);
  font-weight: var(--head-weight);
  line-height: .96;
  letter-spacing: -0.055em;
  margin-bottom: clamp(2.2rem, 5vw, 3.5rem);
}
.cta .line {
  display: block;
  overflow: hidden;
  padding-block: .08em;
  margin-block: -.08em;
}
html.js .cta:not(.is-in) .word { transform: translateY(120%); }
.cta .word {
  display: inline-block;
  transition: transform 1s var(--ease-out);
}
.cta.is-in .word { transform: none; }
.cta.is-in .line:nth-child(2) .word { transition-delay: .1s; }
.cta em { color: var(--ember); }

.contact {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem;
  padding-bottom: clamp(1.5rem, 3vw, 2.25rem);
}

.contact__mail {
  display: inline-flex;
  align-items: center;
  gap: 1rem;
  font-size: clamp(1.05rem, 3.2vw, 2.05rem);
  font-weight: 500;
  letter-spacing: -0.035em;
  padding: .5em 0;
  overflow-wrap: anywhere;
}
.contact__mailText {
  background-image: var(--sweep);
  background-repeat: no-repeat;
  background-size: 0% 2px;
  background-position: 0 100%;
  transition: background-size .6s var(--ease-out);
}
.contact__mail:hover .contact__mailText { background-size: 100% 2px; }
.contact__mail svg {
  flex: none;
  width: clamp(20px, 3vw, 30px);
  height: clamp(20px, 3vw, 30px);
  fill: none; stroke: var(--ember); stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .5s var(--ease-out);
}
.contact__mail:hover svg { transform: translateX(7px); }

.copy {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  padding: .6em 1em;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  color: var(--text-3);
  font: 400 var(--t-xs)/1 var(--label);
  letter-spacing: .1em;
  text-transform: uppercase;
  transition: color .35s var(--ease), border-color .35s var(--ease);
}
.copy:hover { color: var(--text); border-color: var(--line-2); }
.copy svg {
  width: 14px; height: 14px;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}
.copy.is-done { color: var(--mint); border-color: color-mix(in srgb, var(--mint) 45%, transparent); }

/* The portrait sits here now, paired with the links as a sign-off. It is
   sized down from the About layout: a face beside the details, not a figure
   the section is built around. */
.contact__end {
  display: grid;
  grid-template-columns: minmax(0, 240px) minmax(0, 1fr);
  gap: clamp(1.75rem, 5vw, 3.5rem);
  align-items: center;
}
.contact__end .portrait { border-radius: var(--r-md); }
.contact__details { display: grid; align-content: center; }

.contact__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0;
  border-top: 1px solid var(--line);
}
.contact__list li {
  display: grid;
  gap: .5rem;
  padding: 1.5rem 1.4rem 1.5rem 0;
  border-bottom: 1px solid var(--line);
}
.contact__k { color: var(--text-3); }
.contact__list a {
  display: inline-flex;
  align-items: center;
  gap: .4em;
  width: fit-content;
  font-size: var(--t-base);
  font-weight: 500;
  position: relative;
  transition: color .3s var(--ease);
}
.contact__list a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -3px;
  height: 1px;
  background: var(--ember);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .45s var(--ease-out);
}
.contact__list a:hover::after { transform: scaleX(1); transform-origin: left; }
.contact__list svg {
  width: 13px; height: 13px;
  fill: none; stroke: var(--text-3); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .4s var(--ease-out), stroke .3s var(--ease);
}
.contact__list a:hover svg { transform: translate(2px, -2px); stroke: var(--ember); }

/* ── 11. Footer ─────────────────────────────────────────────────────── */

.foot {
  border-top: 1px solid var(--line);
  padding-block: 2.2rem;
  background: color-mix(in srgb, var(--ink-2) 60%, transparent);
}
.foot__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  font-size: var(--t-sm);
  color: var(--text-3);
}
.foot__note { letter-spacing: .08em; }
.foot__top {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  transition: color .3s var(--ease);
}
.foot__top:hover { color: var(--text); }
.foot__top svg {
  width: 14px; height: 14px;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .45s var(--ease-out);
}
.foot__top:hover svg { transform: translateY(-3px); }

/* ── 12. Motion & media ─────────────────────────────────────────────── */

html.js .reveal {
  opacity: 0;
  transform: translateY(30px);
  transition:
    opacity .9s var(--ease-out) calc(var(--d, 0) * 90ms),
    transform .9s var(--ease-out) calc(var(--d, 0) * 90ms);
}
html.js .reveal.is-in { opacity: 1; transform: none; }

/* Per-word reveal for lead paragraphs. Words only exist once JS splits the
   text, so nothing here can hide copy from a reader without scripting. */
[data-words] .w {
  display: inline-block;
  opacity: 0;
  transform: translateY(.42em);
  transition:
    opacity .55s var(--ease-out) calc(var(--i) * 24ms),
    transform .7s var(--ease-out) calc(var(--i) * 24ms);
}
[data-words].is-in .w { opacity: 1; transform: none; }

/* Content leans into the direction of travel; JS writes the transform. */
[data-skew] { will-change: transform; }

/* Theme swap: circular wipe from the toggle via the View Transitions API */
::view-transition-old(root),
::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
::view-transition-old(root) { z-index: 1; }
::view-transition-new(root) { z-index: 2; }
html.vt-theme::view-transition-new(root) {
  animation: reveal-theme .62s var(--ease-out);
}
@keyframes reveal-theme {
  from { clip-path: circle(0 at var(--tx, 50%) var(--ty, 50%)); }
  to   { clip-path: circle(160% at var(--tx, 50%) var(--ty, 50%)); }
}

@media (max-width: 900px) {
  :root { --nav-h: 66px; }
  .nav__links, .nav__cta { display: none; }
  .burger { display: block; }
  .brand__text { display: none; }

  .contact__end { grid-template-columns: 1fr; }
  .contact__end .portrait { max-width: 260px; }
}

@media (max-width: 860px) {
  .hero__grid { grid-template-columns: 1fr; }
  .rail { display: none; }
}

@media (max-width: 620px) {
  .hero__foot { flex-direction: column; align-items: flex-start; gap: 1.6rem; }
  .hero__social { flex-wrap: wrap; }
  .hero__actions .btn { flex: 1 1 auto; justify-content: center; }
  .contact__list li { padding-right: 0; }
  .foot__inner { justify-content: flex-start; }
  .foot__note { order: 3; flex-basis: 100%; }
}

/* ── Reduced motion ──────────────────────────────────────────────────────
   "Reduce motion" means no vestibular motion — large translation, parallax,
   scroll-hijacking, drifting backgrounds. It does not mean a dead page, so
   opacity and color transitions stay, and so does the 6px status pulse.
   The media query only seeds the default: html.calm is what actually gates
   everything, and the visitor can flip it from the nav. */

@media (prefers-reduced-motion: reduce) {
  html:not(.js) { scroll-behavior: auto; }
  html:not(.js) .reveal { opacity: 1; transform: none; }
  html:not(.js) .ink,
  html:not(.js) .loader { display: none; }
  html:not(.js) .marquee__track,
  html:not(.js) .blob,
  html:not(.js) .ambient__grain { animation: none; }
}

html.calm { scroll-behavior: auto; }

/* Ambient drift, marquee travel, film grain, sweeping rules: all motion. */
html.calm .marquee__track,
html.calm .blob,
html.calm .ambient__grain,
html.calm .scrollcue__line i { animation: none !important; }

html.calm .ink { display: none; }
html.calm .loader { display: none; }
html.calm .ambient__spot { display: none; }
html.calm .cursor { display: none; }
html.calm.has-cursor, html.calm.has-cursor * { cursor: auto !important; }

/* Nothing may be left parked off-screen or invisible. */
html.calm .reveal { opacity: 1 !important; transform: none !important; transition: none; }
html.calm [data-words] .w { opacity: 1; transform: none; transition: none; }
html.calm .hero__title .word,
html.calm .cta .word { transform: none !important; }
html.calm [data-fill]::before { -webkit-mask-image: none; mask-image: none; }
html.calm [data-skew] { transform: none !important; }

/* Scroll-hijacking is the big one — hand the rail back to the browser. Same
   for a page with no script: nothing would be driving the rail, so pinning
   it would clip a run the visitor has no way to move. Unpinned, the head
   unstacks and the section takes its own spacing back. */
html.calm .section--rail,
html:not(.js) .section--rail { padding-block: var(--sec); scroll-margin-top: 0; }
html.calm .gallery__stage,
html:not(.js) .gallery__stage {
  position: static;
  height: auto;
  display: block;
  overflow: visible;
  padding-block: 0;
}
html.calm .secHead--rail,
html:not(.js) .secHead--rail { display: block; margin-bottom: clamp(2.75rem, 5vw, 4.5rem); }
html.calm .secHead--rail .secHead__lead,
html:not(.js) .secHead--rail .secHead__lead { max-width: 46ch; }
html.calm .secHead--rail .secHead__note,
html:not(.js) .secHead--rail .secHead__note { margin-top: 1.4rem; font-size: var(--t-lg); }
html.calm .gallery__rail,
html:not(.js) .gallery__rail {
  overflow-x: auto;
  overflow-y: hidden;
  height: auto;
  padding-block: 1rem 1.75rem;
  transform: none !important;
  scroll-snap-type: x mandatory;
}
html.calm .gallery__rail > *,
html:not(.js) .gallery__rail > * { scroll-snap-align: center; }
html.calm .gallery__bar,
html:not(.js) .gallery__bar { padding-block: 0 .5rem; }
html.calm .gallery__label [data-hint="scroll"],
html:not(.js) .gallery__label [data-hint="scroll"] { display: none; }
html.calm .gallery__label [data-hint="swipe"],
html:not(.js) .gallery__label [data-hint="swipe"] { display: inline; }
html.calm .gallery__meter i,
html:not(.js) .gallery__meter i { transform: none; opacity: .3; }

/* Transforms that only fire on hover are user-initiated and brief, but they
   are still movement — trade them for a color response. */
html.calm .btn:hover,
html.calm .chips li:hover,
html.calm .iconbtn:hover,
html.calm .brand:hover .brand__mark { transform: none !important; }
html.calm .btn svg,
html.calm .card__cta svg,
html.calm .contact__list svg,
html.calm .foot__top svg { transition: none; }
html.calm .portrait img { transform: none !important; }

@media print {
  .ambient, .cursor, .loader, .nav, .menu, .progress, .marquee, .scrollcue { display: none !important; }
  body { background: #fff; color: #000; }
  .section { padding-block: 2rem; }
  a::after { content: " (" attr(href) ")"; font-size: .75em; word-break: break-all; }
}
