/* Timothy Cai portfolio, hardware edition.
   One dark theme for the whole site (the plume needs a night sky).
   Accent: plume orange, used sparingly. Square corners everywhere; uppercase display headings and
   small mono uppercase labels for metadata (shared with the light edition). */
@font-face { font-family: "Geist"; src: url("../fonts/Geist-Variable.woff2") format("woff2"); font-weight: 100 900; font-display: swap; }
@font-face { font-family: "Geist Mono"; src: url("../fonts/GeistMono-Variable.woff2") format("woff2"); font-weight: 100 900; font-display: swap; }

:root {
  --k: 1;   /* tracking scale: display type tightens less as it gets smaller (see media queries below) */
  color-scheme: dark;
  --bg: #0a0b0d;
  --bg-2: #121316;
  --bg-3: #191b1f;
  --line: #24272c;
  --line-2: #33373e;
  --text: #ededeb;
  --text-2: #a7aab1;
  --text-3: #767a82;
  --text-3s: #8e939b;   /* small text (under ~14px): one step brighter so it stays readable */
  --accent: #ea8c5e;
  --accent-ink: #1a0f0a;
  --r: 0px;
  --sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --wide: 1240px;
  --gutter: clamp(16px, 4vw, 40px);
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  /* z scale: hero darkness 1, plume 2, hero copy 3, nav 40, lightbox 60 */
}

*, *::before, *::after { box-sizing: border-box; border-radius: 0 !important; }   /* square, everywhere */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
/* smooth wheel scrolling (Lenis, see site.js): it drives the scroll itself, so the CSS smoothing must step aside */
html.lenis, html.lenis body { height: auto; }
html.lenis { scroll-behavior: auto !important; }
.lenis:not(.lenis-autoToggle).lenis-stopped { overflow: clip; }
body {
  margin: 0; background: var(--bg); color: var(--text); transition: background-color 1.2s ease;
  font-family: var(--sans); font-size: 1.0625rem; line-height: 1.6;
  font-feature-settings: "ss01", "cv11"; -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img, video { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
p { margin: 0; }
h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: calc(var(--k) * -0.03em); line-height: 1.05; text-wrap: balance; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.wrap { max-width: var(--wide); margin-inline: auto; padding-inline: var(--gutter); }
.mono { font-family: var(--mono); font-feature-settings: "zero"; letter-spacing: 0; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
svg.i { width: 1.1em; height: 1.1em; flex: none; }

/* ---------- nav ---------- */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 40; height: 56px;
  background: rgb(10 11 13 / 0.72); -webkit-backdrop-filter: saturate(160%) blur(18px); backdrop-filter: saturate(160%) blur(18px);
}
/* where content meets the floating nav: a short fade with a little blur, instead of a hard 1px line */
.nav::after {
  content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 22px; pointer-events: none; opacity: 0; transition: opacity .35s;
  background: linear-gradient(rgb(10 11 13 / .55), rgb(10 11 13 / 0));
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  -webkit-mask-image: linear-gradient(#000, transparent); mask-image: linear-gradient(#000, transparent);
}
.nav.edge::after { opacity: 1; }
.nav .wrap { height: 100%; display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.brand { text-decoration: none; font-weight: 600; letter-spacing: .02em; text-transform: uppercase; font-size: .875rem; display: inline-flex; align-items: center; gap: .65rem; white-space: nowrap; }
.brand-mark { width: 26px; height: 26px; border-radius: 7px; display: grid; place-items: center; background: var(--text); color: var(--bg); font-size: .78rem; font-weight: 700; letter-spacing: -0.04em; }
.nav-links { display: flex; align-items: center; gap: clamp(.9rem, 2.2vw, 1.9rem); font-size: .8125rem; }
.nav-sec a { font-family: var(--mono); text-transform: uppercase; letter-spacing: .06em; font-size: .75rem; }
.nav-links a { text-decoration: none; color: var(--text-2); transition: color .2s; white-space: nowrap; }
.nav-links a[aria-current] { color: var(--text); }
.pill {
  display: inline-flex; align-items: center; gap: .5rem; height: 42px; padding: 0 1.15rem;
  font-size: .9375rem; font-weight: 500; text-decoration: none; white-space: nowrap; border: 1px solid transparent;
  transition: background .25s var(--ease), color .25s var(--ease), border-color .25s, transform .15s;
}
.pill:active { transform: translateY(1px); }
.pill.solid { background: var(--text); color: var(--bg); }
.pill.line { border-color: var(--text-2); color: var(--text); }
.pill.small { height: 32px; padding: 0 .85rem; font-size: .8125rem; }
/* the hero's main action: jump straight to the projects */
.pill.skip {
  height: 56px; padding: 0 1.6rem 0 1.75rem; gap: .6rem; font-size: 1.0625rem; font-weight: 600; letter-spacing: 0;
  background: var(--accent); color: var(--accent-ink);
}
.pill.skip .i { width: 1.15em; height: 1.15em; transition: transform .35s var(--ease); }
.hero-sub .cta { align-items: center; }
.nav .pill.small { color: var(--bg); }
/* section links + the bar that slides under the section you are in */
.nav-sec { position: relative; display: flex; align-items: center; gap: clamp(.9rem, 2.2vw, 1.8rem); }
.nav-sec a { padding-block: .55rem; }
.nav-sec a.on { color: var(--text); }
.nav-ind {
  position: absolute; left: 0; bottom: 1px; width: 100px; height: 2px; border-radius: 2px; background: var(--accent);
  transform-origin: 0 50%; transform: translateX(0) scaleX(0); opacity: 0; pointer-events: none;
  transition: transform .5s var(--ease), opacity .3s;
}
@media (max-width: 720px) {
  .brand-name { display: none; }
  .nav .wrap { gap: .75rem; }
  .nav-links { flex: 1; min-width: 0; justify-content: flex-end; gap: .7rem; font-size: .8125rem; }
  /* every section stays reachable: the links scroll sideways, fading out at the right edge */
  .nav-sec {
    flex: 0 1 auto; min-width: 0; gap: 1.05rem; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
    padding-right: 18px; -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 22px), transparent); mask-image: linear-gradient(90deg, #000 calc(100% - 22px), transparent);
  }
  .nav-sec::-webkit-scrollbar { display: none; }
}

/* ---------- hero ---------- */
.hero {
  position: relative; min-height: 100vh; min-height: 100dvh; overflow: hidden; isolation: isolate;
  /* --eh is the layout unit the copy is placed with (the plume radius is 0.2185 of it);
     --ih/--ew are the render's own box, sized so its nozzle matches that radius */
  --p: 0; --eh: min(33vh, 21vw); --ih: calc(var(--eh) * 0.5813); --ew: calc(var(--ih) * 3.8794);
  --ax: 44vw; --ay: 54%;                 /* where the nozzle exit sits */
  background: radial-gradient(70% 55% at 72% 54%, #15100e 0%, var(--bg) 65%);
}
.hero-engine {
  position: absolute; z-index: 0; height: var(--ih); width: var(--ew); max-width: none;
  left: calc(var(--ax) - var(--ew) * 0.997); top: calc(var(--ay) - var(--ih) * 0.5017);
  user-select: none; -webkit-user-drag: none;
}
/* flame light on the engine: an orange wash masked to the render's own silhouette, strongest at the
   nozzle exit; plume.js drives its opacity with the flame (ignition, flicker, throttle) */
.hero-glow {
  position: absolute; z-index: 0; pointer-events: none; height: var(--ih); width: var(--ew);
  left: calc(var(--ax) - var(--ew) * 0.997); top: calc(var(--ay) - var(--ih) * 0.5017);
  -webkit-mask: url("../hero/goblet-hero-side.webp") center / 100% 100% no-repeat; mask: url("../hero/goblet-hero-side.webp") center / 100% 100% no-repeat;
  background:
    radial-gradient(ellipse 9% 62% at 100% 50%, rgb(255 168 96 / .9), rgb(255 130 60 / .35) 45%, transparent 100%),
    radial-gradient(ellipse 30% 120% at 100% 50%, rgb(255 120 55 / .3), transparent 70%);
  mix-blend-mode: screen; opacity: 0;
}
.hero.no-webgl .hero-glow { opacity: .5; }
canvas.plume { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 2; mix-blend-mode: screen; pointer-events: none; }
.hero.no-webgl canvas.plume { display: none; }
.hero.no-webgl::after {
  content: ""; position: absolute; z-index: 2; pointer-events: none; mix-blend-mode: screen;
  left: var(--ax); top: calc(var(--ay) - var(--eh) * 0.3); width: 56vw; height: calc(var(--eh) * 0.6);
  background: radial-gradient(60% 50% at 0% 50%, rgb(255 190 130 / .9), rgb(234 120 70 / .45) 35%, transparent 75%);
}
.hero-copy { position: absolute; z-index: 3; left: calc(var(--ax) + 1.5vw); right: var(--gutter); top: 0; bottom: 0; pointer-events: none; }
.hero-copy > * { pointer-events: auto; }
.hero h1 {
  position: absolute; left: 0; bottom: calc(100% - var(--ay) + var(--eh) * 0.12);
  font-size: clamp(3rem, 7.2vw, 7.6rem); font-weight: 700; text-transform: uppercase; letter-spacing: calc(var(--k) * -0.045em); line-height: .9; padding-bottom: .04em;
  white-space: nowrap; text-shadow: 0 2px 30px rgb(10 11 13 / .5);
  transform: translateY(calc(var(--p) * -48px)); opacity: calc(1.15 - var(--p) * 1.15);
}
.hero-sub {
  position: absolute; left: 0; top: calc(var(--ay) + var(--eh) * 0.62); max-width: 34ch;
  display: grid; gap: 1.4rem; transform: translateY(calc(var(--p) * -24px)); opacity: calc(1.2 - var(--p) * 1.3);
}
.hero-sub p { color: var(--text-2); font-size: clamp(1.02rem, 1.25vw, 1.2rem); line-height: 1.5; }
.hero-sub p b { color: var(--text); font-weight: 500; }
.cta { display: flex; gap: .75rem; flex-wrap: wrap; }
.callout {
  position: absolute; z-index: 3; text-decoration: none;
  left: max(var(--gutter), calc(var(--ax) - var(--ew) * 0.42)); top: calc(var(--ay) - var(--ih) * 0.5017 - 4.6rem);
  display: grid; gap: .15rem; font-size: .75rem; color: var(--text-2); font-family: var(--mono); text-transform: uppercase; letter-spacing: .06em;
  padding-left: .8rem; border-left: 2px solid var(--accent);
  transition: color .2s, border-color .2s; opacity: calc(1.2 - var(--p) * 1.3);
}
.callout b { color: var(--text); font-family: var(--sans); text-transform: none; letter-spacing: -0.01em; font-weight: 500; font-size: 1rem; display: inline-flex; align-items: center; gap: .3rem; }
.callout::after { content: ""; position: absolute; left: -2px; top: 100%; height: 2.6rem; border-left: 1px dashed var(--line-2); }
/* telemetry readout: the plume.js state machine writes into it */
.telemetry {
  position: absolute; z-index: 3; left: var(--gutter); bottom: 1.5rem; margin: 0;
  display: flex; align-items: center; gap: .6rem; font-size: .72rem; letter-spacing: .08em; text-transform: uppercase; color: var(--text-3s);
}
.telemetry.steady [data-tl-state], .telemetry.steady .tl-sep { display: none; }   /* running steady: just the throttle */
.telemetry .dot { flex: none; width: 6px; height: 6px; margin-right: .15rem; background: var(--accent); box-shadow: 0 0 6px rgb(234 140 94 / .55); }
.telemetry b { color: var(--text-2); font-weight: 500; font-variant-numeric: tabular-nums; display: inline-block; min-width: 4ch; }

/* ignition sequence. html.ign-pre is set before first paint (motion allowed, landing at the top):
   the page waits in the dark with only the engine dimly lit, and plume.js adds .ign-lit at main-stage ignition */
.hero-dark {
  position: absolute; inset: 0; z-index: 1; pointer-events: none; opacity: 0;
  background: radial-gradient(calc(var(--ew) * 0.62) calc(var(--ih) * 1.9) at calc(var(--ax) - var(--ew) * 0.48) calc(var(--ay) - var(--ih) * 0.35),
    rgb(0 0 0 / .3), rgb(0 0 0 / .78) 55%, #000 100%);
}
html.ign-pre:not(.ign-lit) body { background-color: #000; }
html.ign-pre .hero-dark { opacity: 1; }
html.ign-pre:not(.ign-lit) :is(.nav, .hero h1, .hero-sub, .callout, .telemetry, main > section:not(.hero), .contact) { opacity: 0; }
html.ign-lit .hero-dark { opacity: 0; transition: opacity 1.6s var(--ease); }
html.ign-lit :is(.nav, .telemetry, main > section:not(.hero), .contact) { transition: opacity 1.2s ease .35s; }
/* the hero's ignition plays for everyone, including with reduced motion (a deliberate choice) */
html.ign-pre.ign-lit :is(.hero h1, .hero-sub, .callout) { animation: rise 1.1s var(--ease) both; }
html.ign-pre.ign-lit .hero h1 { animation-delay: .2s; } html.ign-pre.ign-lit .hero-sub { animation-delay: .4s; } html.ign-pre.ign-lit .callout { animation-delay: .55s; }
.hero-engine { animation: fadein 1.6s ease both; }
@keyframes rise { from { opacity: 0; translate: 0 18px; } to { translate: 0 0; } }
@keyframes fadein { from { opacity: 0; } }
@media (max-width: 760px) {
  .hero { --eh: 36vw; --ax: 58vw; --ay: 50%; }
  .hero-copy { left: var(--gutter); }
  .hero h1 { font-size: clamp(2.8rem, 15vw, 4.2rem); bottom: calc(100% - var(--ay) + var(--eh) * 0.9); white-space: normal; }
  .hero-sub { top: calc(var(--ay) + var(--eh) * 0.85); max-width: none; }
  .callout { display: none; }
}

/* ---------- sections ---------- */
section { position: relative; }
.sec { padding-block: clamp(5rem, 11vw, 9rem); }
.sec + .sec { border-top: 1px solid var(--line); }
.h2 { font-size: clamp(2.4rem, 5.6vw, 4.8rem); font-weight: 700; text-transform: uppercase; letter-spacing: calc(var(--k) * -0.04em); line-height: .92; }
.lead { color: var(--text-2); font-size: 1.125rem; max-width: 60ch; margin-top: 1.1rem; }
.eyebrow { font-family: var(--mono); font-size: .75rem; text-transform: uppercase; letter-spacing: .08em; color: var(--accent); margin-bottom: 1rem; display: block; }
.reveal { opacity: 0; translate: 0 10px; transition: opacity .45s var(--ease), translate .45s var(--ease); }
.reveal.now { transition: none; }
.reveal.in { opacity: 1; translate: 0 0; }
@media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; translate: none; transition: none; } }

/* about: statement beside the portrait, then the fireball full width as the section's centrepiece */
.about-grid { display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); column-gap: clamp(2rem, 5vw, 5rem); row-gap: 16px; align-items: end; }
.statement { font-size: clamp(1.6rem, 2.9vw, 2.55rem); line-height: 1.22; letter-spacing: calc(var(--k) * -0.025em); font-weight: 500; margin-top: 1.6rem; }
.statement span { color: var(--text-3); }
.about-actions { display: flex; gap: .75rem; margin-top: 2.2rem; flex-wrap: wrap; }
.about-grid .ph { margin: 0; border-radius: var(--r); overflow: hidden; background: var(--bg-2); }
.about-grid .ph img { width: 100%; height: 100%; object-fit: cover; display: block; }
.about-portrait { aspect-ratio: 4 / 5; }
.about-fire { grid-column: 1 / -1; aspect-ratio: 2 / 1; }
.about-fire img { object-position: 52% 45%; }
@media (max-width: 900px) {
  .about-grid { grid-template-columns: 1fr; }
  .about-portrait { aspect-ratio: 4 / 3.4; max-height: none; }
  .about-portrait img { object-position: 50% 30%; }
  .about-grid { row-gap: 2rem; }
  .about-fire { aspect-ratio: 16 / 10; margin-top: -1rem; }
}

/* experience: horizontal rail */
.rail-head { display: flex; justify-content: space-between; align-items: end; gap: 1rem; }
.rail-lead { margin-top: 1rem; color: var(--text-2); font-size: clamp(1.05rem, 1.5vw, 1.25rem); max-width: 46ch; line-height: 1.45; }
.rail-btns { display: flex; gap: .5rem; }
@media (max-width: 720px) { .rail-btns { display: none; } }
.icon-btn { width: 44px; height: 44px; border-radius: 999px; display: grid; place-items: center; border: 1px solid var(--line-2); background: transparent; color: var(--text); cursor: pointer; transition: background .2s, border-color .2s, opacity .2s; }
.icon-btn[disabled] { opacity: .35; cursor: default; }
.rail {
  display: grid; grid-auto-flow: column; grid-auto-columns: min(460px, 84vw); gap: 20px;
  overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: var(--gutter);
  padding: 2.4rem var(--gutter) 1rem; margin: .4rem 0 0; list-style: none; scrollbar-width: none; overscroll-behavior-x: contain;
}
.rail::-webkit-scrollbar { display: none; }
/* with a mouse the cards can be grabbed and thrown (site.js) */
@media (hover: hover) and (pointer: fine) { .rail { cursor: grab; } }
.rail.dragging { cursor: grabbing; user-select: none; }
.rail img { -webkit-user-drag: none; }
.rail-outer { max-width: calc(var(--wide) + (100vw - var(--wide)) / 2); margin-left: auto; }
@media (max-width: 1240px) { .rail-outer { max-width: none; } }
/* scrubber under the rail: drag it, click anywhere on it, or use the arrow keys */
.rail-bar {
  position: relative; height: 28px; margin: .6rem var(--gutter) 0; cursor: pointer; touch-action: none;
  max-width: calc(var(--wide) - var(--gutter) * 2);
}
.rail-bar::before { content: ""; position: absolute; inset: 13px 0 auto; height: 2px; border-radius: 2px; background: var(--line); }
.rail-thumb {
  position: absolute; top: 11px; left: 0; height: 6px; border-radius: 6px; background: var(--text-3);
  transition: background .2s, height .2s var(--ease), top .2s var(--ease);
}
.rail-bar.drag .rail-thumb, .rail-bar:focus-visible .rail-thumb { background: var(--text); top: 10px; height: 8px; }
.rail-bar.drag { cursor: grabbing; }
.rail-bar:focus-visible { outline-offset: 2px; }
/* the timeline: one continuous line through every role, a node and dates for each */
.tl { scroll-snap-align: start; display: grid; grid-template-rows: auto 1fr; gap: 1.4rem; }
.tl-head { position: relative; padding-top: 4.6rem; }
.tl-head::before {
  content: ""; position: absolute; left: 0; right: -20px; top: calc(4.6rem + 6px); height: 2px; background: var(--line-2);
}
.tl:first-child .tl-head::before { left: 5px; }
/* a role that hasn't started yet: dashed line, hollow node */
.tl.future .tl-head::before { background: repeating-linear-gradient(90deg, var(--line-2) 0 6px, transparent 6px 11px); }
.tl.future .tl-dot { background: var(--bg); box-shadow: none; }
.tl:last-child .tl-head::before { right: 0; background: linear-gradient(90deg, var(--line-2) 30%, transparent); }
.tl-year {
  position: absolute; top: 0; left: -.04em; font-size: clamp(2.6rem, 4.4vw, 3.6rem); font-weight: 700; letter-spacing: calc(var(--k) * -0.04em);
  line-height: 1; color: var(--text); font-variant-numeric: tabular-nums;
}
.tl-dot {
  position: relative; z-index: 1; display: block; width: 13px; height: 13px;
  background: var(--bg); border: 2px solid var(--text-3); transition: border-color .3s, background .3s;
}
.tl.now .tl-dot { background: var(--accent); border-color: var(--accent); box-shadow: 0 0 0 5px rgb(234 140 94 / .16); }
.tl-date { margin-top: 1rem; display: flex; flex-wrap: wrap; gap: .3rem .7rem; align-items: baseline; font-family: var(--mono); font-size: .78rem; text-transform: uppercase; letter-spacing: .05em; color: var(--text); }
.tl-date span { color: var(--text-3s); font-size: .76rem; }
.tl.now .tl-date time { color: var(--accent); }
.tl.now.future .tl-dot { background: var(--bg); }
.job { background: var(--bg-2); border-radius: var(--r); overflow: hidden; display: flex; flex-direction: column; border: 1px solid var(--line); }
.job-img { aspect-ratio: 16 / 10; overflow: hidden; background: var(--bg-3); }
.job-img img { width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease); }
.job-body { padding: 1.5rem 1.6rem 1.8rem; display: grid; gap: .9rem; align-content: start; }
.job-top { display: flex; align-items: center; gap: 1rem; }
.job-logo { flex: none; width: 52px; height: 52px; background: #f3f3f1; padding: 6px; object-fit: contain; }
.job h3 { font-size: clamp(1.5rem, 2.1vw, 1.85rem); letter-spacing: -0.024em; line-height: 1.08; }
.job h3 span { display: block; color: var(--text-2); font-weight: 400; font-size: 1rem; margin-top: .3rem; letter-spacing: 0; }
.job p { color: var(--text-2); font-size: 1rem; line-height: 1.6; }

/* goblet tour: pinned scene; a camera moves between parts as you scroll (assets/js/goblet.js) */
.figs { display: grid; grid-template-columns: repeat(2, auto); justify-content: start; gap: .2rem 2.6rem; margin-top: .2rem; }
.fig b { display: block; font-size: clamp(1.9rem, 3vw, 2.6rem); font-weight: 500; letter-spacing: calc(var(--k) * -0.03em); line-height: 1.1; }
.fig span { color: var(--text-3s); font-size: .875rem; }
.gx { position: relative; }
.port-head { scroll-margin-top: 104px; }   /* "Skip to portfolio" lands clear of the nav */
.gx-pin {
  position: relative; max-width: var(--wide); margin-inline: auto; padding-inline: var(--gutter);
  display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: clamp(1.5rem, 4vw, 4.5rem);
}
.gx-stage { position: relative; min-height: 0; }
.gx-still { width: 100%; max-height: 80vh; object-fit: contain; }
.gx-canvas, .gx-lead { display: none; }
.gx-side { display: grid; grid-template-rows: auto 1fr auto; gap: 1.6rem; min-height: 0; }
.gx-title { font-size: clamp(2.4rem, 4.6vw, 4rem); font-weight: 700; text-transform: uppercase; letter-spacing: calc(var(--k) * -0.04em); line-height: .92; }
.gx-copy { position: relative; display: grid; gap: 3rem; }
.gx-step { display: grid; gap: .9rem; justify-items: start; }
.gx-n { color: var(--accent); font-size: .75rem; text-transform: uppercase; letter-spacing: .07em; }
.gx-step h4 { margin: 0; font-size: clamp(1.7rem, 2.8vw, 2.45rem); font-weight: 600; letter-spacing: calc(var(--k) * -0.03em); line-height: 1.08; text-wrap: balance; }
.gx-step p { color: var(--text-2); max-width: 44ch; }
.gx-index { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .4rem; }
.gx-index button {
  font: inherit; font-size: .8125rem; color: var(--text-3s); background: none; border: 1px solid var(--line); border-radius: 999px;
  height: 32px; padding: 0 .8rem; display: inline-flex; align-items: center; gap: .45rem; cursor: pointer; transition: color .25s, border-color .25s, background .25s;
}
.gx-index button span { font-size: .75rem; }
.gx-index button[aria-current] { color: var(--text); background: var(--bg-3); border-color: var(--line-2); }
.gx-index button[aria-current] span { color: var(--accent); }

/* with JS: the scene pins and the camera does the work */
.gx.gx-on { height: calc(var(--n) * 110vh + 100vh); height: calc(var(--n) * 110svh + 100svh); }
.gx-on .gx-pin { position: sticky; top: 0; height: 100vh; height: 100dvh; padding-block: calc(56px + 3vh) 4vh; }
.gx-on .gx-still { display: none; }
.gx-on .gx-canvas {
  display: block; position: absolute; inset: 0; width: 100%; height: 100%;
  -webkit-mask-image: linear-gradient(transparent, #000 9%, #000 91%, transparent); mask-image: linear-gradient(transparent, #000 9%, #000 91%, transparent);
}
.gx-on .gx-lead { display: block; position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; z-index: 2; transition: opacity .2s; }
.gx-lead polyline { fill: none; stroke: var(--text-2); stroke-width: 1; }
.gx-lead circle.a { fill: var(--accent); stroke: rgb(234 140 94 / .28); stroke-width: 10; }
.gx-lead circle.b { fill: var(--text-2); }
.gx-on .gx-copy { display: block; align-self: center; min-height: 20rem; }
.gx-on .gx-step {
  position: absolute; left: 0; right: 0; top: 50%; opacity: 0; pointer-events: none; visibility: hidden;
  /* --off is set per step by goblet.js: the text you leave goes the way you scroll, the next comes from the other side */
  transform: translateY(calc(-50% + var(--off, 16px))); transition: opacity .45s var(--ease), transform .7s var(--ease), visibility 0s .45s;
}
.gx-on .gx-step.on { opacity: 1; pointer-events: auto; visibility: visible; transform: translateY(-50%); transition: opacity .55s var(--ease) .1s, transform .8s var(--ease) .1s, visibility 0s; }
@media (prefers-reduced-motion: reduce) { .gx-on .gx-step, .gx-on .gx-step.on { transition: opacity .2s, visibility 0s; transform: translateY(-50%); } }
@media (max-width: 860px) {
  .gx-pin { grid-template-columns: 1fr; }
  .gx-on .gx-pin { grid-template-rows: 52svh 1fr; gap: 1rem; padding-block: calc(56px + 1vh) 2vh; }
  .gx-on .gx-top, .gx-on .gx-index { display: none; }
  .gx-on .gx-side { grid-template-rows: 1fr; }
  .gx-on .gx-copy { align-self: start; min-height: 0; height: 100%; }
  .gx-on .gx-step { top: 0; transform: translateY(calc(var(--off, 16px) * .75)); }
  .gx-on .gx-step.on { transform: none; }
  .gx-step h4 { font-size: 1.55rem; }
  .gx-step p { font-size: .98rem; }
  .figs { gap: .2rem 1.6rem; }
}

/* where-am-I rail (desktop): a tick per section down the left edge. The current one is longer, in the
   accent, and named; hovering the rail names them all. Fades in once the hero has scrolled away (site.js). */
.loc { display: none; }
@media (min-width: 1200px) and (hover: hover) and (pointer: fine) {
  .loc {
    position: fixed; z-index: 30; left: clamp(14px, 1.6vw, 26px); top: 50%; display: grid; gap: .2rem;
    opacity: 0; transform: translate(-8px, -50%); pointer-events: none; transition: opacity .5s var(--ease), transform .6s var(--ease);
  }
  .loc.show { opacity: 1; transform: translate(0, -50%); pointer-events: auto; }
  html.gx-open .loc { opacity: 0; pointer-events: none; }
  .loc a { display: flex; align-items: center; gap: .5rem; height: 24px; text-decoration: none; color: var(--text-3s); font-family: var(--mono); font-size: .68rem; text-transform: uppercase; letter-spacing: .07em; }
  .loc i { flex: none; width: 12px; height: 2px; border-radius: 2px; background: var(--text-3); transition: width .45s var(--ease), background .3s; }
  .loc span {
    padding: .1rem .45rem; background: rgb(10 11 13 / .72); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
    white-space: nowrap; opacity: 0; transform: translateX(-4px); transition: opacity .3s, transform .45s var(--ease), color .3s;
  }
  .loc a.on i { width: 26px; background: var(--accent); }
  .loc a:not(.on):hover i { width: 18px; background: var(--text-2); }
  .loc:hover span { opacity: .85; transform: none; }
  .loc a.on span { color: var(--text); }
  .loc a:hover span { color: var(--text); opacity: 1; }   /* narrower screens: named on hover only, so it never sits over content */
}
@media (min-width: 1600px) and (hover: hover) and (pointer: fine) {
  .loc a.on span { opacity: 1; transform: none; }          /* room beside the content: the current one is always named */
}

/* the tour's sheet: fixed over the page, its own scroller, grown out of the Goblet tile (goblet.js drives
   the clip and the engine's transform). Hidden, it still lays out, so it can be measured before it shows. */
.gx-sheet { position: fixed; inset: 0; z-index: 70; background: var(--bg); visibility: hidden; pointer-events: none; }
.gx-sheet.open { visibility: visible; pointer-events: auto; }
.gx-sheet:not(.open) .gx-step { visibility: hidden !important; }   /* the shown step sets its own visibility */
.gx-scroll { position: absolute; inset: 0; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none; }
.gx-scroll::-webkit-scrollbar { display: none; }
.gx-sheet .gx-stage { transform-origin: 0 0; }
.gx-bar { position: absolute; z-index: 3; top: 10px; right: var(--gutter); display: flex; align-items: center; gap: .6rem; }
.gx-bar .pill { height: 40px; }
.gx-close { background: rgb(255 255 255 / .06); }
html.gx-open.lenis.lenis-stopped { overflow: visible; }
/* the end of the tour runs straight into the Goblet page's opening screen, laid out exactly as that page
   (one screen tall, so at the bottom it sits where the real page starts); goblet.js lifts it against a little
   resistance and then hands over to the real page at the same spot */
.gx-end { position: relative; height: 100vh; height: 100dvh; overflow: clip; }
.gx-peek { pointer-events: none; }
.gx-navclone { pointer-events: none; z-index: 4; opacity: 0; }
@media (max-width: 640px) { .gx-more { display: none; } }

/* project filter: one row of type buttons; the chosen one is filled. Filtered, the tiles drop their bento
   spans and sit in an even grid (a curated bento only works with every project in it) */
.pf { display: flex; gap: .4rem; margin-top: 2rem; flex-wrap: wrap; }
.pf button {
  font: inherit; font-family: var(--mono); font-size: .72rem; text-transform: uppercase; letter-spacing: .07em;
  height: 36px; padding: 0 .85rem; display: inline-flex; align-items: center; gap: .6rem; cursor: pointer;
  color: var(--text-2); background: none; border: 1px solid var(--line-2); transition: color .2s, background .2s, border-color .2s;
}
.pf button span { color: var(--text-3s); font-size: .68rem; transition: color .2s; }
.pf button[aria-pressed="true"] { background: var(--text); border-color: var(--text); color: var(--bg); }
.pf button[aria-pressed="true"] span { color: var(--bg); opacity: .6; }
.pf button:active { transform: translateY(1px); }
@media (hover: hover) and (pointer: fine) { .pf button[aria-pressed="false"]:hover { color: var(--text); border-color: var(--text-2); } }
@media (max-width: 640px) {
  .pf { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter); }
  .pf::-webkit-scrollbar { display: none; }
  .pf button { flex: none; }
}
.bento .tile[hidden] { display: none; }
.bento.filtered .tile.tile { grid-column: auto; grid-row: auto; flex-direction: column; }
.bento.filtered .tile.tile .tile-img { aspect-ratio: 16 / 10; min-height: 0; flex: none; width: auto; max-height: none; }

/* projects: bento with exact cells */
.bento { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-flow: row dense; gap: 16px; margin-top: 1.6rem; }
.tile {
  position: relative; display: flex; flex-direction: column; text-decoration: none; background: var(--bg-2);
  border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; transition: border-color .3s;
}
.tile-img { overflow: hidden; background: var(--bg-3); aspect-ratio: 16 / 10; }
.tile-img img { width: 100%; height: 100%; object-fit: cover; transition: transform .9s var(--ease); }
.tile-body { padding: 1.25rem 2.8rem 1.5rem 1.4rem; display: grid; gap: .45rem; align-content: start; }
.tile h3 { font-size: 1.4rem; letter-spacing: -0.018em; display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
.tile h3 small { font-size: 1rem; font-weight: 400; color: var(--text-2); letter-spacing: 0; }
.tile .meta { display: flex; gap: .8rem; align-items: center; font-family: var(--mono); font-size: .7rem; text-transform: uppercase; letter-spacing: .07em; color: var(--text-3s); }
.tile .meta .wip { color: var(--accent); }
/* achievements, then skills, as a hanging bullet list */
.hl-list { list-style: none; margin: .15rem 0 0; padding: 0; display: grid; gap: .4rem; }
.hl-list li { position: relative; padding-left: 1.05rem; color: var(--text-2); font-size: .95rem; line-height: 1.45; }
.hl-list li::before {
  content: ""; position: absolute; left: 0; top: .6em; width: 5px; height: 5px; border-radius: 50%; background: var(--accent);
}
.hl-list li.sk { color: var(--text-3s); font-size: .88rem; }
.hl-list li.sk::before { background: none; box-shadow: inset 0 0 0 1px var(--text-3); }
.tile .go { position: absolute; right: 1.1rem; bottom: 1.2rem; color: var(--text-3); transition: color .2s, translate .3s var(--ease); }
.tile.big { grid-column: span 2; grid-row: span 2; }
.tile.big .tile-img { aspect-ratio: auto; flex: 1; min-height: 340px; }
.tile.big h3 { font-size: clamp(2rem, 3.4vw, 3rem); font-weight: 700; text-transform: uppercase; letter-spacing: calc(var(--k) * -0.035em); }
.tile.big h3 small { text-transform: none; letter-spacing: 0; }
.tile .stats { display: flex; gap: 2.6rem; margin-top: .5rem; }
.tile .stats b { display: block; font-size: clamp(1.7rem, 2.6vw, 2.2rem); font-weight: 500; letter-spacing: calc(var(--k) * -0.035em); line-height: 1; color: var(--text); }
.tile.big .stats b { font-size: clamp(2rem, 3.6vw, 3rem); }
.tile .stats span { font-size: .85rem; color: var(--text-3s); }
/* Goblet: the tile shows the tour's first frame, faded exactly as the tour draws it, so the engine can grow
   straight into the tour when the tile opens it */
.tile.tour .tile-img { position: relative; background: var(--bg); }
.tile.tour .tile-img img {
  position: absolute; top: 0; left: 50%; translate: -50% 0; height: 100%; width: auto; max-width: none;
  -webkit-mask-image: linear-gradient(transparent, rgb(0 0 0 / .4) 13.5%, #000 30%, #000 94%, transparent), linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
  -webkit-mask-composite: source-in; mask-image: linear-gradient(transparent, rgb(0 0 0 / .4) 13.5%, #000 30%, #000 94%, transparent), linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
  mask-composite: intersect;
}
.tour-cue {
  position: absolute; left: 1.1rem; bottom: 1.1rem; z-index: 1; display: inline-flex; align-items: center; gap: .5rem;
  height: 42px; padding: 0 1.05rem 0 .85rem; font-size: .9375rem; font-weight: 500; color: var(--text);
  background: rgb(255 255 255 / .08); border: 1px solid rgb(255 255 255 / .14); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  transition: background .25s, border-color .25s;
}
.tour-cue .i { width: 15px; height: 15px; color: var(--accent); }
.tile.tour.opened .tile-img img, .tile.tour.opened .tour-cue { visibility: hidden; }
.tile.wide { grid-column: span 2; }
.tile.wide .tile-img { aspect-ratio: 21 / 9; }
.tile.strip { grid-column: 1 / -1; flex-direction: row; }
.tile.strip .tile-img { aspect-ratio: auto; width: 46%; flex: none; max-height: 340px; }
.tile.strip .tile-body { align-content: center; }
@media (max-width: 960px) {
  .bento { grid-template-columns: 1fr 1fr; }
  .tile.big { grid-column: span 2; grid-row: auto; }
  .tile.wide, .tile.strip { grid-column: span 2; }
  .tile.tour .tile-img { min-height: min(560px, 62vh); }
}
@media (max-width: 640px) {
  .bento { grid-template-columns: 1fr; }
  .tile.big, .tile.wide, .tile.strip { grid-column: auto; }
  .tile.big .tile-img { min-height: 240px; }
  .tile.tour .tile-img { min-height: 400px; }
  .tile.strip { flex-direction: column; }
  .tile.strip .tile-img { width: auto; aspect-ratio: 16 / 10; }
}

/* skills: grouped by years of experience, the figure set large as the anchor of each row (no bars: a
   number says it exactly). Under each skill, the projects that show it, as small linked chips. */
.sk { margin-top: clamp(2.6rem, 5vw, 3.6rem); }
.sk-tier {
  display: grid; grid-template-columns: minmax(7.5rem, 13rem) repeat(2, minmax(0, 1fr)); gap: 1.6rem clamp(2rem, 4vw, 4rem);
  align-items: start; padding-block: clamp(1.8rem, 3.2vw, 2.6rem); border-top: 1px solid var(--line);
}
.sk-yrs { display: flex; align-items: baseline; gap: .55rem; }
.sk-yrs b { font-size: clamp(3.4rem, 6.4vw, 5.6rem); font-weight: 600; line-height: .82; letter-spacing: calc(var(--k) * -0.05em); color: var(--text); }
.sk-yrs span { font-family: var(--mono); font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; color: var(--text-3s); }
.sk-item { display: grid; gap: 1rem; padding-top: .35rem; }
.sk-item h3 { font-size: clamp(1.3rem, 1.9vw, 1.6rem); font-weight: 600; letter-spacing: calc(var(--k) * -0.02em); line-height: 1.15; }
.sk-tools { margin-top: -.45rem; color: var(--text-2); font-size: .975rem; line-height: 1.45; max-width: 40ch; }
.sk-used { display: flex; flex-wrap: wrap; gap: .5rem; }
.sk-used a {
  display: inline-flex; align-items: center; gap: .55rem; height: 34px; padding: 0 .85rem 0 3px;
  border: 1px solid var(--line); text-decoration: none; color: var(--text-2); font-size: .875rem; white-space: nowrap;
  transition: color .2s, border-color .2s, background .2s;
}
.sk-used img { width: 26px; height: 26px; object-fit: cover; background: var(--bg-3); }
@media (hover: hover) and (pointer: fine) {
  .sk-used a:hover { color: var(--text); border-color: var(--line-2); background: var(--bg-2); }
}
@media (max-width: 760px) {
  .sk-tier { grid-template-columns: minmax(0, 1fr); gap: 1.6rem; }
  .sk-yrs b { font-size: 3.2rem; }
  .sk-item { padding-top: 0; }
}

/* contact */
.contact { padding-block: clamp(5rem, 11vw, 9rem) 3rem; border-top: 1px solid var(--line); }
.contact .h2 { max-width: 20ch; font-size: clamp(2rem, 4.4vw, 3.6rem); line-height: .98; }
.contact .about-actions { margin-top: 2rem; }
.foot { margin-top: clamp(4rem, 8vw, 6rem); padding-top: 1.2rem; border-top: 1px solid var(--line); display: flex; justify-content: space-between; gap: 1rem; color: var(--text-3s); font-family: var(--mono); font-size: .72rem; text-transform: uppercase; letter-spacing: .07em; flex-wrap: wrap; }

/* ---------- project pages ---------- */
.p-head { padding-top: calc(56px + clamp(2.5rem, 7vw, 5rem)); }
.back { display: inline-flex; align-items: center; gap: .45rem; text-decoration: none; color: var(--text-2); font-family: var(--mono); font-size: .75rem; text-transform: uppercase; letter-spacing: .07em; }
.p-title { font-size: clamp(3rem, 9vw, 7.6rem); font-weight: 700; text-transform: uppercase; letter-spacing: calc(var(--k) * -0.05em); line-height: .9; margin-top: 1.4rem; padding-bottom: .04em; }
.p-sub { font-size: clamp(1.3rem, 2.4vw, 2rem); color: var(--text-2); letter-spacing: -0.018em; margin-top: .6rem; font-weight: 500; }
.facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1.2rem 2rem; margin-top: 2.4rem; padding-top: 1.6rem; border-top: 1px solid var(--line); }
.fact span { display: block; font-family: var(--mono); font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; color: var(--text-3s); margin-bottom: .4rem; }
.fact p { color: var(--text); font-size: .98rem; line-height: 1.45; }
.fact .wip { color: var(--accent); }
.p-cover { margin-top: clamp(2rem, 5vw, 3.5rem); }
.p-cover img { width: 100%; max-height: 72vh; object-fit: cover; border-radius: var(--r); }
.p-layout { display: grid; grid-template-columns: 210px minmax(0, 1fr); gap: clamp(2rem, 6vw, 5.5rem); padding-block: clamp(3.5rem, 8vw, 6rem); }
.toc { position: sticky; top: 88px; align-self: start; display: grid; gap: .1rem; font-size: .9rem; max-height: calc(100vh - 110px); overflow: auto; }
.toc a { text-decoration: none; color: var(--text-3s); padding: .32rem 0 .32rem .9rem; border-left: 1px solid var(--line); transition: color .2s, border-color .2s; line-height: 1.35; }
.toc a.on { color: var(--text); border-left-color: var(--accent); }
.prose { min-width: 0; display: grid; gap: 1.25rem; }
.prose section { display: grid; gap: 1.25rem; scroll-margin-top: 80px; }
.prose section + section { margin-top: clamp(2.6rem, 6vw, 4.5rem); }
.prose h2 { font-size: clamp(1.9rem, 3.6vw, 2.9rem); font-weight: 700; text-transform: uppercase; letter-spacing: calc(var(--k) * -0.035em); line-height: .95; padding-top: 1.1rem; border-top: 1px solid var(--line-2); }
.prose h3 { font-size: 1.35rem; letter-spacing: -0.012em; margin-top: .6rem; }
.prose p, .prose ul, .prose .tbl, .prose .links { max-width: 66ch; }
.prose p { color: #cfd1d5; }
.prose p a { text-decoration-color: var(--accent); text-underline-offset: .2em; }
.prose ul { margin: 0; padding-left: 1.15rem; display: grid; gap: .35rem; color: #cfd1d5; }
.prose ul li::marker { color: var(--accent); }
.prose .quote { font-size: clamp(1.4rem, 2.4vw, 1.9rem); line-height: 1.3; letter-spacing: calc(var(--k) * -0.02em); color: var(--text); font-weight: 500; }
.media { margin: 0; border-radius: var(--r); overflow: hidden; background: var(--bg-2); }
.media a { display: block; cursor: zoom-in; }
.media img, .media video { width: 100%; }
.prose > section > .media, .prose > section > .gallery { max-width: 940px; }
.gallery { display: grid; gap: 12px; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); align-items: start; }
.gallery .media img, .gallery .media video { aspect-ratio: var(--ar, auto); object-fit: cover; }
@media (max-width: 640px) { .gallery { --n: 1 !important; } .gallery[data-n="2"], .gallery[data-n="4"] { --n: 2 !important; } }
.tbl { overflow-x: auto; }
.tbl table { border-collapse: collapse; min-width: 520px; width: 100%; font-variant-numeric: tabular-nums; }
.tbl th, .tbl td { text-align: left; padding: .7rem 1.2rem .7rem 0; vertical-align: top; }
.tbl thead th { font-family: var(--mono); font-weight: 400; font-size: .72rem; text-transform: uppercase; letter-spacing: .07em; color: var(--text-3s); border-bottom: 1px solid var(--line-2); }
.tbl tbody th { font-weight: 600; }
.tbl tbody tr + tr > * { border-top: 1px solid var(--line); }
.tbl td { color: #cfd1d5; }
.links { display: flex; gap: .7rem; flex-wrap: wrap; }
.embed { position: relative; aspect-ratio: 16 / 9; width: 100%; max-width: 940px; border-radius: var(--r); overflow: hidden; background: var(--bg-2); border: 1px solid var(--line); display: grid; place-items: center; }
.embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.embed-ui { display: grid; justify-items: center; gap: 1rem; text-align: center; padding: 1rem; }
.play { width: 72px; height: 72px; border-radius: 999px; border: 0; background: var(--text); color: var(--bg); display: grid; place-items: center; cursor: pointer; transition: transform .2s var(--ease); }
.play svg { width: 26px; height: 26px; margin-left: 3px; }
.embed-ui small { color: var(--text-3s); font-size: .875rem; }
.embed-ui small a { color: var(--text-2); }
.p-next { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; padding-bottom: clamp(3rem, 8vw, 6rem); }
.p-next a { display: grid; grid-template-columns: 96px 1fr; gap: 1rem; align-items: center; text-decoration: none; padding: .9rem; border-radius: var(--r); background: var(--bg-2); border: 1px solid var(--line); transition: border-color .3s; }
.p-next img { width: 96px; height: 72px; object-fit: cover; border-radius: 10px; }
.p-next span { display: block; font-family: var(--mono); font-size: .7rem; text-transform: uppercase; letter-spacing: .07em; color: var(--text-3s); }
.p-next b { font-weight: 600; letter-spacing: -0.01em; font-size: 1.05rem; }
.p-next a:last-child { grid-template-columns: 1fr 96px; text-align: right; }
.p-next a:last-child img { order: 2; }
@media (max-width: 960px) { .p-layout { grid-template-columns: 1fr; } .toc { display: none; } }
@media (max-width: 640px) { .p-next { grid-template-columns: 1fr; } }

/* ---------- lightbox ---------- */
dialog.lb { padding: 0; border: 0; margin: 0; width: 100vw; height: 100vh; height: 100dvh; max-width: 100vw; max-height: 100dvh; background: transparent; color: var(--text); overflow: hidden; }
dialog.lb::backdrop { background: transparent; }
/* the backdrop darkens with the photo as it opens, and lightens as you swipe it away (site.js) */
.lb-scrim { position: fixed; inset: 0; background: rgb(8 9 10 / .95); opacity: 0; }
.lb-in { position: relative; z-index: 1; width: 100%; height: 100%; display: grid; grid-template-rows: auto 1fr; padding: 14px 16px calc(env(safe-area-inset-bottom, 0px) + 16px); gap: 10px; }
.lb-bar { display: flex; justify-content: space-between; align-items: center; gap: 1rem; font-family: var(--mono); font-size: .8rem; color: var(--text-2); }
.lb-btns { display: flex; gap: .5rem; }
.lb-stage { position: relative; min-height: 0; touch-action: none; }
.lb-item { position: absolute; transform-origin: 0 0; will-change: transform; border-radius: 12px; overflow: hidden; }
.lb-item img, .lb-item video { width: 100%; height: 100%; object-fit: contain; display: block; }
.lb-bar { position: relative; z-index: 2; }
.lb-btns .icon-btn[disabled] { opacity: .3; }

/* tracking eases off as display type shrinks on narrower screens */
@media (max-width: 900px) { :root { --k: .82; } }
@media (max-width: 560px) { :root { --k: .66; } }

/* hover effects only where there is a real pointer to hover with (no sticky hover after a tap on a phone) */
@media (hover: hover) and (pointer: fine) {
  .nav-links a:hover { color: var(--text); }
  .pill.solid:hover { background: #fff; }
  .pill.line:hover { border-color: var(--text-2); background: var(--bg-3); }
  .pill.skip:hover { background: #f29d72; }
  .pill.skip:hover .i { transform: translateY(3px); }
  .callout:hover { color: var(--text); border-color: var(--accent); }
  .icon-btn:hover { background: var(--bg-3); border-color: var(--text-3); }
  .rail-bar:hover .rail-thumb { background: var(--text); top: 10px; height: 8px; }
  .tl:hover .tl-dot { border-color: var(--text); }
  .job:hover .job-img img { transform: scale(1.03); }
  .gx-index button:hover { color: var(--text); border-color: var(--line-2); }
  .tile:hover { border-color: var(--line-2); }
  .tile:hover .tile-img img { transform: scale(1.035); }
  .tile:hover .go { color: var(--text); translate: 2px -2px; }
  .tile.tour:hover .tour-cue { background: rgb(255 255 255 / .14); border-color: rgb(255 255 255 / .22); }
  .back:hover { color: var(--text); }
  .toc a:hover { color: var(--text); }
  .play:hover { transform: scale(1.05); }
  .p-next a:hover { border-color: var(--line-2); }
}

/* pressed: responds the instant it is pressed, eases back on release */
.tile, .gx-index button, .icon-btn, .p-next a, .callout, .play, .back, .lb-btns button {
  transition-property: transform, border-color, color, background, opacity; transition-duration: .3s; transition-timing-function: var(--ease);
}
.pill:active, .tile:active, .gx-index button:active, .icon-btn:active, .p-next a:active, .play:active, .lb-btns button:active {
  transform: scale(.98); transition-duration: .08s;
}
.callout:active, .back:active, .nav-links a:active, .toc a:active { opacity: .6; transition-duration: .08s; }
