/* =================================================================
   Anatoly Kataev — portfolio
   ================================================================= */

:root {
  --bg:        #0A0A0B;
  --bg-2:      #121215;
  --bg-3:      #191920;
  --line:      #26262C;
  --line-soft: #1C1C22;
  --line-ui:   #5A5A64;   /* 3:1 against --bg — for control borders */
  --fg:        #F3F3F1;
  --fg-2:      #A4A49E;
  --fg-3:      #83837D;   /* 5.0:1 against --bg */
  /* the accent is plain white: numbers, markers, the progress line,
     hovers and focus. Text set on it is near-black. The only colour on the
     site is each project's brand colour, on its problem slide (see
     "coloured slides" below). */
  --accent:    #F3F3F1;
  --accent-dim:#F3F3F1;
  --on-accent: #0A0A0B;

  --ff-display: 'Inter Tight', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --ff-body:    'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --ff-mono:    'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  --pad:  clamp(20px, 5vw, 88px);
  --padY: clamp(52px, 7vh, 96px);
  --rail: 56px;
  --ease: cubic-bezier(.22,.61,.36,1);
}

* { box-sizing: border-box; }
html, body, figure, figcaption, dl, dd { margin: 0; padding: 0; }

html { background: var(--bg); -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--ff-body);
  background: var(--bg);
  color: var(--fg);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow: hidden;
}

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

::selection { background: var(--accent); color: var(--on-accent); }

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

.skip {
  position: fixed; top: 10px; left: 10px; z-index: 100;
  background: var(--accent); color: var(--on-accent); font-weight: 500;
  padding: 10px 16px; border-radius: 6px; text-decoration: none;
  transform: translateY(-160%); transition: transform .2s var(--ease);
}
.skip:focus { transform: none; }

/* ---------------------------------------------------------------- deck */
.deck {
  height: 100dvh;
  overflow-y: scroll;
  overflow-x: hidden;
  scroll-snap-type: y mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
}
.deck::-webkit-scrollbar { display: none; }

.slide {
  position: relative;
  min-height: 100dvh;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* the header is fixed and ~60px tall; a short viewport shrinks --padY
     below that, so the top padding has its own floor */
  padding: max(var(--padY), 76px) var(--pad) var(--padY) calc(var(--pad) + var(--rail));
  border-bottom: 1px solid var(--line-soft);
  isolation: isolate;
}
.slide > * { width: 100%; }

.slide-inner { max-width: 1520px; margin: 0 auto; width: 100%; }

/* ------------------------------------------------------------ chrome */
.chrome {
  position: fixed; inset: 0 0 auto 0; z-index: 60;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px;
  padding: 18px var(--pad) 18px calc(var(--pad) + var(--rail));
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(10,10,11,.9), rgba(10,10,11,0));
}
.chrome > * { pointer-events: auto; }

.wordmark {
  font-family: var(--ff-display);
  font-weight: 600; font-size: 15px; letter-spacing: -.01em;
  text-decoration: none; display: flex; align-items: center;
  /* a finger needs more than the cap height of the word */
  min-height: 44px; padding-right: 10px;
}
.chrome-right { display: flex; align-items: center; gap: 18px; }

.now-showing {
  font-family: var(--ff-mono); font-size: 11px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--fg-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 44vw;
  transition: color .3s var(--ease);
}
.now-showing b { color: var(--fg-2); font-weight: 500; }

.menu-btn {
  font-family: var(--ff-mono); font-size: 11px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--fg-2);
  background: transparent; border: 1px solid var(--line-ui);
  border-radius: 999px; padding: 7px 15px; cursor: pointer;
  transition: border-color .35s var(--ease), color .35s var(--ease);
}
.menu-btn:hover { border-color: var(--fg-3); color: var(--fg); }

/* --------------------------------------------------------- side rail */
.rail {
  position: fixed; z-index: 55;
  left: 0; top: 0; bottom: 0; width: calc(var(--pad) + var(--rail));
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; pointer-events: none;
}
.rail-item {
  pointer-events: auto; position: relative;
  width: 22px; height: 8px; border: 0; background: transparent;
  cursor: pointer; padding: 0;
  display: flex; align-items: center; justify-content: center;
}
/* A finger cannot usefully hit a 22×8 mark, and there is no room to grow one
   without widening the rail. On a touch screen it stays as a position
   indicator and navigation goes through Index. */
@media (pointer: coarse) {
  .rail { pointer-events: none; }
  .rail-item { pointer-events: none; cursor: default; }
}
.rail-item::after {
  content: ''; width: 14px; height: 2px; border-radius: 2px;
  background: var(--line); transition: all .3s var(--ease);
}
.rail-item:hover::after { background: var(--fg-3); width: 18px; }
.rail-item.is-active::after { background: var(--accent); width: 22px; }
.rail-item.is-lead::after { width: 20px; background: var(--fg-3); }
.rail-item.is-lead.is-active::after { background: var(--accent); }
.rail-item .tip {
  position: absolute; left: 30px; white-space: nowrap;
  font-family: var(--ff-mono); font-size: 10px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--on-accent);
  background: var(--accent); border: 1px solid var(--accent);
  padding: 4px 9px; border-radius: 5px;
  opacity: 0; transform: translateX(-4px); transition: all .2s var(--ease);
  pointer-events: none;
}
.rail-item:hover .tip { opacity: 1; transform: none; }

/* -------------------------------------------------------- progress */
.progress {
  position: fixed; left: 0; bottom: 0; height: 2px; z-index: 60;
  background: var(--accent); width: 0; transition: width .18s linear, background-color .35s var(--ease);
}

/* ------------------------------------------------------------ menu */
.menu {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(10,10,11,.96);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  display: grid; place-items: center;
  opacity: 0; visibility: hidden;
  transition: opacity .3s var(--ease), visibility 0s linear .3s;
  padding: var(--pad);
}
.menu.is-open {
  opacity: 1; visibility: visible;
  transition: opacity .3s var(--ease), visibility 0s linear 0s;
}
.menu-inner {
  width: min(900px, 100%);
  max-height: calc(100dvh - 110px); overflow-y: auto; scrollbar-width: none;
}
.menu-inner::-webkit-scrollbar { display: none; }
.menu h2 {
  font-family: var(--ff-mono); font-size: 11px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--fg-3); margin: 0 0 22px;
}
.menu ol { list-style: none; margin: 0 0 30px; padding: 0; }
.menu li { border-top: 1px solid var(--line-soft); }
.menu li:last-child { border-bottom: 1px solid var(--line-soft); }
.menu a {
  display: flex; align-items: baseline; gap: 18px;
  padding: 10px 4px; text-decoration: none;
  transition: padding .25s var(--ease), background .25s var(--ease);
}
.menu a:hover { padding-left: 14px; background: rgba(255,255,255,.02); }
.menu .m-n { font-family: var(--ff-mono); font-size: 11px; color: var(--fg-3); width: 26px; flex: none; }
.menu .m-name { font-family: var(--ff-display); font-size: clamp(19px, 2.3vw, 26px); font-weight: 600; letter-spacing: -.02em; }
.menu .m-tag { color: var(--fg-3); font-size: 13px; margin-left: auto; text-align: right; }
.menu-close {
  position: fixed; top: 18px; right: var(--pad);
  background: transparent; border: 1px solid var(--line-ui); color: var(--fg-2);
  border-radius: 999px; padding: 7px 15px; cursor: pointer;
  font-family: var(--ff-mono); font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
}

/* ----------------------------------------------------- type helpers */
.eyebrow {
  font-family: var(--ff-mono); font-size: 11px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--fg-3);
  display: flex; align-items: center; gap: 10px; margin: 0 0 22px;
}

h1, h2, h3, h4 { font-family: var(--ff-display); font-weight: 600; letter-spacing: -.028em; margin: 0; }

.display {
  font-size: clamp(38px, 7.4vw, 108px);
  line-height: .96; letter-spacing: -.038em; word-spacing: .06em; font-weight: 600;
}
.display .d-line { display: block; }
/* small phones: shrink just enough that each headline line keeps to one line */
@media (max-width: 420px) { .display { font-size: min(38px, calc((100vw - 40px) / 9.2)); } }
.display .muted { color: var(--fg-3); }

.h-sec { font-size: clamp(28px, 4.2vw, 56px); line-height: 1.02; }
.h-sub { font-size: clamp(20px, 2.3vw, 30px); line-height: 1.18; }

.lede {
  font-size: clamp(16px, 1.35vw, 20px); line-height: 1.55;
  color: var(--fg-2); max-width: 62ch;
}
.body-col p { color: var(--fg-2); max-width: 58ch; margin: 0 0 15px; font-size: 15.5px; line-height: 1.68; }
.body-col p:last-child { margin-bottom: 0; }

/* ----------------------------------------------------------- intro */
.s-intro .slide-inner {
  display: flex; flex-direction: column; justify-content: space-between;
  min-height: calc(100dvh - max(var(--padY), 76px) - var(--padY));
}
.intro-top { flex: 1; display: flex; flex-direction: column; justify-content: center; }
.intro-headline { margin: 0 0 clamp(24px, 3vw, 40px); }
.intro-grid { display: grid; grid-template-columns: minmax(0,1fr); }
/* a blank line typed into the paragraph in the editor shows as one */
.intro-grid .lede { white-space: pre-line; }
.intro-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; flex-wrap: wrap;
  padding-top: 22px; border-top: 1px solid var(--line-soft);
}
.scroll-cue {
  font-family: var(--ff-mono); font-size: 11px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--fg-3);
  display: flex; align-items: center; gap: 10px;
}
.scroll-cue .arrow { animation: bob 2.4s var(--ease) infinite; }
@keyframes bob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(4px); } }
.quick-links { display: flex; gap: 6px 18px; flex-wrap: wrap; align-items: center; }
.quick-links a {
  font-family: var(--ff-mono); font-size: 11px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--fg-3); text-decoration: none;
  transition: color .22s var(--ease);
  display: inline-flex; align-items: center; min-height: 44px;
}
.quick-links a:hover { color: var(--accent); }

/* ----------------------------------------------------------- about */
.two-col {
  display: grid; grid-template-columns: minmax(0, .82fr) minmax(0, 1.18fr);
  gap: clamp(28px, 5vw, 80px); align-items: start;
}
.facts { list-style: none; margin: 26px 0 0; padding: 0; }
.facts li {
  display: grid; grid-template-columns: 96px 1fr; gap: 14px;
  padding: 11px 0; border-top: 1px solid var(--line-soft);
  font-size: 14px;
}
.facts .k {
  font-family: var(--ff-mono); font-size: 10.5px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--fg-3); padding-top: 3px;
}
.facts .v { color: var(--fg-2); }

.about-portrait {
  width: 100%; max-width: 260px; aspect-ratio: 1; border-radius: 50%;
  overflow: hidden; border: 1px solid var(--line); margin-bottom: 26px;
}
.about-portrait img { width: 100%; height: 100%; object-fit: cover; }

/* -------------------------------------------------------- approach */
.steps { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 1px; background: var(--line-soft); margin-top: 34px; }
.step { background: var(--bg); padding: 22px clamp(14px,1.6vw,24px); }
.step .n { font-family: var(--ff-mono); font-size: 11px; color: var(--accent); letter-spacing: .08em; }
.step h3 { font-size: 16.5px; margin: 9px 0 8px; letter-spacing: -.004em; line-height: 1.3; }
.step p { margin: 0; color: var(--fg-3); font-size: 13.5px; line-height: 1.58; }

.collab { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 16px 28px; margin-top: 30px; }
.collab div { border-top: 1px solid var(--line-soft); padding-top: 11px; }
.collab b {
  display: block; font-family: var(--ff-mono); font-size: 10.5px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--accent-dim);
  font-weight: 500; margin-bottom: 5px;
}
.collab span { color: var(--fg-3); font-size: 13px; line-height: 1.5; }

/* ----------------------------------------------------- work index */
.work-list { list-style: none; margin: 30px 0 0; padding: 0; }
.work-list li { border-top: 1px solid var(--line-soft); }
.work-list li:last-child { border-bottom: 1px solid var(--line-soft); }
.work-row {
  display: grid;
  /* fractional tracks only, so the tag and year columns line up down the list */
  grid-template-columns: 44px minmax(0,1fr) minmax(0,.9fr) minmax(0,.5fr);
  gap: clamp(12px, 2.4vw, 34px); align-items: baseline;
  padding: clamp(13px, 1.7vw, 22px) 6px; width: 100%;
  background: transparent; border: 0; color: inherit; cursor: pointer;
  text-align: left; font: inherit;
  transition: padding .3s var(--ease), background .3s var(--ease);
}
.work-row:hover { padding-left: 18px; background: rgba(255,255,255,.022); }
.work-row .w-n { font-family: var(--ff-mono); font-size: 11px; color: var(--fg-3); }
.work-row:hover .w-n { color: var(--accent); }
.work-row .w-name { font-family: var(--ff-display); font-size: clamp(22px, 3.1vw, 40px); font-weight: 600; letter-spacing: -.03em; line-height: 1; }
.work-row .w-tag { color: var(--fg-3); font-size: 14px; }
.work-row .w-year { font-family: var(--ff-mono); font-size: 11px; color: var(--fg-3); white-space: nowrap; text-align: right; }

/* ------------------------------------------------------ case cover */
.cover-grid { display: grid; gap: clamp(26px, 4vw, 54px); }
.cover-head { display: flex; align-items: flex-start; gap: clamp(16px, 3vw, 40px); }
.cover-n {
  font-family: var(--ff-mono); font-size: 12px; color: var(--fg-3);
  padding-top: clamp(8px, 1.2vw, 18px); flex: none;
}
.cover-title { font-size: clamp(44px, 9vw, 132px); line-height: .9; letter-spacing: -.045em; }
.cover-tag {
  font-family: var(--ff-mono); font-size: 12px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--fg-3); margin-top: 14px;
}
.cover-headline { font-size: clamp(19px, 2.3vw, 31px); line-height: 1.28; max-width: 26ch; font-family: var(--ff-display); font-weight: 500; letter-spacing: -.022em; }
.meta-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 0; border-top: 1px solid var(--line-soft);
}
/* a cell draws its own rule, so an incomplete last row leaves no phantom block */
.meta-grid div {
  padding: 15px clamp(16px, 2vw, 30px) 16px 0;
  border-bottom: 1px solid var(--line-soft);
}
.meta-grid dt {
  font-family: var(--ff-mono); font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--fg-3); margin-bottom: 6px;
}
.meta-grid dd { margin: 0; font-size: 13.5px; color: var(--fg); line-height: 1.45; }

/* --------------------------------------------------------- HMW */
.s-hmw .hmw-q {
  font-family: var(--ff-display); font-weight: 500;
  font-size: clamp(26px, 4.6vw, 62px); line-height: 1.08; letter-spacing: -.035em;
  max-width: 20ch;
}
.hmw-ctx { margin-top: clamp(24px, 3.4vw, 44px); max-width: 62ch; color: var(--fg-2); font-size: clamp(15px,1.25vw,18px); line-height: 1.66; }

/* the problem slides with a scene keep their copy to the left half, and the
   scene (js/scenes.js) takes the right; stacked, it sits under the copy */
.hmw-fx {
  position: absolute; top: 0; right: 0; bottom: 0; width: 42%;
  pointer-events: none; z-index: 0;
  opacity: 0; transition: opacity 1.2s var(--ease);
}
.hmw-fx.is-on { opacity: 1; }
.hmw-fx canvas { display: block; width: 100%; height: 100%; }
.s-hmw.has-fx .slide-inner { position: relative; z-index: 1; }
@media (min-width: 901px) {
  .s-hmw.has-fx .hmw-q { max-width: min(20ch, 46vw); }
  .s-hmw.has-fx .hmw-ctx { max-width: min(62ch, 46vw); }
}
@media (max-width: 900px) {
  .hmw-fx { position: relative; top: auto; right: auto; bottom: auto; width: 100%;
            height: min(50vh, 96vw); flex: none; margin-top: 12px; }
}

/* ---------------------------------------------------- story slides */
.story {
  display: grid; grid-template-columns: minmax(280px, .74fr) minmax(0, 1.26fr);
  gap: clamp(24px, 4vw, 68px); align-items: center;
}
.story.rev { grid-template-columns: minmax(0,1.26fr) minmax(280px,.74fr); }
.story.rev .story-text { order: 2; }
.story-text h3 { font-size: clamp(22px, 2.7vw, 36px); line-height: 1.08; margin-bottom: 16px; }

.stage { display: flex; align-items: center; justify-content: center; min-width: 0; }
.stage-grid { display: grid; gap: clamp(10px, 1.2vw, 20px); width: 100%; align-items: start; }
.stage-grid.cols-1 { grid-template-columns: 1fr; justify-items: center; }
.stage-grid.cols-1 > .shot { max-width: 1120px; }
.stage-grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.stage-grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
.stage-grid.cols-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1260px) { .stage-grid.cols-4 { grid-template-columns: repeat(2, 1fr); } }

/* wide-screen case studies: copy on top, screens full width beneath */
.story-v { display: flex; flex-direction: column; gap: clamp(20px, 2.6vw, 38px); }
.sv-head {
  display: grid; grid-template-columns: minmax(0,.72fr) minmax(0,1.28fr);
  gap: clamp(18px, 3.4vw, 56px); align-items: start;
}
.sv-head h3 { font-size: clamp(24px, 3vw, 40px); line-height: 1.04; }
.sv-head .body-col { columns: 2; column-gap: clamp(20px, 2.6vw, 42px); }
.sv-head .body-col p { max-width: none; break-inside: avoid; }
.stage-phones {
  display: flex; flex-wrap: wrap; row-gap: 22px;
  gap: clamp(10px, 1.4vw, 24px); justify-content: center; align-items: flex-start; width: 100%;
}
.stage-phones .shot { flex: 1 1 0; min-width: 0; max-width: 290px; }

.shot {
  position: relative; cursor: zoom-in; min-width: 0;
  display: flex; flex-direction: column; align-items: center;
}
.shot figcaption {
  font-size: 12px; color: var(--fg-3); line-height: 1.45; margin-top: 10px;
  font-family: var(--ff-body); text-align: center; max-width: 52ch;
}
/* wide frames hug their screenshot rather than stretching to the grid cell */
.frame-browser, .frame-plain { width: -moz-fit-content; width: fit-content; max-width: 100%; }
/* a phone fills its column — the column is already phone-shaped */
.frame-phone { width: 100%; }
/* a page taller than it is wide is shown as a viewport crop, not shrunk to a stamp */
.frame-browser img.tall, .frame-plain img.tall {
  aspect-ratio: 4 / 3; object-fit: cover; object-position: top center;
}

/* device framing */
.frame-browser {
  border-radius: 10px; overflow: hidden; background: var(--bg-3);
  border: 1px solid var(--line);
  box-shadow: 0 24px 60px -24px rgba(0,0,0,.9), 0 2px 10px rgba(0,0,0,.4);
  transition: transform .4s var(--ease), box-shadow .4s var(--ease);
}
.shot:hover .frame-browser { transform: translateY(-3px); box-shadow: 0 34px 70px -26px rgba(0,0,0,.95); }
.frame-browser .bar {
  height: 26px; display: flex; align-items: center; gap: 5px; padding: 0 10px;
  background: #1E1E24; border-bottom: 1px solid var(--line);
}
.frame-browser .bar i { width: 7px; height: 7px; border-radius: 50%; background: #34343C; }
.frame-browser img { width: 100%; height: auto; display: block; }

.frame-phone {
  border-radius: clamp(18px, 2.2vw, 30px); overflow: hidden;
  background: #18181C; padding: clamp(4px, .5vw, 7px);
  border: 1px solid var(--line);
  box-shadow: 0 22px 54px -22px rgba(0,0,0,.9);
  transition: transform .4s var(--ease);
}
.shot:hover .frame-phone { transform: translateY(-4px); }
.frame-phone img { width: 100%; height: auto; border-radius: clamp(14px, 1.8vw, 24px); display: block; }

.frame-plain {
  border-radius: 8px; overflow: hidden; border: 1px solid var(--line);
  background: var(--bg-2);
  box-shadow: 0 20px 50px -24px rgba(0,0,0,.85);
}
.frame-plain img { width: 100%; height: auto; }

/* cap media height so a slide stays within one screen */
.stage img { object-fit: contain; object-position: top; max-height: min(40vh, 460px); }
.stage-phones img { max-height: min(56vh, 660px); }
.stage-grid.n-1 img { max-height: min(62vh, 780px); }
.stage-grid.n-2 img { max-height: min(56vh, 660px); }
.stage-grid.n-3 img { max-height: min(42vh, 480px); }
.stage-grid.n-4 img { max-height: min(38vh, 440px); }

/* keep the grid roughly as wide as the frames it holds, so columns don't
   leave a gutter down the middle */
.stage-grid.n-2 { max-width: 1280px; margin-inline: auto; }
.stage-grid.n-3 { max-width: 1440px; margin-inline: auto; }

/* ---------------------------------------------------- canvas slide */
.canvas-wrap {
  border: 1px solid var(--line); border-radius: 10px; overflow: hidden;
  background: var(--bg-2); margin-top: 26px; cursor: zoom-in;
  box-shadow: 0 26px 60px -30px rgba(0,0,0,.9);
}
.canvas-wrap img { width: 100%; height: auto; max-height: 56vh; object-fit: cover; object-position: top; }
.canvas-head { display: grid; grid-template-columns: minmax(0,.8fr) minmax(0,1.2fr); gap: clamp(20px,4vw,60px); align-items: end; }

/* ---------------------------------------------------- impact slide */
.impact-list {
  display: grid; grid-template-columns: repeat(3, minmax(0,1fr));
  gap: 0; margin-top: 34px; border-top: 1px solid var(--line-soft);
}
.impact-list > div {
  padding: 22px clamp(16px,2vw,30px) 24px 0;
  border-bottom: 1px solid var(--line-soft);
}
.impact-list h4 { font-size: 17px; line-height: 1.24; margin-bottom: 10px; letter-spacing: -.02em; }
.impact-list p { margin: 0; color: var(--fg-3); font-size: 13.5px; line-height: 1.6; }

/* ------------------------------------------------------ experience */
.xp { list-style: none; margin: 26px 0 0; padding: 0; }
.xp li { border-top: 1px solid var(--line-soft); }
.xp li:last-child { border-bottom: 1px solid var(--line-soft); }
.xp-row {
  display: grid;
  /* every track is fractional: an `auto` track would size to each row's own
     content, so the columns would land in a different place on every line */
  grid-template-columns: minmax(0,.7fr) minmax(0,1fr) minmax(0,1.05fr) minmax(0,.8fr);
  gap: clamp(10px,2vw,28px); padding: 12px 4px; align-items: baseline;
}
.xp-co { font-family: var(--ff-display); font-weight: 600; font-size: 16px; letter-spacing: -.02em; }
.xp-role { color: var(--fg-2); font-size: 13.5px; }
.xp-when { font-family: var(--ff-mono); font-size: 11px; color: var(--fg-3); }
.xp-where { font-family: var(--ff-mono); font-size: 11px; color: var(--fg-3); text-align: right; white-space: nowrap; }

.tags { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 12px; }
.tag {
  font-family: var(--ff-mono); font-size: 10.5px; letter-spacing: .05em;
  color: var(--fg-3); border: 1px solid var(--line-soft);
  border-radius: 999px; padding: 4px 11px;
}

/* --------------------------------------------------------- contact */
.s-contact { justify-content: center; }
.contact-lede { max-width: 30ch; font-size: clamp(17px,1.6vw,23px); color: var(--fg); }
.mail {
  display: inline-block; text-decoration: none;
  font-family: var(--ff-display); font-weight: 600;
  font-size: clamp(26px, 6.4vw, 92px); line-height: 1; letter-spacing: -.045em;
  margin: 18px 0 30px; word-break: break-word; padding: 10px 0;
  background-image: linear-gradient(var(--accent), var(--accent));
  background-size: 0% 2px; background-position: 0 100%; background-repeat: no-repeat;
  transition: background-size .45s var(--ease), color .3s var(--ease);
}
.mail:hover { background-size: 100% 2px; }
.contact-links { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 8px; }
.contact-links a {
  text-decoration: none; border: 1px solid var(--line-ui);
  border-radius: 999px; padding: 9px 18px; font-size: 13px; color: var(--fg-2);
  transition: all .25s var(--ease);
}
.contact-links a:hover { border-color: var(--accent); color: var(--accent); }
.colophon { margin-top: clamp(40px,7vh,84px); padding-top: 20px; border-top: 1px solid var(--line-soft); color: var(--fg-3); font-size: 12.5px; display: flex; justify-content: space-between; gap: 18px; flex-wrap: wrap; }

/* ------------------------------------------------------- lightbox */
.lightbox {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(7,7,8,.985);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  display: grid; place-items: center; padding: clamp(16px,4vw,56px);
  opacity: 0; visibility: hidden;
  transition: opacity .28s var(--ease), visibility 0s linear .28s;
  cursor: zoom-out;
}
.lightbox.is-open {
  opacity: 1; visibility: visible;
  transition: opacity .28s var(--ease), visibility 0s linear 0s;
}
.lightbox img {
  max-width: 100%; max-height: 86vh; object-fit: contain;
  border-radius: 6px; box-shadow: 0 30px 90px rgba(0,0,0,.8);
}
.lightbox .lb-cap {
  position: absolute; left: 0; right: 0; bottom: clamp(14px,3vh,30px);
  text-align: center; color: var(--fg-3); font-size: 13px; padding: 0 20px;
}
.lightbox .lb-close {
  position: absolute; top: 18px; right: 20px; background: transparent;
  border: 1px solid var(--line-ui); color: var(--fg-2); border-radius: 999px;
  padding: 7px 15px; cursor: pointer;
  font-family: var(--ff-mono); font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
}

/* ------------------------------------------------------- reveals */
.rv { opacity: 0; transform: translateY(16px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
.slide.is-seen .rv { opacity: 1; transform: none; }
.slide.is-seen .rv:nth-child(2) { transition-delay: .06s; }
.slide.is-seen .rv:nth-child(3) { transition-delay: .12s; }
.slide.is-seen .rv:nth-child(4) { transition-delay: .18s; }

/* -------------------------------------------------------- hint */
.kbd-hint {
  position: fixed; right: var(--pad); bottom: 18px; z-index: 58;
  font-family: var(--ff-mono); font-size: 10px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--fg-3);
  opacity: 0; transition: opacity .5s var(--ease); pointer-events: none;
}
.kbd-hint.show { opacity: 1; }
.kbd-hint kbd {
  border: 1px solid var(--line); border-radius: 4px; padding: 2px 6px;
  font-family: inherit; font-size: 10px; color: var(--fg-2);
}

/* ------------------------------------------------------ responsive */
@media (max-width: 1080px) {
  .steps, .collab, .impact-list { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .story, .story.rev, .two-col, .canvas-head, .sv-head { grid-template-columns: 1fr; }
  .story.rev .story-text { order: 0; }
  .sv-head .body-col { columns: 2; }
  .stage img { max-height: 44vh; }
}

@media (max-width: 900px) {
  :root { --rail: 22px; }
  .deck { scroll-snap-type: y proximity; }
  .slide {
    padding: 84px var(--pad) 56px;
    justify-content: flex-start;
  }
  .rail { display: none; }
  .chrome { padding-left: var(--pad); }
  .now-showing { display: none; }
  .work-row { grid-template-columns: 30px minmax(0,1fr) auto; row-gap: 4px; }
  .work-row .w-name { grid-column: 2 / -1; }
  .work-row .w-tag  { grid-column: 2; }
  .work-row .w-year { grid-column: 3; align-self: baseline; }
  /* four columns of dates and places do not fit a tablet; two do */
  .xp-row { grid-template-columns: minmax(0,1fr) minmax(0,.85fr); row-gap: 2px; }
  .xp-where { text-align: right; }
  .cover-head { flex-direction: column; gap: 10px; }
  .kbd-hint { display: none; }
  .eyebrow { font-size: 12px; }
}

/* ------------------------------------------------------------- phones */
@media (max-width: 620px) {
  body { font-size: 15px; }
  .steps, .collab, .impact-list,
  .stage-grid.cols-1, .stage-grid.cols-2, .stage-grid.cols-3, .stage-grid.cols-4 {
    grid-template-columns: 1fr;
  }
  .stage-grid { max-width: none; }
  .stage-grid.cols-1 > .shot { max-width: none; }
  .sv-head .body-col { columns: 1; }
  .stage-phones { flex-wrap: wrap; row-gap: 22px; }
  .stage-phones .shot { flex: 1 1 42%; max-width: none; }
  .stage img, .stage-phones img, .stage-grid img { max-height: none; }
  .frame-browser img.tall, .frame-plain img.tall { aspect-ratio: auto; object-fit: contain; }
  .canvas-wrap img { max-height: 40vh; }
  .xp-row { grid-template-columns: 1fr; row-gap: 2px; }
  .xp-where { text-align: left; }
  .facts li { grid-template-columns: 1fr; gap: 2px; }
  .meta-grid { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
}

/* -------------------------------------------- dense slides / short screens */
/* These two carry the most content; keep them inside one screen. */
#approach h2.h-sec { font-size: clamp(24px, 2.9vw, 40px); max-width: 30ch; }
#approach .steps { margin-top: clamp(18px, 2.2vw, 30px); }
#approach .step { padding: 18px clamp(13px, 1.4vw, 20px); }
#approach .step p { font-size: 13px; line-height: 1.52; }

#experience h2.h-sec { font-size: clamp(22px, 2.6vw, 34px); max-width: 34ch; }
#experience .xp { margin-top: 18px; }
#experience .xp-row { padding: 9px 4px; }
#experience .xp-co { font-size: 15px; }
#experience .xp-role, #experience .xp-when, #experience .xp-where { font-size: 12.5px; }
/* a small laptop or a tablet on its side: the longest dates still fit one line */
@media (min-width: 901px) and (max-width: 1140px) {
  #experience .xp-row { grid-template-columns: minmax(0,.62fr) minmax(0,.95fr) minmax(0,1.2fr) minmax(0,.8fr); }
  #experience .xp-when, #experience .xp-where { font-size: 11px; }
}

@media (max-height: 880px) and (min-width: 761px) {
  :root { --padY: clamp(40px, 5.2vh, 64px); }
  .sv-head h3 { font-size: clamp(20px, 2.4vw, 30px); }
  .story-v { gap: clamp(14px, 1.8vw, 24px); }
  .stage-grid.n-2 img { max-height: 50vh; }
  .stage-grid.n-3 img { max-height: 38vh; }
  .stage-grid.n-4 img { max-height: 34vh; }
  #experience .tags { margin-top: 8px; }
  #experience .tag { padding: 3px 9px; }
}
@media (max-height: 800px) and (min-width: 761px) {
  .stage-grid.n-1 img { max-height: 54vh; }
  .stage-grid.n-2 img { max-height: 44vh; }
  .stage-grid.n-3 img { max-height: 34vh; }
  .stage-phones img { max-height: 48vh; }
  .sv-head .body-col p { font-size: 14.5px; margin-bottom: 11px; }
  #experience .xp-row { padding: 7px 4px; }
  #experience .tags { margin-top: 6px; }
  #experience h2.h-sec { font-size: clamp(20px, 2.2vw, 28px); }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; animation-iteration-count: 1 !important;
      transition-duration: .01ms !important; scroll-behavior: auto !important; }
  .rv { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------- hero field */
/* A canvas layer behind the opening slide. It is decoration: it sits under
   the content, ignores the pointer for hit-testing purposes elsewhere, and
   the slide reads identically without it. */
.hero-fx {
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none; overflow: hidden;
  opacity: 0; transition: opacity 1.2s var(--ease);
}
.hero-fx.is-on { opacity: 1; }
.hero-fx canvas { display: block; width: 100%; height: 100%; }
/* the field covers the whole slide; a soft ground keeps the headline and
   the header and footer rows quiet without cutting anything out */
.hero-fx::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(100deg, rgba(10,10,11,.55) 0%, rgba(10,10,11,.34) 36%, rgba(10,10,11,.1) 62%, rgba(10,10,11,0) 84%),
    linear-gradient(to bottom, rgba(10,10,11,.8) 0%, rgba(10,10,11,0) 16%, rgba(10,10,11,0) 76%, rgba(10,10,11,.5) 90%, rgba(10,10,11,.85) 100%);
}
.s-intro .slide-inner { position: relative; z-index: 1; }

/* stacked: the copy runs the full width, so the ground is a touch quieter
   everywhere and the header band stays */
@media (max-width: 900px) {
  .hero-fx::after {
    background:
      linear-gradient(to bottom, rgba(10,10,11,.8) 0%, rgba(10,10,11,.25) 14%, rgba(10,10,11,.25) 60%, rgba(10,10,11,0) 78%, rgba(10,10,11,.5) 100%);
  }
}

@media print { .chrome, .rail, .progress, .menu, .kbd-hint { display: none; } .slide { min-height: auto; page-break-inside: avoid; } }

/* --------------------------------------------------------------- edit mode */
/* The editor is a separate document in an overlay iframe, so its stylesheet
   never has to share a cascade with this one. */
#edit-frame {
  position: fixed; inset: 0; width: 100%; height: 100%;
  border: 0; z-index: 300; background: #0D0D0F;
}
body.is-editing { overflow: hidden; }
#edit-btn { border-color: var(--accent); color: var(--accent); }

/* ---------------------------------------------------- case-study accent */
/* Inside a case study the accent is that project's brand colour: app.js
   sets --accent on its slides, and on the body while one is on screen, so
   the rail marker and the progress line follow. It marks the project number
   and tag on the cover and the small labels above a section. */
.s-proj .cover-n, .s-proj .cover-tag, .s-proj .eyebrow { color: var(--accent); }

/* ------------------------------------------------------- coloured slides */
/* Each project's problem statement sits on that project's brand colour
   (the `accent` field in content.js). app.js sets --ground and --on-ground
   on the slide, and on the body while it is on screen; a colour that does
   not parse leaves the slide on the usual dark ground. */
.s-brand {
  --ground: var(--bg); --on-ground: var(--fg);
  background: var(--ground); color: var(--on-ground);
  border-bottom-color: color-mix(in srgb, var(--on-ground) 20%, transparent);
}
.s-brand .eyebrow, .s-brand .hmw-q, .s-brand .hmw-ctx, .s-brand .contact-lede { color: var(--on-ground); }
.s-brand .hmw-ctx { font-weight: 500; }
.s-brand .mail { color: var(--on-ground); background-image: linear-gradient(var(--on-ground), var(--on-ground)); }
.s-brand .contact-links a { color: var(--on-ground); border-color: color-mix(in srgb, var(--on-ground) 50%, transparent); }
.s-brand .contact-links a:hover { color: var(--on-ground); border-color: var(--on-ground); background: color-mix(in srgb, var(--on-ground) 8%, transparent); }
.s-brand .colophon { color: var(--on-ground); border-top-color: color-mix(in srgb, var(--on-ground) 25%, transparent); }
.s-brand ::selection { background: var(--on-ground); color: var(--ground); }
.s-brand :focus-visible { outline-color: var(--on-ground); }

/* while one is on screen, the fixed header, rail, hint and progress line
   take its colours so they stay visible */
.on-brand .chrome { background: linear-gradient(to bottom, color-mix(in srgb, var(--ground) 92%, transparent), transparent); }
.on-brand .wordmark, .on-brand .now-showing, .on-brand .now-showing b { color: var(--on-ground); }
.on-brand .menu-btn { color: var(--on-ground); border-color: color-mix(in srgb, var(--on-ground) 50%, transparent); }
.on-brand .menu-btn:hover { border-color: var(--on-ground); }
.on-brand .rail-item::after { background: color-mix(in srgb, var(--on-ground) 30%, transparent); }
.on-brand .rail-item.is-lead::after { background: color-mix(in srgb, var(--on-ground) 55%, transparent); }
.on-brand .rail-item.is-active::after, .on-brand .rail-item:hover::after { background: var(--on-ground); }
.on-brand .rail-item .tip { background: var(--on-ground); border-color: var(--on-ground); color: var(--ground); }
.on-brand .progress { background: var(--on-ground); }
.on-brand .kbd-hint { color: color-mix(in srgb, var(--on-ground) 72%, transparent); }
.on-brand .kbd-hint kbd { color: var(--on-ground); border-color: color-mix(in srgb, var(--on-ground) 35%, transparent); }
.wordmark { transition: color .35s var(--ease); }
