/*
 * Dark portfolio design system. Inter throughout, stacked dual-frame cards,
 * fixed dot grid, left-aligned, single ember accent.
 */
:root {
  --ds-bg: #050505;
  --ds-surface: rgba(255, 255, 255, 0.04);
  --ds-surface-2: rgba(255, 255, 255, 0.07);
  --ds-surface-elev: rgba(255, 255, 255, 0.12);
  --ds-border: rgba(255, 255, 255, 0.2);
  --ds-border-soft: rgba(255, 255, 255, 0.12);
  --ds-border-hairline: rgba(255, 255, 255, 0.08);

  --ds-text: #ffffff;
  --ds-text-secondary: rgba(255, 255, 255, 0.7);
  --ds-text-tertiary: rgba(255, 255, 255, 0.5);
  --ds-text-muted: rgba(255, 255, 255, 0.6);

  --ds-accent: #ff4704; /* focus outlines only; never a visible highlight */

  /* The intro light's blue, white and gold: the one highlight palette on the
     site, used by the border glow and the match pill. */
  --ds-glow-blue: rgb(170, 188, 255);
  --ds-glow-white: rgb(255, 248, 236);
  --ds-glow-gold: rgb(246, 160, 74);
  --ds-glow-warm: rgba(246, 160, 74, 0.95);
  --ds-glow-cool: rgba(170, 188, 255, 0.55);
  --ds-glow-cool-0: rgba(170, 188, 255, 0);

  --ds-font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --ds-font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;

  --ds-dot-color: rgba(255, 255, 255, 0.12);
  --ds-dot-size: 14px; /* matches DOT_SIZE in dot-canvas.js */

  --ds-text-micro: 12px;
  --ds-text-small: 13px;
  --ds-text-body: 14px;
  --ds-text-lead: 16px;
  --ds-text-card: 20px;
  --ds-text-section: 36px;
  --ds-text-hero: 48px;

  --ds-leading-tight: 1.08;
  --ds-leading-snug: 1.13;
  --ds-leading-normal: 1.5;
  --ds-leading-body: 1.43;

  --ds-tracking-hero: -0.02em;
  --ds-tracking-section: -0.02em;
  --ds-tracking-card: -0.005em;
  --ds-tracking-body: 0;
  --ds-tracking-wide: 0.05em;

  --ds-space-1: 4px;
  --ds-space-2: 8px;
  --ds-space-3: 12px;
  --ds-space-4: 16px;
  --ds-space-5: 20px;
  --ds-space-6: 24px;
  --ds-space-8: 32px;
  --ds-space-10: 40px;
  --ds-space-12: 48px;
  --ds-space-16: 64px;

  --ds-btn-height: 36px;
  --ds-btn-padding-x: 16px;
  --ds-card-padding: 24px;
  --ds-section-gap: 96px;
  --ds-section-head-gap: 8px;
  --ds-section-stack-gap: 48px;
  --ds-nav-height: 64px;

  --ds-radius-sm: 4px;
  --ds-radius-md: 12px;
  --ds-radius-lg: 16px;
  --ds-radius-full: 9999px;

  --ds-container-max: 1200px;
  --ds-container-padding: clamp(20px, 4vw, 32px);

  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --dur-fast: 180ms;
  --dur-base: 250ms;

  color-scheme: dark;
}

/* Wide-gamut displays get a richer ember: same lightness and hue as #ff4704,
   more chroma than sRGB can show. Everything else keeps the hex above. */
@supports (color: oklch(0 0 0)) {
  @media (color-gamut: p3) {
    :root { --ds-accent: oklch(0.66 0.25 36); }
  }
}

/* ===== Base ===== */

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; background: var(--ds-bg); overflow-x: hidden; scrollbar-gutter: stable; }

body {
  margin: 0;
  background-color: var(--ds-bg);
  color: var(--ds-text);
  font-family: var(--ds-font-sans);
  font-size: var(--ds-text-body);
  line-height: var(--ds-leading-body);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-synthesis: style;
  font-feature-settings: "kern" 1;
  text-align: left;
  position: relative;
}

/* Fixed dot grid covers the viewport at all scroll positions */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  background-image: radial-gradient(var(--ds-dot-color) 1px, transparent 1px);
  background-size: var(--ds-dot-size) var(--ds-dot-size);
  background-position: 0 0;
  pointer-events: none;
  z-index: 0;
}

body.has-dot-canvas::before { display: none; }

#dot-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
}

main, header, footer { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; transition: color 0.15s ease; }
h1, h2, h3, h4, p, ul { margin: 0; }
ul { padding: 0; list-style: none; }

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

/* ===== Headings ===== */

h1, h2, h3, h4 {
  font-family: var(--ds-font-sans);
  color: var(--ds-text);
  font-weight: 500;
  margin: 0;
}

h1 {
  font-size: clamp(40px, 4vw + 8px, var(--ds-text-hero));
  font-weight: 500;
  line-height: var(--ds-leading-tight);
  letter-spacing: var(--ds-tracking-hero);
  text-wrap: balance;
}

h2 {
  font-size: clamp(28px, 2.5vw + 8px, var(--ds-text-section));
  font-weight: 500;
  line-height: var(--ds-leading-snug);
  letter-spacing: var(--ds-tracking-section);
  text-wrap: balance;
}

h3 {
  font-size: var(--ds-text-card);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: var(--ds-tracking-card);
}

h4 {
  font-size: var(--ds-text-lead);
  font-weight: 500;
  letter-spacing: var(--ds-tracking-body);
}

p {
  color: var(--ds-text-secondary);
  font-size: var(--ds-text-body);
  line-height: var(--ds-leading-body);
  letter-spacing: var(--ds-tracking-body);
  text-wrap: pretty;
}

.lead {
  font-size: var(--ds-text-lead);
  line-height: var(--ds-leading-normal);
  letter-spacing: var(--ds-tracking-body);
  color: var(--ds-text-secondary);
  max-width: 64ch;
  text-wrap: balance;
  margin: 0;
}

/* ===== Buttons ===== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ds-space-2);
  height: var(--ds-btn-height);
  padding: 0 var(--ds-btn-padding-x);
  border-radius: var(--ds-radius-full);
  font-family: var(--ds-font-sans);
  font-size: var(--ds-text-body);
  font-weight: 500;
  letter-spacing: var(--ds-tracking-body);
  border: 1px solid transparent;
  cursor: pointer;
  line-height: 1;
  white-space: nowrap;
  transition:
    transform var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

.btn:active { transform: scale(0.96); }

.btn-primary {
  background: var(--ds-text);
  color: var(--ds-bg);
  border-color: var(--ds-text);
}
.btn-primary:hover {
  background: rgba(255, 255, 255, 0.85);
  border-color: rgba(255, 255, 255, 0.85);
}

.btn-secondary {
  background: var(--ds-surface-elev);
  color: var(--ds-text);
  border-color: transparent;
  box-shadow: none;
}
.btn-secondary:hover {
  background: var(--ds-border);
}

.btn-ghost {
  background: transparent;
  color: var(--ds-text-secondary);
  border-color: transparent;
  box-shadow: none;
}
.btn-ghost:hover { color: var(--ds-text); }

.btn.btn-compact {
  height: 32px;
  padding: 0 var(--ds-space-3);
  font-size: var(--ds-text-body);
}

/* Touch devices: bump real control heights so tap targets clear 44px. */
@media (hover: none) and (pointer: coarse) {
  .btn { height: 44px; }
  .btn.btn-compact { height: 40px; padding: 0 var(--ds-space-4); }
  .link-arrow { padding: var(--ds-space-2) 0 var(--ds-space-3); }
  .contact-list a { padding: var(--ds-space-5) 0; }
  .tl-item { padding: var(--ds-space-3) 0; }
}

/* The outline follows each element's own radius, so pills stay pills. */
:focus-visible {
  outline: 2px solid var(--ds-accent);
  outline-offset: 3px;
}

/* Fixed nav is 64px tall; anchored sections land below it, not under it. */
section[id] { scroll-margin-top: var(--ds-nav-height); }

/* ===== Card ===== */

.card {
  background-color: var(--ds-surface-2);
  border: 1px solid var(--ds-border-hairline);
  border-radius: var(--ds-radius-lg);
  padding: var(--ds-space-1);
  display: flex;
  flex-direction: column;
  position: relative;
}

.card-panel {
  background-color: var(--ds-bg);
  border-radius: var(--ds-radius-md);
  padding: var(--ds-card-padding);
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-2);
  flex: 1;
  height: 100%;
}

.card-panel h3 { margin: 0; color: var(--ds-text); }
.card-panel p {
  margin: 0;
  font-size: var(--ds-text-body);
  color: var(--ds-text-secondary);
  line-height: var(--ds-leading-body);
  letter-spacing: var(--ds-tracking-body);
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--ds-space-6);
  width: 100%;
}

@media (max-width: 900px) {
  .card-grid { grid-template-columns: 1fr; }
}

/* ===== Principles ===== */

.section-head.section-head--center { align-items: center; text-align: center; }

.principles { display: flex; flex-direction: column; width: 100%; }

/* Three lines drop from the heading: the middle one runs straight into the
   middle card, the outer two turn out and land on the outer cards' centres.
   They fade as they reach the cards. */
.principles-tree {
  --lane: 12px;
  --corner: 12px;
  --target: calc((100% - 2 * var(--ds-space-6)) / 6);
  position: relative;
  height: clamp(72px, 8vw, 112px);
  color: var(--ds-border);
  -webkit-mask-image: linear-gradient(#000 40%, transparent);
  mask-image: linear-gradient(#000 40%, transparent);
}

.principles-tree__trunk {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  border-left: 1px solid currentColor;
}

.principles-tree__branch {
  position: absolute;
  top: 0;
  bottom: 0;
}

.principles-tree__branch::before,
.principles-tree__branch::after {
  content: '';
  position: absolute;
  border: 0 solid currentColor;
}

.principles-tree__branch--left { left: var(--target); right: calc(50% + var(--lane)); }

.principles-tree__branch--left::before {
  top: 0;
  right: 0;
  left: var(--corner);
  height: 50%;
  border-right-width: 1px;
  border-bottom-width: 1px;
  border-bottom-right-radius: var(--corner);
}

.principles-tree__branch--left::after {
  top: calc(50% - 1px);
  bottom: 0;
  left: 0;
  width: calc(var(--corner) + 1px);
  border-left-width: 1px;
  border-top-width: 1px;
  border-top-left-radius: var(--corner);
}

.principles-tree__branch--right { left: calc(50% + var(--lane)); right: var(--target); }

.principles-tree__branch--right::before {
  top: 0;
  left: 0;
  right: var(--corner);
  height: 50%;
  border-left-width: 1px;
  border-bottom-width: 1px;
  border-bottom-left-radius: var(--corner);
}

.principles-tree__branch--right::after {
  top: calc(50% - 1px);
  bottom: 0;
  right: 0;
  width: calc(var(--corner) + 1px);
  border-right-width: 1px;
  border-top-width: 1px;
  border-top-right-radius: var(--corner);
}

@media (max-width: 900px) {
  .principles-tree { display: none; }
  .principles { gap: 0; }
}

/* Principle icons: small dark glass orbs, their rims catching the intro
   light's blue and gold. */
.orbs {
  position: relative;
  display: flex;
  align-items: center;
  height: 56px;
  margin-bottom: var(--ds-space-3);
}

.orbs i {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 34% 28%, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0) 42%),
    radial-gradient(circle at 50% 60%, #1d1d1d, #070707 72%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.08),
    inset -3px -4px 6px rgba(246, 160, 74, 0.2),
    inset 3px 3px 6px rgba(170, 188, 255, 0.1),
    0 6px 14px rgba(0, 0, 0, 0.55);
}

.orbs--pair i + i { margin-left: -14px; }

.orbs--stack { flex-direction: column; justify-content: center; align-items: flex-start; }
.orbs--stack i { width: 34px; height: 34px; }
.orbs--stack i + i { margin-top: -12px; }

.orbs--cluster { width: 60px; }
.orbs--cluster i { position: absolute; width: 34px; height: 34px; }
.orbs--cluster i:nth-child(1) { left: 0; top: 14px; }
.orbs--cluster i:nth-child(2) { left: 13px; top: 0; }
.orbs--cluster i:nth-child(3) { left: 22px; top: 18px; }

/* ===== Methodology ===== */

/* Breaks out of .frame to span 100vw. The canvas fills the sticky viewport,
   the heading floats top-center, the four step cards sit in the corners. */
.methodology {
  width: 100vw;
  margin-left: calc(-50vw + 50%);
  margin-right: calc(-50vw + 50%);
  position: relative;
}

.methodology__scroll {
  position: relative;
  height: 700vh;
}

.methodology__sticky {
  position: sticky;
  top: 0;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

#methodology-viz {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;
}

.methodology__head {
  position: absolute;
  /* Clear the fixed 64px site nav so the heading never slides under it. */
  top: calc(var(--ds-nav-height) + clamp(16px, 3vh, 36px));
  left: 50%;
  transform: translateX(-50%);
  text-align: center;
  z-index: 2;
  max-width: 90vw;
}

.methodology__head h2 {
  font-size: clamp(24px, 2.4vw + 8px, var(--ds-text-section));
  margin: 0 0 var(--ds-space-2);
}

.methodology__head .lead {
  font-size: var(--ds-text-small);
  color: var(--ds-text-tertiary);
  margin: 0;
}

.methodology__steps {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 1400px;
  height: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  z-index: 2;
  pointer-events: none;
}

.step {
  position: absolute;
  max-width: 220px;
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-1);
  opacity: 0.22;
  transition:
    opacity 350ms var(--ease-out),
    transform 350ms var(--ease-out);
  transform: translateY(2px);
  pointer-events: auto;
}

.step.is-active {
  opacity: 1;
  transform: translateY(0);
}

.step__title {
  font-size: var(--ds-text-lead);
  font-weight: 500;
  letter-spacing: var(--ds-tracking-card);
  color: var(--ds-text);
  margin: 0;
}

.step__body {
  font-size: var(--ds-text-small);
  color: var(--ds-text-secondary);
  line-height: var(--ds-leading-body);
  margin: 0;
}

.step--tl { top: clamp(120px, 22vh, 200px); left: clamp(24px, 5vw, 64px); }
.step--tr { top: clamp(120px, 22vh, 200px); right: clamp(24px, 5vw, 64px); text-align: right; align-items: flex-end; }
.step--bl { bottom: clamp(40px, 10vh, 96px); left: clamp(24px, 5vw, 64px); }
.step--br { bottom: clamp(40px, 10vh, 96px); right: clamp(24px, 5vw, 64px); text-align: right; align-items: flex-end; }

/* Mobile: the four corner blocks become one bottom-anchored caption that
   swaps with the active step. */
@media (max-width: 900px) {
  .methodology { width: 100%; margin: 0; }
  /* Shorter scroll travel; long pins feel laborious with one-finger swipes. */
  .methodology__scroll { height: 500vh; }

  .methodology__head {
    top: calc(var(--ds-nav-height) + clamp(8px, 2vh, 20px));
    left: var(--ds-container-padding);
    right: var(--ds-container-padding);
    transform: none;
    max-width: none;
    text-align: left;
  }
  .methodology__head h2 { font-size: clamp(22px, 6vw, 30px); margin: 0 0 var(--ds-space-1); }
  .methodology__head .lead { font-size: var(--ds-text-small); }

  /* Undo the desktop centering transform. */
  .methodology__steps {
    transform: none;
    left: 0;
    right: 0;
    width: 100%;
    max-width: none;
    padding: 0 var(--ds-container-padding);
  }

  .step {
    position: absolute;
    inset: auto 0 clamp(24px, 6vh, 56px) 0;
    max-width: none;
    padding: 0 var(--ds-container-padding);
    text-align: left;
    align-items: flex-start;
    opacity: 0;
    pointer-events: none;
    transform: translateY(6px);
  }
  /* All four steps stack in the same bottom slot. */
  .step--tl, .step--tr, .step--bl, .step--br {
    top: auto;
    right: 0;
    bottom: clamp(24px, 6vh, 56px);
    left: 0;
    text-align: left;
    align-items: flex-start;
  }
  .step.is-active { opacity: 1; transform: translateY(0); pointer-events: auto; }
  .step__title { font-size: var(--ds-text-card); }
  .step__body { font-size: var(--ds-text-body); max-width: 52ch; }
}

/* ===== Frame + Section ===== */

.frame {
  position: relative;
  max-width: 1220px;
  margin: 0 auto;
  border: none;
  padding: 0;
}

main {
  padding: 0;
  display: block;
}

.section {
  width: 100%;
  padding: clamp(24px, 3vw, 40px) clamp(24px, 4vw, 48px);
  border: 1px solid var(--ds-border-hairline);
  background: var(--ds-bg);
  position: relative;
}

/* Overlap stacked section borders so the shared edge is a single hairline. */
.section + .section { margin-top: -1px; }

/* Pages outside the portfolio (gate, AI view, job match, case studies) sit in
   one bordered section too, so the dot grid stays behind the page instead of
   under the text. */
.gate > .section,
.ai > .section,
.match > .section,
.page > .section { width: 100%; }

/* ===== Border glow =====
   A radial spotlight at the cursor lights up only the 1px border ring (mask
   trick), so it travels around all four sides. It spreads like the intro
   light: a white core, then gold, then blue fading out. scatter.js writes
   --atmos-x, --atmos-y and --atmos-opacity on every .section and .card. */
.section::after,
.card::after {
  content: '';
  position: absolute;
  inset: -1px;
  padding: 1px;
  border-radius: inherit;
  pointer-events: none;
  background: radial-gradient(
    circle 220px at var(--atmos-x, 50%) var(--atmos-y, 50%),
    var(--ds-glow-white) 0%,
    var(--ds-glow-warm) 22%,
    var(--ds-glow-cool) 48%,
    var(--ds-glow-cool-0) 80%
  );
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  mask-composite: exclude;
  opacity: var(--atmos-opacity, 0);
  transition: opacity var(--dur-base) var(--ease-out);
}

.section-inner {
  max-width: 1100px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--ds-section-stack-gap);
  align-items: stretch;
  text-align: left;
  width: 100%;
}

.section-head {
  display: flex;
  flex-direction: column;
  gap: var(--ds-section-head-gap);
  align-items: flex-start;
  text-align: left;
  width: 100%;
}

.section-head h2 { margin: 0; max-width: 24ch; }
.section-head .lead { margin: 0; max-width: 64ch; text-align: left; }

@media (max-width: 720px) {
  .section { padding: 48px 20px; }
}

/* ===== Site nav ===== */

.site-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  height: var(--ds-nav-height);
  display: flex;
  align-items: center;
  padding: 0 var(--ds-container-padding);
  background: rgba(0, 0, 0, 0.65);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-bottom: 1px solid var(--ds-border-hairline);
}

.site-nav-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--ds-container-max);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-space-6);
}

.site-nav-group {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--ds-space-3);
  color: var(--ds-text);
  padding: 0;
}

.brand__mark { width: 28px; height: auto; flex-shrink: 0; color: currentColor; }

.brand__wordmark {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ds-text);
}

.brand__role {
  font-size: var(--ds-text-small);
  font-weight: 400;
  color: var(--ds-text-muted);
  letter-spacing: 0;
  padding-left: var(--ds-space-3);
  margin-left: var(--ds-space-1);
  border-left: 1px solid var(--ds-border-hairline);
}

@media (max-width: 720px) {
  .brand__role { display: none; }
}

.nav-links { display: flex; align-items: center; gap: var(--ds-space-1); }

@media (max-width: 720px) {
  .nav-links { display: none; }
}

/* Full-bleed intro animation that gates the rest of the page. Transparent:
   the stage's canvas covers it, and once the light is boxed in, the dot grid
   shows in the gutters like everywhere else. */
.intro-hero {
  position: relative;
  width: 100%;
  margin: 0;
  padding: 0;
  border: none;
  z-index: 2;
}

.reveal-after-intro {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s var(--ease-out);
}

body.intro-done .reveal-after-intro {
  opacity: 1;
  pointer-events: auto;
}

/* The nav waits until the hero itself has scrolled halfway out. */
.reveal-after-hero {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s var(--ease-out);
}

body.hero-passed .reveal-after-hero {
  opacity: 1;
  pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
  .reveal-after-intro,
  .reveal-after-hero { opacity: 1; pointer-events: auto; transition: none; }
}

/* 100vh sticky pin + 200vh of travel: the animation scrubs over 200vh. */
.hero-scroll {
  position: relative;
  height: 300vh;
}

@media (max-width: 720px) {
  /* Shorter scrub on mobile; content starts after ~2 swipes instead of ~3. */
  .hero-scroll { height: 200vh; }
}

.hero-stage {
  position: sticky;
  top: 0;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

.hero-stage__canvas,
.hero-stage__hdr,
.hero-stage__fallback {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

.hero-stage__fallback svg { width: 100%; height: 100%; }

/* Shape data only: intro-light.js reads its paths. */
.hero-stage__mark { display: none; }

/* As the hero forms, the light closes in to the frame's column (--clip, the
   gutter width, set per frame). */
.hero-stage__canvas,
.hero-stage__hdr { clip-path: inset(0 var(--clip, 0px)); }

/* On HDR displays the WebGPU layer presents the frame; the WebGL canvas still
   renders it. */
.hero-stage.is-hdr .hero-stage__canvas { visibility: hidden; }
.hero-stage__hdr { dynamic-range-limit: no-limit; }

.hero-stage.is-fallback .hero-stage__canvas { display: none; }

/* The hero the intro settles into: one column of eyebrow, mark and copy, in a
   box the width of the site frame and padded like a .section, so it reads as
   the page's first section and runs straight into the next one. */
.hero-stage__hero {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  width: min(1220px, 100%);
  margin: 0 auto;
  display: flex;
  align-items: center;
  padding: 0 clamp(24px, 4vw, 48px);
}

/* The frame's hairlines fade in as the hero forms (--frame, set per frame). */
.hero-stage__hero::before {
  content: '';
  position: absolute;
  inset: 0;
  border: 1px solid var(--ds-border-hairline);
  border-top: 0;
  opacity: var(--frame, 0);
  pointer-events: none;
}

/* Hidden until the mark is in place; intro-light.js reveals it, and offsets
   it (top) so the slot sits at the mark's centred height. */
.hero-stage__copy {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--ds-space-5);
  visibility: hidden;
}

.hero-stage__eyebrow {
  font-size: var(--ds-text-lead);
  color: var(--ds-text-secondary);
}

/* Only reserves the mark's place; intro-light.js sizes it to the mark and
   draws the mark into it. */
.hero-stage__slot {
  flex: 0 0 auto;
  width: clamp(96px, 13vw, 190px);
  aspect-ratio: 193.9 / 103;
}

.hero-stage__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--ds-space-4);
}

.hero-stage__body h1 {
  max-width: 16ch;
  font-size: clamp(38px, 3.4vw + 14px, 68px);
}

.hero-stage__body .lead { max-width: 44ch; }

/* The copy unfolds from behind the mark: --edge is the mark's top (eyebrow)
   or bottom (body) edge in the element's own coordinates, and the mask hides
   the part still behind it. */
.hero-stage__eyebrow,
.hero-stage__body { will-change: transform; }

.hero-stage__eyebrow {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(var(--edge, 999px) - 8px), transparent var(--edge, 999px));
  mask-image: linear-gradient(to bottom, #000 calc(var(--edge, 999px) - 8px), transparent var(--edge, 999px));
}

.hero-stage__body {
  -webkit-mask-image: linear-gradient(to bottom, transparent var(--edge, -999px), #000 calc(var(--edge, -999px) + 8px));
  mask-image: linear-gradient(to bottom, transparent var(--edge, -999px), #000 calc(var(--edge, -999px) + 8px));
}

@media (prefers-reduced-motion: reduce) {
  .hero-scroll { height: 100vh; }
  .hero-stage { position: static; }
}

.hero-intro {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-4);
  max-width: var(--ds-container-max);
  margin: 0 auto;
  align-items: flex-start;
  text-align: left;
  width: 100%;
}

.hero-intro h1 {
  margin: 0;
  text-wrap: balance;
  max-width: 20ch;
}

.hero-intro .lead {
  margin: 0;
  max-width: 60ch;
  text-align: left;
}

.hero-cta {
  display: flex;
  gap: var(--ds-space-3);
  margin: 0;
  flex-wrap: wrap;
  justify-content: flex-start;
}

/* ===== Project rows ===== */

.project-list { display: flex; flex-direction: column; width: 100%; }
.project-list li { border-top: 1px solid var(--ds-border-hairline); }
.project-list li:last-child { border-bottom: 1px solid var(--ds-border-hairline); }

.project-row {
  display: grid;
  grid-template-columns: 0.6fr 1.4fr;
  gap: var(--ds-space-6);
  padding: var(--ds-space-6) 0;
  align-items: start;
  transition: padding var(--dur-base) var(--ease-out);
}

.project-row:hover { padding-left: var(--ds-space-3); }
.project-row:hover h3 { color: var(--ds-text); }

.project-row__meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-top: 3px; /* sits on the h3's first line */
  font-size: var(--ds-text-small);
  color: var(--ds-text-tertiary);
}

.project-row__info {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-2);
  max-width: 60ch;
}

.project-row__info h3 {
  font-size: var(--ds-text-card);
  font-weight: 500;
  color: var(--ds-text-secondary);
  transition: color var(--dur-fast) var(--ease-out);
  margin: 0;
  letter-spacing: var(--ds-tracking-card);
}

.project-row__info p {
  font-size: var(--ds-text-body);
  color: var(--ds-text-tertiary);
  line-height: var(--ds-leading-body);
  letter-spacing: var(--ds-tracking-body);
  margin: 0;
}

/* One column: role and sector drop under the description instead of
   sitting above the title like a kicker. */
@media (max-width: 720px) {
  .project-row { grid-template-columns: 1fr; gap: var(--ds-space-2); }
  .project-row__meta { order: 1; flex-direction: row; flex-wrap: wrap; column-gap: var(--ds-space-3); padding-top: 0; }
}

/* ===== Eon featured ===== */

/* Lives in a standard .section frame; the inner split has no card chrome. */
.featured-grid {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
  width: 100%;
}

.featured-info {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-5);
  align-items: flex-start;
}

.featured-info h2 { max-width: 14ch; }
.featured-info .lead { max-width: 50ch; }

.tags,
.page__tags { display: flex; flex-wrap: wrap; gap: var(--ds-space-2); }

/* Sentence case on purpose: uppercase turned "iOS" into "IOS". */
.tags li,
.page__tags li {
  display: inline-flex;
  align-items: center;
  height: 28px;
  padding: 0 var(--ds-space-3);
  font-size: var(--ds-text-small);
  color: var(--ds-text-secondary);
  border: 1px solid var(--ds-border-soft);
  border-radius: var(--ds-radius-full);
}

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--ds-space-2);
  font-family: var(--ds-font-sans);
  font-size: var(--ds-text-body);
  font-weight: 500;
  letter-spacing: var(--ds-tracking-body);
  color: var(--ds-text);
  border-bottom: 1px solid var(--ds-border);
  padding-bottom: var(--ds-space-1);
  transition: color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), gap var(--dur-fast) var(--ease-out);
}

.link-arrow:hover { color: var(--ds-text); border-color: var(--ds-text); gap: var(--ds-space-3); }

.featured-visual {
  display: block;
  position: relative;
  border-radius: var(--ds-radius-lg);
  overflow: hidden;
  border: 1px solid var(--ds-border-hairline);
  background: var(--ds-surface);
  transition:
    transform var(--dur-base) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

.featured-visual:hover {
  transform: translateY(-2px);
  border-color: var(--ds-border);
}

.featured-visual__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

@media (max-width: 900px) {
  .featured-grid { grid-template-columns: 1fr; gap: var(--ds-space-8); }
}

/* ===== Contact ===== */

.contact-list { display: flex; flex-direction: column; border-top: 1px solid var(--ds-border-soft); width: 100%; }
.contact-list li { border-bottom: 1px solid var(--ds-border-soft); }

.contact-list a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--ds-space-6) 0;
  font-size: var(--ds-text-lead);
  font-weight: 500;
  color: var(--ds-text);
  transition: color var(--dur-fast) var(--ease-out), padding var(--dur-base) var(--ease-out);
}

.contact-list a:hover { color: var(--ds-text-secondary); padding-left: var(--ds-space-3); }

.contact-list-meta {
  font-size: var(--ds-text-small);
  font-weight: 400;
  color: var(--ds-text-tertiary);
}

/* ===== Footer ===== */

/* Same voice as .gate-footer: sentence case, small, quiet. The extra bottom
   padding keeps the last line clear of the floating toggle. */
.site-footer {
  padding: var(--ds-space-8) var(--ds-container-padding) calc(var(--ds-space-8) + 48px);
  border-top: 1px solid var(--ds-border-hairline);
  position: relative;
  z-index: 1;
}

.site-footer-inner {
  max-width: var(--ds-container-max);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-space-4);
  flex-wrap: wrap;
  font-size: var(--ds-text-small);
  color: var(--ds-text-tertiary);
}

.site-footer-cluster { display: flex; flex-wrap: wrap; gap: var(--ds-space-5); }
.site-footer-cluster a:hover { color: var(--ds-text); }

/* ===== Case study pages ===== */

.page {
  flex: 1;
  width: 100%;
  margin: 0 auto;
  padding: calc(var(--ds-nav-height) + var(--ds-space-8)) 0 var(--ds-space-8);
}

.page > .section {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-6);
  align-items: flex-start;
}

.page__back {
  display: inline-flex;
  align-items: center;
  gap: var(--ds-space-2);
  font-size: var(--ds-text-body);
  font-weight: 500;
  color: var(--ds-text-muted);
  transition: color var(--dur-fast) var(--ease-out);
  margin-bottom: var(--ds-space-4);
}

.page__back:hover { color: var(--ds-text); }

.page__title { max-width: 22ch; margin: 0; }

.page__lead {
  font-size: var(--ds-text-lead);
  line-height: var(--ds-leading-normal);
  color: var(--ds-text-secondary);
  max-width: 60ch;
  text-wrap: pretty;
  margin: 0;
}

.page__tags { margin: var(--ds-space-2) 0 0; }

/* Stands in for the write-up until there is one. */
.page__note {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--ds-space-4);
  width: 100%;
  margin-top: var(--ds-space-6);
  padding-top: var(--ds-space-8);
  border-top: 1px solid var(--ds-border-hairline);
}
.page__note p { max-width: 52ch; }

/* ===== Gate (landing) page ===== */

/* Short pages still put the footer at the bottom of the screen. */
.gate-body,
body:has(> main.page) {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.gate-brand {
  position: absolute;
  top: var(--ds-space-6);
  left: var(--ds-container-padding);
  z-index: 1;
  opacity: 0;
  animation: gate-brand-in 600ms 200ms var(--ease-out) forwards;
}

/* Taller than the viewport, so it top-aligns and the statement stays in view. */
.gate {
  flex: 1;
  display: flex;
  flex-direction: column;
  width: 100%;
  margin: 0 auto;
  padding: calc(var(--ds-nav-height) + var(--ds-space-8)) 0 var(--ds-space-8);
  text-align: left;
}

/* Statement on the left, role list on the right. */
.gate-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(40px, 8vw, 120px);
  align-items: start;
  width: 100%;
}

.exp-list {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 520px;
}

/* Each role is an accordion row that expands in place. */
.exp-row { border-top: 1px solid var(--ds-border-hairline); }
.exp-row:last-child { border-bottom: 1px solid var(--ds-border-hairline); }

.exp-row__head {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  column-gap: var(--ds-space-4);
  padding: var(--ds-space-4) 0;
  cursor: pointer;
  list-style: none;
}
.exp-row__head::-webkit-details-marker { display: none; }

.exp-row__title {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.exp-row__title strong {
  font-weight: 500;
  font-size: var(--ds-text-lead);
  letter-spacing: var(--ds-tracking-card);
  color: var(--ds-text);
}

.exp-row__role {
  font-size: var(--ds-text-small);
  color: var(--ds-text-secondary);
  transition: color var(--dur-fast) var(--ease-out);
}

.exp-row__years {
  font-family: var(--ds-font-mono);
  font-size: var(--ds-text-micro);
  letter-spacing: var(--ds-tracking-wide);
  color: var(--ds-text-tertiary);
  white-space: nowrap;
}

/* Disclosure indicator, the 3rd grid column of the header. */
.exp-row__head::after {
  content: "+";
  font-size: 18px;
  line-height: 1;
  color: var(--ds-text-tertiary);
  transition: color var(--dur-fast) var(--ease-out);
}
.exp-row[open] .exp-row__head::after { content: "−"; color: var(--ds-text); }
.exp-row__head:hover .exp-row__role,
.exp-row__head:hover::after { color: var(--ds-text); }

.exp-row__body {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-4);
  padding: 0 0 var(--ds-space-5);
  animation: exp-body-in var(--dur-base) var(--ease-out);
}

.exp-row__body p {
  margin: 0;
  font-size: var(--ds-text-small);
  line-height: var(--ds-leading-body);
  color: var(--ds-text-secondary);
}

/* Keep the See more button hugging its content. */
.exp-row__body > a:not(.tl-item) { align-self: flex-start; }

@keyframes exp-body-in {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: none; }
}

@media (max-width: 860px) {
  .gate-grid { grid-template-columns: 1fr; gap: var(--ds-space-8); }
  .exp-list { max-width: none; }
}

.gate-statement {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--ds-space-5);
  text-align: left;
  max-width: 64ch;
}

@media (min-width: 861px) {
  .gate-statement { position: sticky; top: calc(var(--ds-nav-height) + var(--ds-space-8)); }
}

.gate-statement h1 {
  margin: 0;
  max-width: 22ch;
}

.about {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-3);
  max-width: 56ch;
}
.about p {
  margin: 0;
  color: var(--ds-text-secondary);
  font-size: var(--ds-text-lead);
  line-height: var(--ds-leading-normal);
}

/* Staggered entrance; per-element delay set inline via --gate-delay. */
.gate-fade {
  opacity: 0;
  transform: translateY(10px);
  animation: gate-fade-in 720ms var(--gate-delay, 0ms) var(--ease-out) forwards;
}

@keyframes gate-fade-in {
  to { opacity: 1; transform: none; }
}

@keyframes gate-brand-in {
  to { opacity: 1; }
}

/* ===== Staggered grid reveal (driven by reveal.js) ===== */
/* Hidden pre-state applies only once reveal.js adds .reveal-ready to <html>,
   so content is never stuck hidden if the script fails to run. Per-item delay
   comes from --reveal-delay; the tiny rotate gives the reveal its swing. */
.reveal-ready [data-reveal] > * {
  opacity: 0;
  transform: translateY(12px) rotate(-2deg);
  transition:
    opacity 720ms var(--ease-out),
    transform 720ms var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

.reveal-ready [data-reveal].is-revealed > * {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .reveal-ready [data-reveal] > * {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* Extra bottom padding keeps the line clear of the floating toggle. */
.gate-footer {
  padding: var(--ds-space-6) var(--ds-container-padding) calc(var(--ds-space-6) + 48px);
  max-width: var(--ds-container-max);
  margin: 0 auto;
  width: 100%;
  font-size: var(--ds-text-small);
  color: var(--ds-text-tertiary);
  text-align: left;
}

.role-thumbs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--ds-space-3);
}

/* A thumb whose image fails to load removes itself; with none left, the
   row collapses instead of showing empty boxes. */
.role-thumbs:not(:has(.role-thumb)) { display: none; }

/* On a case study, a lone image gets the full row. */
.page .role-thumb:only-child { grid-column: 1 / -1; }

.role-thumb {
  display: block;
  aspect-ratio: 4 / 3;
  background: var(--ds-surface);
  border-radius: 6px;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
  transition: background var(--dur-fast) var(--ease-out);
}

.role-thumb:hover { background: var(--ds-surface-2); }

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

.role-highlights ul {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.role-highlights li {
  position: relative;
  padding-left: var(--ds-space-4);
  font-size: var(--ds-text-body);
  color: var(--ds-text-secondary);
  line-height: var(--ds-leading-body);
}

.role-highlights li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.65em;
  width: 8px;
  height: 1px;
  background: var(--ds-border);
}

/* ===== Lightbox ===== */
.lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.92);
  z-index: 200;
  display: none;
  align-items: center;
  justify-content: center;
}

.lightbox.is-open { display: flex; }
.lightbox [hidden] { display: none; }

.lightbox__img {
  max-width: min(92vw, 1400px);
  max-height: 85vh;
  object-fit: contain;
  display: block;
}

.lightbox__close,
.lightbox__prev,
.lightbox__next {
  position: absolute;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.16);
  color: var(--ds-text);
  width: 44px;
  height: 44px;
  border-radius: var(--ds-radius-full);
  cursor: pointer;
  font-size: 22px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background var(--dur-fast) var(--ease-out);
}

.lightbox__close:hover,
.lightbox__prev:hover,
.lightbox__next:hover { background: rgba(255, 255, 255, 0.16); }

.lightbox__close { top: 24px; right: 24px; }
.lightbox__prev { left: 24px; top: 50%; transform: translateY(-50%); }
.lightbox__next { right: 24px; top: 50%; transform: translateY(-50%); }

.lightbox__counter {
  position: absolute;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--ds-font-mono);
  font-size: var(--ds-text-small);
  color: var(--ds-text-tertiary);
  letter-spacing: var(--ds-tracking-wide);
}

.earlier-timeline {
  display: flex;
  flex-direction: column;
  padding-left: var(--ds-space-5);
  border-left: 1px solid var(--ds-border-soft);
}

.tl-item {
  display: flex;
  align-items: baseline;
  gap: var(--ds-space-3);
  padding: var(--ds-space-2) 0;
  text-decoration: none;
  position: relative;
}

.tl-item::before {
  content: '';
  position: absolute;
  left: calc(-1 * var(--ds-space-5) - 3px);
  top: 50%;
  transform: translateY(-50%);
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--ds-border);
  transition: background var(--dur-fast) var(--ease-out);
}

.tl-item:hover::before { background: var(--ds-text); }

.tl-name {
  font-size: var(--ds-text-body);
  color: var(--ds-text);
  border-bottom: 1px solid var(--ds-border-hairline);
  transition: border-color var(--dur-fast) var(--ease-out);
}

.tl-item:hover .tl-name { border-color: var(--ds-text); }

.tl-tag {
  font-size: var(--ds-text-small);
  color: var(--ds-text-tertiary);
}

@media (prefers-reduced-motion: reduce) {
  .gate-fade { animation: none; opacity: 1; transform: none; }
  .gate-brand { animation: none; opacity: 1; }
}

/* ===== View toggle ===== */
/* Four destinations, each its own URL: AI view, gate, full portfolio, job match. */
.view-toggle {
  position: fixed;
  left: 50%;
  bottom: var(--ds-space-6);
  transform: translateX(-50%);
  z-index: 20;
  padding: 5px;
  overflow: hidden;
  border-radius: var(--ds-radius-full);
  background: rgba(20, 20, 20, 0.85);
  border: 1px solid var(--ds-border-soft);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  opacity: 0;
  animation: gate-brand-in 600ms 700ms var(--ease-out) forwards;
}

/* The options keep their size and spacing at all times. Collapsing is the
   pill narrowing over them and the track sliding to centre the current page,
   so nothing ever reflows against its neighbours. */
.view-toggle__track {
  display: flex;
  gap: 2px;
  width: max-content;
}

.view-toggle__btn {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  white-space: nowrap;
  height: 32px;
  padding: 0 var(--ds-space-4);
  border-radius: var(--ds-radius-full);
  color: var(--ds-text-tertiary);
  font: 500 var(--ds-text-small) / 1 var(--ds-font-sans);
  text-decoration: none;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}
.view-toggle__btn:hover { color: var(--ds-text); }
.view-toggle__btn:active { transform: scale(0.96); }
.view-toggle__btn[aria-current="page"] {
  background: var(--ds-text);
  color: var(--ds-bg);
}
/* Inset, because the pill clips anything drawn outside it. */
.view-toggle__btn:focus-visible { outline-offset: -2px; }

/* Phones: the full labels need ~520px. Short labels show instead, and the
   long ones stay in the accessibility tree as the links' names. */
.view-toggle__short { display: none; }
@media (max-width: 560px) {
  .view-toggle {
    max-width: calc(100vw - 2 * var(--ds-space-3));
    overflow-x: auto;
    scrollbar-width: none;
  }
  .view-toggle::-webkit-scrollbar { display: none; }
  .view-toggle__btn { padding: 0 var(--ds-space-3); }
  .view-toggle__long {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .view-toggle__short { display: inline; }
}

@media (prefers-reduced-motion: reduce) {
  .view-toggle { animation: none; opacity: 1; }
}

/* ===== AI view: the site as plain text ===== */
.ai {
  flex: 1;
  width: 100%;
  margin: 0 auto;
  padding: calc(var(--ds-nav-height) + var(--ds-space-8)) 0 var(--ds-space-8);
}

.ai-head,
.ai-doc { max-width: 72ch; }

.ai-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-space-4);
  flex-wrap: wrap;
  padding-bottom: var(--ds-space-6);
  margin-bottom: var(--ds-space-8);
  border-bottom: 1px solid var(--ds-border-hairline);
}
.ai-note {
  margin: 0;
  color: var(--ds-text-tertiary);
  font-size: var(--ds-text-small);
}
.ai-note a { color: var(--ds-text-secondary); text-decoration: underline; text-underline-offset: 3px; }
.ai-note a:hover { color: var(--ds-text); }

.ai-doc {
  font-family: var(--ds-font-mono);
  font-size: var(--ds-text-small);
  line-height: 1.7;
  color: var(--ds-text-secondary);
}
.ai-doc h1, .ai-doc h2, .ai-doc h3 {
  font-family: var(--ds-font-sans);
  color: var(--ds-text);
  margin: 0;
}
.ai-doc h1 { font-size: var(--ds-text-section); letter-spacing: var(--ds-tracking-section); line-height: var(--ds-leading-snug); margin-bottom: var(--ds-space-4); }
.ai-doc h2 { font-size: var(--ds-text-card); letter-spacing: var(--ds-tracking-card); margin-top: var(--ds-space-12); margin-bottom: var(--ds-space-3); }
.ai-doc h3 { font-size: var(--ds-text-lead); margin-top: var(--ds-space-8); margin-bottom: var(--ds-space-2); }
.ai-doc p { margin: 0 0 var(--ds-space-3); }
.ai-doc ul, .ai-doc ol { margin: 0 0 var(--ds-space-3); padding-left: 1.4em; }
.ai-doc li { margin: 0 0 var(--ds-space-1); }
.ai-doc a { color: var(--ds-text); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--ds-border); word-break: break-word; }
.ai-doc a:hover { text-decoration-color: var(--ds-text); }

/* ===== Page switching ===== */
/* Cross-document view transition. Layouts differ completely between pages, so
   instead of a cross-fade (reads as ghosting) the old page fades to the
   background, then the new one fades in. Only the toggle stays put. */
@view-transition { navigation: auto; }
.view-toggle { view-transition-name: view-toggle; }
::view-transition-group(view-toggle) { animation-duration: 0s; }
::view-transition-old(root) {
  animation: vt-out 160ms var(--ease-out) both;
}
::view-transition-new(root) {
  animation: vt-in 240ms 120ms var(--ease-out) both;
}
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; } }

/* Arriving via the toggle: no entrance choreography, content is already at rest. */
.from-toggle { scroll-behavior: auto; }
.from-toggle .gate-fade,
.from-toggle .gate-brand { animation: none; opacity: 1; transform: none; }
.from-toggle .view-toggle { animation: none; opacity: 1; }
.from-toggle.reveal-ready [data-reveal] > * { opacity: 1; transform: none; transition: none; }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; }
}

/* ===== Job match ===== */
.match > .section {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-12);
}

.match {
  flex: 1;
  width: 100%;
  margin: 0 auto;
  padding: calc(var(--ds-nav-height) + var(--ds-space-8)) 0 var(--ds-space-8);
}

.match-form,
.match-result { max-width: 72ch; }

.match-form {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-5);
}
.match-form h1 { margin: 0; max-width: 20ch; }
.match-form .lead { margin: 0; color: var(--ds-text-secondary); }

.match-input {
  width: 100%;
  min-height: 220px;
  padding: var(--ds-space-4);
  resize: vertical;
  border-radius: var(--ds-radius-md);
  border: 1px solid var(--ds-border-soft);
  background: var(--ds-surface);
  color: var(--ds-text);
  font-family: var(--ds-font-sans);
  font-size: var(--ds-text-body);
  line-height: var(--ds-leading-normal);
  transition: border-color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out);
}
.match-input::placeholder { color: var(--ds-text-tertiary); }
.match-input:hover { border-color: var(--ds-border); }
.match-input:focus { outline: none; border-color: var(--ds-text-secondary); background: var(--ds-surface-2); }

.match-actions {
  display: flex;
  align-items: center;
  gap: var(--ds-space-4);
  flex-wrap: wrap;
}
.match-hint { color: var(--ds-text-tertiary); font-size: var(--ds-text-small); }
.match-form button[disabled] { opacity: 0.6; cursor: progress; }

.match-result {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-4);
  padding-top: var(--ds-space-10);
  border-top: 1px solid var(--ds-border-hairline);
  scroll-margin-top: var(--ds-space-8);
}
.match-result[hidden] { display: none; }
.match-result h2 { margin: 0; }
.match-result h3 {
  margin: var(--ds-space-4) 0 0;
  font-size: var(--ds-text-lead);
  color: var(--ds-text);
}
.match-wink { margin: 0; color: var(--ds-text-tertiary); }

.match-score {
  display: flex;
  align-items: baseline;
  gap: var(--ds-space-2);
  color: var(--ds-glow-warm);
}
.match-score__num {
  font-size: clamp(64px, 12vw, 112px);
  font-weight: 600;
  letter-spacing: var(--ds-tracking-hero);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.match-score__label { font-size: var(--ds-text-lead); color: var(--ds-text-secondary); }

.match-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.match-list li {
  display: grid;
  grid-template-columns: minmax(140px, 1fr) 2fr;
  gap: var(--ds-space-4);
  padding: var(--ds-space-3) 0;
  border-bottom: 1px solid var(--ds-border-hairline);
}
.match-list strong { font-weight: 500; color: var(--ds-text); }
.match-list span { color: var(--ds-text-secondary); }
@media (max-width: 560px) {
  .match-list li { grid-template-columns: 1fr; gap: var(--ds-space-1); }
}

.match-result.is-in > * { animation: gate-fade-in 520ms var(--ease-out) both; }
.match-result.is-in .match-list li { animation: gate-fade-in 520ms calc(120ms + var(--i, 0) * 60ms) var(--ease-out) both; }
.match-list li { opacity: 0; transform: translateY(10px); }
.match-result.is-in .match-list li { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .match-result.is-in > *, .match-result.is-in .match-list li { animation: none; }
  .match-list li { opacity: 1; transform: none; }
}

/* Job match pill: a 1px border in the glow colours, the warm core travelling
   around it. No halo, the border is the whole effect. */
@property --orbit { syntax: '<angle>'; inherits: false; initial-value: 0deg; }

.view-toggle__btn--match { position: relative; isolation: isolate; }
.view-toggle__btn--match::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1.5px;
  background: conic-gradient(from var(--orbit), var(--ds-glow-cool-0) 0 40%, var(--ds-glow-cool) 62%, var(--ds-glow-white) 74%, var(--ds-glow-warm) 84%, var(--ds-glow-cool-0) 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  animation: orbit 2.6s linear infinite;
  pointer-events: none;
  z-index: -1;
}
.view-toggle__btn--match[aria-current="page"]::before { display: none; }

@keyframes orbit { to { --orbit: 360deg; } }

@media (prefers-reduced-motion: reduce) {
  .view-toggle__btn--match::before { animation: none; background: var(--ds-glow-warm); }
}

/* ===== Toggle: collapsed to the current page, expands on hover ===== */
/* Only two things move: the pill's width and the track's offset. The edge
   vignette is an overlay that fades out over the same stretch, so the cut-off
   neighbours dissolve as the box opens rather than snapping to full strength. */
@media (hover: hover) and (pointer: fine) {
  .view-toggle.is-ready {
    /* Hover has to be held this long before the pill opens, so a cursor
       crossing the strip leaves it alone. Closing waits for nothing. */
    --intent: 260ms;
    --ease-soft: cubic-bezier(0.32, 0.72, 0, 1);
    width: var(--w-shut);
    transition: width 420ms var(--ease-soft);
  }
  .view-toggle.is-ready .view-toggle__track {
    transform: translateX(var(--shift, 0px));
    transition: transform 420ms var(--ease-soft);
  }
  .view-toggle.is-ready::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    border-radius: inherit;
    background:
      linear-gradient(to right, rgba(20, 20, 20, 0.94), rgba(20, 20, 20, 0) var(--fade-l, 0px)),
      linear-gradient(to left, rgba(20, 20, 20, 0.94), rgba(20, 20, 20, 0) var(--fade-r, 0px));
    transition: opacity 320ms var(--ease-soft);
  }

  .view-toggle.is-ready:hover,
  .view-toggle.is-ready:focus-within {
    width: var(--w-open);
    transition: width 540ms var(--ease-soft) var(--intent);
  }
  .view-toggle.is-ready:hover .view-toggle__track,
  .view-toggle.is-ready:focus-within .view-toggle__track {
    transform: translateX(0);
    transition: transform 540ms var(--ease-soft) var(--intent);
  }
  .view-toggle.is-ready:hover::after,
  .view-toggle.is-ready:focus-within::after {
    opacity: 0;
    transition: opacity 500ms var(--ease-soft) var(--intent);
  }

  /* The ring is the cue for the one destination people would not guess at,
     so it waits until the pill has finished opening. */
  .view-toggle__btn--match::before { transition: opacity 300ms var(--ease-soft); }
  .view-toggle.is-ready:not(:hover):not(:focus-within) .view-toggle__btn--match::before { opacity: 0; }
  .view-toggle.is-ready:hover .view-toggle__btn--match::before { transition-delay: calc(var(--intent) + 320ms); }
}

/* No animation while widths are being measured or on first paint. */
.view-toggle.is-measuring,
.view-toggle.is-measuring::after,
.view-toggle.is-measuring .view-toggle__track,
.view-toggle.is-measuring .view-toggle__btn { transition: none !important; }

@media (prefers-reduced-motion: reduce) {
  .view-toggle.is-ready,
  .view-toggle.is-ready::after,
  .view-toggle.is-ready .view-toggle__track,
  .view-toggle.is-ready .view-toggle__btn { transition: none; }
}
