/* ---------- Fonts ----------
   One place to change typography. To use a web font, either add its <link> in
   index.html's <head> or drop an @font-face rule here, e.g.

   @font-face {
     font-family: 'Her Font';
     src: url('fonts/her-font.woff2') format('woff2');
     font-weight: 100 900;
     font-display: swap;
   }

   then put 'Her Font' first in the variables below. */
:root {
  --font-display: ui-sans-serif, system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif;
  --font-body: ui-sans-serif, system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif;
  --font-mono: ui-monospace, 'SF Mono', Menlo, monospace;
}

/* ---------- Theme tokens (monochrome) ---------- */
:root {
  --bg: #f7f7f5;
  --raised: #ffffff;
  --ink: #141414;
  --muted: #6e6e6a;
  --line: #e3e3df;
  --line-strong: #c9c9c4;
  /* Story photos sit in a print: a mat a touch warmer/lighter than the page. */
  --print: #fdfdfa;
  --print-edge: rgba(20, 20, 20, 0.09);
  --print-shadow: 0 1px 1px rgba(20, 20, 20, 0.05), 0 3px 8px -2px rgba(20, 20, 20, 0.08);
  --print-lift: 0 22px 38px -16px rgba(20, 20, 20, 0.3), 0 8px 14px -8px rgba(20, 20, 20, 0.12);
  --print-ink: #161615;
  --print-ink-text: #f4f4f0;
  /* The one accent: a light powder blue, used only on the timeline (trail,
     traveler, progress bar), the Story/Work pill and link hover underlines;
     never on cards. Flat color only: no gradients or glow; the Story/Work
     pill is an outline, not a fill. Powder is too pale for
     a focus ring on the light page (~1.9:1), so --focus is a deeper blue
     (#2f7fd6, 3.8:1 on --bg); in dark mode Powder itself passes. */
  --accent: #7cbcff;
  --focus: #2f7fd6;
  color-scheme: light;

  --bar: 3.5rem;
  --gutter: clamp(1rem, 4vw, 2.5rem);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease: ease;
  --t-fast: 0.2s;
  --t-med: 0.45s;
  --page: 60rem;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --bg: #111111;
    --raised: #1a1a1a;
    --ink: #f2f2ef;
    --muted: #9b9b96;
    --line: #262626;
    --line-strong: #3d3d3b;
    --print: #232322;
    --print-edge: rgba(255, 255, 255, 0.07);
    --print-shadow: 0 1px 1px rgba(0, 0, 0, 0.4), 0 3px 8px -2px rgba(0, 0, 0, 0.45);
    --print-lift: 0 24px 40px -14px rgba(0, 0, 0, 0.75), 0 8px 14px -8px rgba(0, 0, 0, 0.5);
    --print-ink: #0b0b0b;
    --print-ink-text: #f2f2ef;
    --accent: #8ec8ff;
    --focus: #8ec8ff;
    color-scheme: dark;
  }
}

:root[data-theme='dark'] {
  --bg: #111111;
  --raised: #1a1a1a;
  --ink: #f2f2ef;
  --muted: #9b9b96;
  --line: #262626;
  --line-strong: #3d3d3b;
  --print: #232322;
  --print-edge: rgba(255, 255, 255, 0.07);
  --print-shadow: 0 1px 1px rgba(0, 0, 0, 0.4), 0 3px 8px -2px rgba(0, 0, 0, 0.45);
  --print-lift: 0 24px 40px -14px rgba(0, 0, 0, 0.75), 0 8px 14px -8px rgba(0, 0, 0, 0.5);
  --print-ink: #0b0b0b;
  --print-ink-text: #f2f2ef;
  --accent: #8ec8ff;
  --focus: #8ec8ff;
  color-scheme: dark;
}

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

h1,
h2,
h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

p {
  margin: 0 0 1rem;
}

a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  text-decoration-color: var(--line-strong);
  transition: text-decoration-color 0.2s ease;
}

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

button {
  font: inherit;
  color: inherit;
}

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

main:focus {
  outline: none;
}

.label {
  margin: 0 0 1rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  line-height: 1.5;
  text-transform: uppercase;
  color: var(--muted);
}

/* Placeholders that still need Iana's words: easy to spot during review. */
[data-todo] {
  text-decoration: underline dashed var(--line-strong);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: 1rem;
  top: -3rem;
  z-index: 50;
  padding: 0.5rem 0.75rem;
  background: var(--ink);
  color: var(--bg);
  text-decoration: none;
}

.skip-link:focus {
  top: 0.5rem;
}

/* ---------- Top bar ---------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  height: var(--bar);
  padding: 0 var(--gutter);
  background: var(--bg);
  border-bottom: 1px solid var(--line);
}

.topbar-name {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}

.topbar-tools {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

/* Contact: a quiet text link, the same small mono caps as the name. */
.topbar-link {
  padding: 0.35rem 0.2rem;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  line-height: 1.6;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--t-fast) var(--ease);
}

.topbar-link:hover,
.topbar-link[aria-current='page'] {
  color: var(--ink);
}

/* The page you're on: inked, with a hairline under it. */
.topbar-link[aria-current='page'] {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.35em;
  text-decoration-color: currentColor;
}

.theme-toggle {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: none;
  cursor: pointer;
  transition: border-color 0.2s ease;
}

.theme-toggle:hover {
  border-color: var(--ink);
}

.theme-toggle svg {
  transition: transform 0.4s var(--ease-out);
}

.theme-toggle[aria-pressed='true'] svg {
  transform: rotate(180deg);
}

/* ---------- View switch (Story / Work) ---------- */
html:not(.js) .view-switch {
  display: none;
}

.view-switch {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  padding: 2px;
  /* No outline around the pair: only the active option's powder-blue pill.
     The border stays (transparent) so the switch keeps its exact size. */
  border: 1px solid transparent;
  border-radius: 999px;
}

.view-switch::before {
  content: '';
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 2px;
  width: calc(50% - 2px);
  box-sizing: border-box;
  border: 1.5px solid var(--accent);
  border-radius: 999px;
  background: none;
  transition: transform 0.35s var(--ease-out);
}

html[data-view='work'] .view-switch::before {
  transform: translateX(100%);
}

.view-switch button {
  position: relative;
  padding: 0.2rem 0.8rem;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.6;
  cursor: pointer;
  transition: color 0.2s ease;
}

.view-switch button:hover {
  color: var(--ink);
}

.view-switch button[aria-pressed='true'] {
  color: var(--ink);
}

html[data-view='work'] .only-story,
html[data-view='story'] .only-work {
  display: none;
}

.view-enter .below {
  animation: fade-in 0.3s ease-out;
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* ---------- Intro ---------- */
.intro {
  padding: 2rem var(--gutter) 1.5rem;
}

.intro h1 {
  font-size: clamp(1.5rem, 2.8vw, 2.25rem);
}

.intro-role {
  margin: 0.35rem 0 0;
  color: var(--muted);
}

/* "Currently at ...": a quiet second line, the company in ink. */
.intro-now {
  margin: 0.3rem 0 0.9rem;
  color: var(--muted);
  font-size: 0.875rem;
}

.intro-now strong {
  color: var(--ink);
  font-weight: inherit;
}

.links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.9375rem;
}

.copy-email {
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  text-decoration-color: var(--line-strong);
  transition: text-decoration-color 0.2s ease;
}

.copy-email:hover {
  text-decoration-color: var(--accent);
}

/* ---------- Timeline: shared pieces ---------- */
.timeline {
  position: relative;
}

.stops {
  margin: 0;
  padding: 0;
  list-style: none;
}

.stop {
  --a: 1;
  position: relative;
}

/* Each photo is a print: an even mat, a deeper bottom margin carrying a small
   caption, a hairline edge and a soft resting shadow. The picture sits in
   .print-window (added by script.js), which clips it. */
.stop {
  --mat: 12px;
  --mat-foot: calc(var(--mat) * 3);
}

.stop-photo {
  position: relative;
  display: flex;
  flex-direction: column;
  margin: 0;
  aspect-ratio: 4 / 5;
  padding: var(--mat) var(--mat) var(--mat-foot);
  background: var(--print);
  border: 1px solid var(--print-edge);
  box-shadow: var(--print-shadow);
}

/* The lifted shadow lives on its own layer; only its opacity changes. */
.stop-photo::after {
  content: '';
  position: absolute;
  inset: -1px;
  z-index: -1;
  box-shadow: var(--print-lift);
  opacity: 0;
  pointer-events: none;
}

.print-window {
  position: relative;
  display: block;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  background: var(--line);
}

.stop-photo img {
  display: block;
  flex: 1 1 auto;
  width: 100%;
  height: 100%;
  min-height: 0;
  object-fit: cover;
  background: var(--line);
}

/* A whisper of film grain over real photos. Static, painted once. */
.stop-photo.has-photo .print-window::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.5 0 0 0 0 0.5 0 0 0 0 0.5 0 0 0 1.6 -0.55'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: 0.35;
  mix-blend-mode: overlay;
  pointer-events: none;
}

.print-caption {
  position: absolute;
  right: var(--mat);
  bottom: 0;
  left: var(--mat);
  display: flex;
  align-items: center;
  height: var(--mat-foot);
  overflow: hidden;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.stop-photo.is-missing img {
  display: none;
}

.stop-photo.is-missing .print-window {
  background: none;
}

/* localhost only: an empty mat with a dashed window that names the file. */
.photo-hint {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  gap: 0.35rem;
  padding: 1rem;
  border: 1px dashed var(--line-strong);
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  line-height: 1.5;
  text-align: center;
  overflow-wrap: anywhere;
}

.photo-hint span {
  color: var(--ink);
}

/* No photo (live site): the print's window is ink with the stop's text. */
.photo-card {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  justify-content: safe flex-end;
  gap: 0.5rem;
  overflow: hidden;
  padding: clamp(0.9rem, 3.5vw, 1.15rem);
  background: var(--print-ink);
  color: var(--print-ink-text);
  text-align: left;
}

.photo-card-kicker {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  opacity: 0.7;
}

.photo-card-title {
  font-family: var(--font-display);
  /* Follows the print's size (--card-w, measured), so a smaller pile keeps its titles whole. */
  font-size: clamp(1.1rem, calc(var(--card-w, 22rem) * 0.08), 1.7rem);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.photo-card-kicker {
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

/* On the pile the text card follows the print's size (--card-w, measured):
   a smaller print gets a slimmer margin and a smaller company line. */
.tl-rig .photo-card {
  padding: clamp(0.6rem, calc(var(--card-w, 22rem) * 0.06), 1.15rem);
}

/* Work stops: the company, a quiet line above the role. */
.photo-card-company {
  margin-bottom: -0.2rem;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  line-height: 1.3;
  /* Tighter than the other mono captions so "Sorenson Communications" stays on one line on a 360px phone. */
  letter-spacing: 0.05em;
  text-transform: uppercase;
  overflow-wrap: break-word;
  opacity: 0.7;
}

.tl-rig .photo-card-company {
  font-size: clamp(0.6rem, calc(var(--card-w, 22rem) * 0.05), 0.6875rem);
}

.photo-card-short {
  display: -webkit-box;
  overflow: hidden;
  font-size: 0.9375rem;
  line-height: 1.4;
  opacity: 0.8;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  text-wrap: balance;
}


.stop-body {
  position: relative;
}

.stop-kicker {
  margin: 0 0 0.35rem;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.03em;
  line-height: 1.5;
  color: var(--muted);
}

/* The stop's type (life, work, project...), added by script.js from data-type. */
.stop-type {
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
}

.stop.is-filtered,
.stop.is-broken {
  display: none !important;
}

/* Parked for now with the `hidden` attribute (the Life stops, "Off the clock",
   the Lab link): never shown, whatever else styles them. script.js skips
   hidden stops entirely. Remove `hidden` in index.html to bring one back. */
.stop[hidden],
.below > section[hidden],
.topbar-link[hidden] {
  display: none !important;
}

/* Type filter: only built when the timeline has more than one type. */
.tl-filter {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  margin: 0;
  padding: 0 var(--gutter) 0.75rem;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.tl-filter button {
  padding: 0.2rem 0;
  border: 0;
  border-bottom: 1px solid transparent;
  background: none;
  color: var(--muted);
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
  transition:
    color 0.2s ease,
    border-color 0.2s ease;
}

.tl-filter button:hover {
  color: var(--ink);
}

.tl-filter button[aria-pressed='true'] {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

.stop-title {
  font-size: 1.0625rem;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.stop-short {
  margin: 0.45rem 0 0;
  text-wrap: balance;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.45;
}

.stop-full {
  font-size: 0.9rem;
  line-height: 1.5;
}

.stop-full p {
  margin: 0;
}

.stop-points {
  margin: 0;
  padding-left: 1rem;
}

.stop-points li + li {
  margin-top: 0.4rem;
}

.stop-points li::marker {
  color: var(--muted);
}

/* The "What I do" stop's back: each skill group's label over its list. */
.stop-skills {
  margin: 0;
}

.stop-skills > div + div {
  margin-top: 0.55rem;
}

.stop-skills dt {
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  line-height: 1.5;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.stop-skills dd {
  margin: 0;
}

.stop-more {
  position: relative;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.6rem;
  padding: 0.2rem 0;
  border: 0;
  background: none;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.03em;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  text-decoration-color: var(--line-strong);
}

.stop-more:hover {
  text-decoration-color: var(--accent);
}

.stop-more::after {
  content: '+';
  display: inline-block;
  width: 0.6em;
  text-align: center;
}

.stop-more[aria-expanded='true']::after {
  content: '\2013';
}

.stop-mark {
  display: none;
}

.tl-foot {
  display: none;
}

/* ---------- Timeline fallback: a plain horizontal row ----------
   Used without JS and with reduced motion. Everything is visible; swipe or
   scroll sideways. */
.timeline:not(.is-pinned) .tl-viewport {
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--gutter);
  padding-bottom: 1.5rem;
}

.timeline:not(.is-pinned) .stops {
  display: flex;
  width: max-content;
  padding: 0.5rem var(--gutter) 0;
}

.timeline:not(.is-pinned) .stop {
  width: min(78vw, 19rem);
  padding-right: 1.5rem;
  scroll-snap-align: start;
}

.timeline:not(.is-pinned) .stop-photo {
  margin-bottom: 1.25rem;
}

/* Laid out flat, the prints keep a small resting tilt, alternating. */
.timeline:not(.is-pinned) .stop:nth-child(odd) .stop-photo {
  transform: rotate(-1deg);
}

.timeline:not(.is-pinned) .stop:nth-child(even) .stop-photo {
  transform: rotate(0.8deg);
}

.timeline:not(.is-pinned) .stop-photo.is-missing:not(.is-placeholder) {
  display: none;
}

.timeline:not(.is-pinned) .stop-body {
  margin-right: -1.5rem;
  padding: 1.25rem 1.5rem 0 0;
  border-top: 1px solid var(--line-strong);
}

.timeline:not(.is-pinned) .stop-body::before {
  content: '';
  position: absolute;
  top: -5px;
  left: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--ink);
}

.timeline:not(.is-pinned) .stop-full {
  margin-top: 0.75rem;
}

/* ---------- Timeline: pinned horizontal scroll ----------
   The section is as tall as the track is wide. While you scroll through it,
   the stage stays put and the track slides left. */
.hero.is-pinned {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}

.hero.is-pinned > * {
  grid-area: 1 / 1;
  min-width: 0;
}

.hero.is-pinned .intro {
  position: sticky;
  top: var(--bar);
  z-index: 3;
  align-self: start;
  /* As tall as the stage, so the intro leaves together with it. */
  margin-bottom: calc(100vh - var(--bar) - var(--intro-h, 9rem));
  margin-bottom: calc(100svh - var(--bar) - var(--intro-h, 9rem));
  pointer-events: none;
}

.hero.is-pinned .intro a,
.hero.is-pinned .intro button {
  pointer-events: auto;
}

.timeline.is-pinned {
  --slot: clamp(17rem, 31vw, 28rem);
  /* Room under the axis for the stop's text, with air below it. */
  --label-h: 11.75rem;
  --photo-gap: 1.5rem;
  /* Free space kept above the pile, under the intro. */
  --pile-room: clamp(1rem, 16svh - 6rem, 3rem);
}

.timeline.is-pinned .tl-stage {
  position: sticky;
  top: var(--bar);
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-columns: minmax(0, 1fr);
  height: calc(100vh - var(--bar));
  height: calc(100svh - var(--bar));
  padding-top: var(--intro-h, 9rem);
  overflow: clip;
}

.timeline.is-pinned .tl-filter {
  grid-row: 1;
}

.timeline.is-pinned .tl-viewport {
  grid-row: 2;
  grid-column: 1;
  position: relative;
  z-index: 1;
  min-height: 0;
  overflow: clip;
}

.timeline.is-pinned .stops {
  position: relative;
  display: flex;
  width: max-content;
  height: 100%;
  /* First stop starts centered and popped; scrolling moves on from there. */
  padding-left: calc(50% - var(--slot) / 2);
  padding-right: calc(50% - var(--slot) / 2);
  will-change: transform;
}

/* The axis: one hairline across the whole track. */
.timeline.is-pinned .stops::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--label-h);
  height: 1px;
  background: var(--line-strong);
}

.timeline.is-pinned .stop {
  display: grid;
  grid-template-rows: minmax(0, 1fr) var(--label-h);
  justify-items: center;
  flex: 0 0 var(--slot);
  height: 100%;
}

.timeline.is-pinned .stop-body {
  grid-row: 2;
  width: min(calc(var(--slot) - 2rem), 21rem);
  padding-top: 1.4rem;
  text-align: center;
}

/* The marker dot sits on the axis. */
.timeline.is-pinned .stop-body::before {
  content: '';
  position: absolute;
  top: -5px;
  left: calc(50% - 5px);
  width: 9px;
  height: 9px;
  border: 1px solid color-mix(in srgb, var(--ink) calc(45% + var(--a) * 55%), var(--bg));
  border-radius: 50%;
  background: var(--bg);
  transition: border-color 0.3s ease;
}

/* Scroll snapping: script.js puts one invisible anchor per stop inside the
   tall section, at the scroll offset where that stop sits centered under the
   dot. The class is only on while the page is inside the timeline, and it's
   proximity, not mandatory (mandatory traps the reader on the last stop), so
   the intro above and everything below scroll freely. Within the timeline the
   anchors are close enough that a scroll always settles on the nearest stop. */
html.tl-snapping {
  scroll-snap-type: y proximity;
}

.tl-snaps {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 0;
  pointer-events: none;
}

.tl-snap-point {
  position: absolute;
  left: 0;
  width: 1px;
  height: 1px;
  scroll-snap-align: start;
}

/* The traveler: one solid dot parked at the center of the axis (placed by
   script.js); the markers slide under it and a blue trail fills the line
   from the first marker up to it. The trail is 100px wide at rest and
   script.js scales it to length, so its gradient stretches end to end. */
.tl-trail,
.tl-traveler {
  display: none;
}

.timeline.is-pinned .tl-trail {
  position: absolute;
  left: 0;
  bottom: calc(var(--label-h) - 0.5px);
  z-index: 1;
  display: block;
  width: 100px;
  height: 2px;
  background: var(--accent);
  transform-origin: 0 50%;
  pointer-events: none;
  will-change: transform;
}

.timeline.is-pinned .tl-traveler {
  position: absolute;
  left: -6px;
  bottom: calc(var(--label-h) - 6.5px);
  z-index: 2;
  display: block;
  width: 12px;
  height: 12px;
  pointer-events: none;
  will-change: transform;
}

.tl-traveler::before,
.tl-traveler::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
}

.tl-traveler::before {
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--bg);
}

.tl-traveler::after {
  border: 1px solid var(--accent);
  opacity: 0;
}

/* Touchdown on a stop: a quick squash and a ring that spreads out. */
.tl-traveler.is-landing::before {
  animation: tl-land 0.5s var(--ease-out);
}

.tl-traveler.is-landing::after {
  animation: tl-ring 0.7s var(--ease-out);
}

/* Same pulse under a second name: script.js alternates the two classes so a
   new landing restarts it without forcing a layout. */
.tl-traveler.is-landing-b::before {
  animation: tl-land-b 0.5s var(--ease-out);
}

.tl-traveler.is-landing-b::after {
  animation: tl-ring-b 0.7s var(--ease-out);
}

@keyframes tl-land {
  0% {
    transform: scale(1);
  }
  35% {
    transform: scale(1.45);
  }
  100% {
    transform: scale(1);
  }
}

@keyframes tl-ring {
  0% {
    opacity: 0.55;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(3.2);
  }
}

@keyframes tl-land-b {
  0% {
    transform: scale(1);
  }
  35% {
    transform: scale(1.45);
  }
  100% {
    transform: scale(1);
  }
}

@keyframes tl-ring-b {
  0% {
    opacity: 0.55;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(3.2);
  }
}

.timeline.is-pinned .stop-title {
  opacity: calc(0.35 + 0.65 * var(--a));
  transition: opacity 0.3s ease;
}

.timeline.is-pinned .stop-short,
.timeline.is-pinned .stop-more {
  opacity: calc((var(--a) - 0.45) * 2);
  transform: translateY(calc((1 - var(--a)) * 0.5rem));
  transition:
    opacity 0.3s ease,
    transform 0.4s var(--ease-out);
}

/* Hover (mouse) or keyboard focus brings a stop's text up wherever it is. */
.timeline.is-pinned .stop.is-hover > *,
.timeline.is-pinned .stop:focus-within > * {
  --a: 1;
}

/* While the page is scrolling, script.js writes --a every frame: the text
   follows the scroll directly. Transitions here would restart each frame
   and trail behind the finger, so they only play for hover and focus. */
.timeline.is-scrolling .stop-title,
.timeline.is-scrolling .stop-short,
.timeline.is-scrolling .stop-more,
.timeline.is-scrolling .stop-body::before {
  transition: none;
}

.timeline.is-pinned .stop-mark {
  position: absolute;
  inset: -0.9rem -0.5rem 0;
  z-index: 1;
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.timeline.is-pinned .stop-mark:focus-visible {
  outline-offset: -2px;
}

/* Full story: the back of the top print. script.js lays it exactly over the
   print on the pile (--card-w/--card-h, measured) and turns both over
   together: the photo side on the pile rotates away while this side rotates
   in. It may grow a little taller (up to --back-max, the free space above the
   pile); a long story scrolls inside it. */
.full-company,
.full-head,
.full-foot {
  display: none;
}

.timeline.is-pinned .stop-full {
  --flip: 0.45s cubic-bezier(0.45, 0.05, 0.25, 1);
  position: absolute;
  bottom: calc(100% + var(--photo-gap));
  left: 50%;
  z-index: 3;
  display: flex;
  flex-direction: column;
  width: var(--card-w, 18rem);
  min-height: var(--card-h, 22rem);
  max-height: var(--back-max, 22rem);
  margin-left: calc(var(--card-w, 18rem) / -2);
  background: var(--print);
  border: 1px solid var(--print-edge);
  box-shadow: var(--print-shadow);
  color: var(--ink);
  text-align: left;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  transform: perspective(2200px) rotateY(-180deg);
  visibility: hidden;
  transition:
    transform var(--flip),
    visibility 0s linear 0.45s;
}

.timeline.is-pinned .stop.is-open .stop-full {
  transform: perspective(2200px) rotateY(0deg);
  visibility: visible;
  transition:
    transform var(--flip),
    visibility 0s;
}

/* Scrolled away: the back leaves at once (the track is moving it). */
.timeline.is-pinned .stop.is-quick .stop-full {
  transition: none;
}

.timeline.is-pinned .full-text {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: calc(var(--mat) + 0.5rem) calc(var(--mat) + 0.4rem) 0.75rem;
  font-size: 0.875rem;
  line-height: 1.5;
}

.timeline.is-pinned .full-text:focus {
  outline: none;
}

.timeline.is-pinned .full-text:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: -2px;
}

.timeline.is-pinned .full-head {
  display: block;
  margin: 0 0 0.6rem;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

/* Work stops: the company, above the role on the back too. */
.timeline.is-pinned .full-company {
  display: block;
  margin: 0 0 0.3rem;
  color: var(--muted);
  font-family: var(--font-mono);
  /* Scales down with a smaller print, like the front's company line. */
  font-size: clamp(0.6rem, calc(var(--card-w, 22rem) * 0.05), 0.6875rem);
  line-height: 1.3;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  overflow-wrap: break-word;
}

/* More to read below: the bottom edge fades out until you scroll to the end. */
.timeline.is-pinned .full-text.has-more {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 2.5rem), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 2.5rem), transparent);
}

/* The mat's bottom margin: the stop's type, like the front's caption, and Close. */
.timeline.is-pinned .full-foot {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  min-height: max(var(--mat-foot), 1.75rem);
  padding: 0 calc(var(--mat) - 0.25rem) 0 var(--mat);
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.full-close {
  align-self: stretch;
  min-width: 2.75rem;
  padding: 0 0.25rem;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  text-decoration-color: var(--line-strong);
}

.full-close:hover {
  text-decoration-color: currentColor;
}

.full-close:focus-visible {
  outline-color: var(--ink);
  outline-offset: -2px;
}

/* ---------- The rig: a pile of prints and the arm that deals them ----------
   Pinned layout only. script.js moves each stop's print into a card here and
   builds the arm (an inline SVG). Per frame it only writes transforms (and a
   shadow's opacity): the arm's joints, the card in the gripper, and the cards
   below it settling when a new one lands. */
.tl-rig {
  display: none;
}

.timeline.is-pinned .tl-rig {
  --mat: 12px;
  --mat-foot: calc(var(--mat) * 3);
  grid-row: 2;
  grid-column: 1;
  position: relative;
  z-index: 0;
  display: block;
  min-height: 0;
  pointer-events: none;
}

/* Where the top print lies: centered above the dot, the size the old pop-up
   print had. Never shown; script.js measures it. */
.rig-frame {
  position: absolute;
  left: 50%;
  bottom: calc(var(--label-h) + var(--photo-gap));
  height: min(calc(100% - var(--label-h) - var(--photo-gap) - var(--pile-room)), calc(var(--slot) * 0.86));
  max-width: calc(var(--slot) * 0.72);
  aspect-ratio: 4 / 5;
  transform: translateX(-50%);
  visibility: hidden;
}

.rig-cards {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.rig-card,
.rig-supply {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  will-change: transform;
}

.rig-card {
  perspective: 2200px;
  visibility: hidden;
}

.rig-flip {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}

.rig-card .stop-photo {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  /* Turning over for the full story (a class toggle, never per frame). */
  transition: transform 0.45s cubic-bezier(0.45, 0.05, 0.25, 1);
}

.rig-card.is-turned .stop-photo {
  transform: rotateY(180deg);
}

.rig-card.is-quick .stop-photo {
  transition-duration: 0.18s;
}

.rig-card.is-snap .stop-photo {
  transition: none;
}

/* A blank card back: the mat, a hairline window and a small registration
   mark. The supply stack is made of these. */
.rig-back {
  position: absolute;
  inset: 0;
  background: var(--print);
  border: 1px solid var(--print-edge);
  box-shadow: var(--print-shadow);
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  transform: rotateX(180deg);
}

.rig-back::before {
  content: '';
  position: absolute;
  inset: var(--mat-foot) var(--mat) var(--mat);
  border: 1px solid var(--line);
}

.rig-back::after {
  content: '';
  position: absolute;
  top: calc(50% + var(--mat) - 9px);
  left: calc(50% - 9px);
  width: 18px;
  height: 18px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background:
    linear-gradient(var(--line-strong), var(--line-strong)) center / 1px 100% no-repeat,
    linear-gradient(var(--line-strong), var(--line-strong)) center / 100% 1px no-repeat;
}

.rig-supply .rig-back {
  transform: none;
}

.rig-supply .rig-back:first-child {
  transform: translate(-3px, 4px) rotate(-2deg);
}

.rig-shadow {
  position: absolute;
  inset: 0;
  box-shadow: var(--print-lift);
  opacity: 0;
}

.rig-arm {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  overflow: visible;
  color: var(--ink);
  opacity: 0;
}

.rig-arm .rig-fill {
  fill: var(--bg);
}

.rig-arm .rig-line {
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.rig-arm .rig-center {
  fill: none;
  stroke: currentColor;
  stroke-width: 0.75;
  stroke-dasharray: 10 3 2 3;
  opacity: 0.4;
}

.rig-arm .rig-dot {
  fill: currentColor;
}

/* Stage footer: scroll hint, progress line, counter. */
.timeline.is-pinned .tl-foot {
  grid-row: 3;
  display: grid;
  grid-template-columns: 5rem 1fr 5rem;
  align-items: center;
  gap: 1.25rem;
  /* Air between the stop's text and the progress line; less on a short window. */
  padding: clamp(1.25rem, 6svh - 0.6rem, 2.5rem) var(--gutter) 1.1rem;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

.tl-hint {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  transition: opacity 0.4s ease;
}

.tl-hint::after {
  content: '';
  width: 1.25rem;
  height: 1px;
  background: currentColor;
  animation: nudge 1.8s ease-in-out infinite;
}

@keyframes nudge {
  0%,
  100% {
    transform: translateX(0);
  }
  50% {
    transform: translateX(0.35rem);
  }
}

.timeline.is-scrolled .tl-hint {
  opacity: 0;
}

.tl-progress {
  position: relative;
  height: 2px;
  border-radius: 1px;
  background: var(--line);
  overflow: hidden;
}

.tl-progress-fill {
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform-origin: 0 50%;
  transform: scaleX(0);
}

.tl-count {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

/* ---------- Below the timeline ---------- */
.below {
  max-width: var(--page);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.below > section {
  padding: 4.5rem 0 0;
}

.below > section:first-child {
  padding-top: 3.5rem;
}

.hobbies {
  border-bottom: 1px solid var(--line);
  padding-bottom: 3rem !important;
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.chip {
  position: relative;
  padding: 0.3rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 0.875rem;
  transition: border-color 0.2s ease;
}

.chip.has-pop {
  padding: 0;
}

.chip-btn {
  padding: 0.3rem 0.85rem;
  border: 0;
  border-radius: 999px;
  background: none;
  cursor: pointer;
}

.chip.has-pop:has(.chip-btn:focus-visible),
.chip.is-open {
  border-color: var(--ink);
}

@media (hover: hover) {
  .chip.has-pop:hover {
    border-color: var(--ink);
  }
}

.chip-pop {
  position: absolute;
  bottom: calc(100% + 0.6rem);
  left: 50%;
  z-index: 5;
  display: block;
  width: 11rem;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--bg);
  pointer-events: none;
  visibility: hidden;
  transform-origin: 50% 100%;
  transform: translate(calc(-50% + var(--shift, 0px)), 1rem) scale(0.6);
  clip-path: inset(100% 0 0 0);
  transition:
    transform 0.45s var(--ease-out),
    clip-path 0.45s var(--ease-out),
    visibility 0s linear 0.45s;
}

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

.chip-pop .photo-hint {
  background: var(--bg);
}

/* Touch screens keep :hover after a tap, so hover only counts with a real
   pointer; taps go through .is-open (script.js), and keyboard focus shows it. */
.chip-btn:focus-visible + .chip-pop,
.chip.is-open .chip-pop {
  visibility: visible;
  transform: translate(calc(-50% + var(--shift, 0px)), 0) scale(1);
  clip-path: inset(0 0 0 0);
  transition:
    transform 0.45s var(--ease-out),
    clip-path 0.45s var(--ease-out);
}

@media (hover: hover) {
  .chip:hover .chip-pop {
    visibility: visible;
    transform: translate(calc(-50% + var(--shift, 0px)), 0) scale(1);
    clip-path: inset(0 0 0 0);
    transition:
      transform 0.45s var(--ease-out),
      clip-path 0.45s var(--ease-out);
  }
}

/* ---------- Experience (Work view) ---------- */
.experience h2 {
  margin-bottom: 1.5rem;
  font-size: clamp(1.5rem, 3vw, 2rem);
}

.jobs {
  margin: 0;
  padding: 0;
  list-style: none;
}

.job {
  border-top: 1px solid var(--line);
}

.job:last-child {
  border-bottom: 1px solid var(--line);
}

.job summary {
  display: grid;
  grid-template-columns: 7.5rem 1fr auto;
  grid-template-areas:
    'date title icon'
    '.    meta  icon';
  align-items: start;
  column-gap: 1rem;
  padding: 1.1rem 0;
  cursor: pointer;
  list-style: none;
}

.job summary::-webkit-details-marker {
  display: none;
}

.job summary::marker {
  content: '';
}

.job-head {
  display: contents;
}

.job-date {
  grid-area: date;
  padding-top: 0.2rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.job-title {
  grid-area: title;
  font-weight: 600;
}

.job-meta {
  grid-area: meta;
  color: var(--muted);
  font-size: 0.9375rem;
}

.job-icon {
  grid-area: icon;
  width: 0.8rem;
  height: 0.8rem;
  margin-top: 0.45rem;
  color: var(--muted);
  background:
    linear-gradient(currentColor, currentColor) center / 100% 1px no-repeat,
    linear-gradient(currentColor, currentColor) center / 1px 100% no-repeat;
}

.job summary:hover .job-icon {
  color: var(--ink);
}

.job details[open] .job-icon {
  color: var(--ink);
  background: linear-gradient(currentColor, currentColor) center / 100% 1px no-repeat;
}

.job-points {
  margin: 0;
  padding: 0 2rem 1.4rem calc(7.5rem + 1rem + 1rem);
}

.job-points li {
  margin-bottom: 0.45rem;
}

.job-points li::marker {
  color: var(--muted);
}

.job details[open] .job-points {
  animation: fade-in 0.25s ease-out;
}

@media (max-width: 34rem) {
  .job summary {
    grid-template-columns: 1fr auto;
    grid-template-areas: 'head icon';
  }

  .job-head {
    display: flex;
    flex-direction: column;
    grid-area: head;
  }

  .job-date {
    order: -1;
    padding: 0 0 0.2rem;
  }

  .job-points {
    padding: 0 0 1.25rem 1.1rem;
  }
}

/* ---------- Lab page (projects and research) ---------- */
.projects-section {
  max-width: var(--page);
  margin: 0 auto;
  padding: 3.5rem var(--gutter) 0;
}

.projects-head {
  margin-bottom: 2.25rem;
}

.projects-head h1 {
  font-size: clamp(1.9rem, 5vw, 2.75rem);
  letter-spacing: -0.025em;
}

.projects-lede {
  margin: 0.6rem 0 0;
  color: var(--muted);
}

/* One column on phones, two from tablets up, three on very wide screens. */
.projects {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.75rem;
}

@media (min-width: 40rem) {
  .projects {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2rem 1.75rem;
  }
}

@media (min-width: 100rem) {
  .projects-section,
  .page-lab .below,
  .page-lab .footer {
    max-width: 84rem;
  }

  .projects {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* Each project is a print, like the timeline's: an even mat with a hairline
   edge and a soft resting shadow; the photo sits in a clipped window and the
   text is written on the mat below it. */
.project {
  --mat: 12px;
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--mat);
  background: var(--print);
  border: 1px solid var(--print-edge);
  box-shadow: var(--print-shadow);
}

/* The lifted shadow lives on its own layer; only its opacity changes. */
.project::after {
  content: '';
  position: absolute;
  inset: -1px;
  z-index: -1;
  box-shadow: var(--print-lift);
  opacity: 0;
  pointer-events: none;
}

.project-photo {
  margin: 0;
}

.project-window {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--line);
}

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

.project-photo.has-photo .project-window::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.5 0 0 0 0 0.5 0 0 0 0 0.5 0 0 0 1.6 -0.55'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: 0.35;
  mix-blend-mode: overlay;
  pointer-events: none;
}

.project-photo.is-missing img {
  display: none;
}

.project-photo.is-missing .project-window {
  background: none;
}

/* Live site without a photo: the card is just its text. */
.project.no-photo .project-photo {
  display: none;
}

.project-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  padding: 1rem calc(var(--mat) * 0.5) calc(var(--mat) * 0.25);
}

.project.no-photo .project-body {
  padding-top: calc(var(--mat) * 0.75);
}

.project-title {
  font-size: 1.125rem;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.project-desc {
  margin: 0.4rem 0 0;
  color: var(--muted);
  font-size: 0.9375rem;
  line-height: 1.45;
}

.project-meta {
  margin: auto 0 0;
  padding-top: 0.9rem;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  line-height: 1.5;
  text-transform: uppercase;
}

/* Project or Research: inked, like the timeline's type label. */
.project-type {
  color: var(--ink);
  letter-spacing: 0.08em;
}

.project-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.1rem;
  margin: 0.55rem 0 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.project-links a {
  padding: 0.15rem 0;
}

/* Cards stay black and white: no accent on hover or focus inside them. */
.project-links a:hover {
  text-decoration-color: currentColor;
}

.project-links a:focus-visible {
  outline-color: var(--ink);
  outline-offset: 2px;
}

/* A slight lift on hover (mouse only) or when a link inside has keyboard focus. */
@media (prefers-reduced-motion: no-preference) {
  .project {
    transition: transform var(--t-med) var(--ease-out);
  }

  .project::after {
    transition: opacity var(--t-med) var(--ease-out);
  }

  .project:has(:focus-visible) {
    transform: translateY(-3px);
  }

  .project:has(:focus-visible)::after {
    opacity: 0.6;
  }
}

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .project:hover {
    transform: translateY(-3px);
  }

  .project:hover::after {
    opacity: 0.6;
  }
}

.page-lab .below > section:first-child {
  padding-top: 4.5rem;
}

/* ---------- Closing + footer ---------- */
/* The Contact link lands here: the section's top tucks under the top bar
   (its own top padding is the gap), and it's at least tall enough, with the
   footer, to scroll all the way up there even at the end of the page. */
.closing {
  padding-bottom: 2rem;
  min-height: calc(100svh - var(--bar) - 8rem);
  scroll-margin-top: var(--bar);
}

.closing:focus {
  outline: none;
}

.mantra {
  margin: 0 0 2rem;
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 6vw, 3.25rem);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.025em;
  color: var(--line-strong);
}

.mantra span {
  display: block;
  transition: color 0.3s ease;
}

.mantra span:hover {
  color: var(--ink);
}

.closing-mail {
  color: var(--muted);
}

.closing-mail a {
  color: var(--ink);
}

.closing .links {
  margin-top: 1.25rem;
}

.footer {
  max-width: var(--page);
  margin: 4rem auto 0;
  padding: 1.25rem var(--gutter) 2rem;
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.footer p {
  margin: 0;
}

/* Work view: no timeline, so the intro is just the page header. */
html[data-view='work'] .intro,
html[data-view='work'] .hero.is-pinned .intro {
  position: static;
  width: 100%;
  max-width: var(--page);
  margin: 0 auto;
  padding-top: 3.5rem;
  pointer-events: auto;
}

html[data-view='work'] .experience {
  padding-top: 2rem;
}

/* ---------- Small screens ---------- */
@media (max-width: 40rem) {
  .timeline.is-pinned {
    --slot: 78vw;
    --label-h: 12.25rem;
    --photo-gap: 1.1rem;
  }

  /* The blank supply and the arm sit above the pile on phones, so the pile
     leaves them about a tenth of its height, plus a little air. */
  .rig-frame {
    height: min(calc((100% - var(--label-h) - var(--photo-gap) - 1rem) / 1.1), calc(var(--slot) * 0.95));
    max-width: calc(var(--slot) * 0.76);
  }

  /* Phone prints: a touch slimmer still, so "Sorenson Communications"
     stays on one line. */
  .tl-rig .photo-card {
    padding: clamp(0.6rem, calc(var(--card-w, 22rem) * 0.05), 0.9rem);
  }

  .tl-rig .photo-card-company {
    letter-spacing: 0.03em;
  }

  .timeline.is-pinned .full-company {
    letter-spacing: 0.04em;
  }

  .timeline.is-pinned .stop-body {
    width: calc(var(--slot) - 1rem);
  }

  .stop,
  .tl-rig {
    --mat: 9px;
  }

  .timeline.is-pinned .full-text {
    font-size: 0.8125rem;
  }

  .timeline.is-pinned .full-head {
    font-size: 0.9375rem;
  }

  .timeline.is-pinned .tl-foot {
    grid-template-columns: 4rem 1fr 4rem;
    gap: 0.9rem;
  }

  .intro {
    padding-top: 1.25rem;
    padding-bottom: 1rem;
  }

  .intro-now {
    margin-bottom: 0.6rem;
    font-size: 0.8125rem;
  }

  .topbar-name {
    font-size: 0.6875rem;
  }
}

/* Phones: name, Contact, the view switch and the theme toggle all
   share one line, so the small caps get a touch smaller and tighter. */
@media (max-width: 26rem) {
  .topbar {
    gap: 0.5rem;
  }

  .topbar-tools {
    gap: 0.35rem;
  }

  .topbar-name {
    font-size: 0.625rem;
    letter-spacing: 0.03em;
  }

  .topbar-link {
    padding: 0.4rem 0.1rem;
    font-size: 0.625rem;
    letter-spacing: 0.02em;
  }

  .view-switch button {
    padding: 0.2rem 0.4rem;
    font-size: 0.625rem;
    letter-spacing: 0.02em;
  }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
}
