/* Glass House Design Lab, V4
   Black void, acid green, cool greys. Archivo display, Inter Tight UI, JetBrains Mono chrome.
   There is no vignette, no CRT warp and no darkening of screen edges or corners anywhere in
   this file. The only full-screen overlay is uniform film grain.

   Sections:
     1  fonts + tokens            6  #work shell (canvas, HUD, list / fallback row, wipe)
     2  base + utilities          7  footer + fan-down
     3  header                    8  contact panel + form
     4  the 3D mark               9  project sheet             10 index view
     5  hero                      11 grain, focus, reduced motion                              */

/* ======================================================================= 1. fonts + tokens */

@font-face {
  font-family: 'Archivo';
  src: url('../fonts/Archivo.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Inter Tight';
  src: url('../fonts/InterTight.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'JetBrains Mono';
  src: url('../fonts/JetBrainsMono.woff2') format('woff2');
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}

:root {
  --black: #000;
  --void: #050505;
  --charcoal: #1a1a1a;
  --slate: #71737d;
  --mist: #d9dcdf;
  --ink: #111;
  --green: #00fd01;
  --green-ink: #04210a;
  --rule: rgba(217, 220, 223, 0.28);
  --rule-green: rgba(4, 33, 10, 0.55);

  --display: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --ui: 'Inter Tight', 'Helvetica Neue', Arial, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, Consolas, monospace;

  --gutter: max(20px, 3vw);
  --hdr-h: 72px;
  --slot-h: 36px;
  --r-card: 18px;
  --r-sheet: 20px;

  --expo-out: cubic-bezier(0.16, 1, 0.3, 1);
  --expo-in-out: cubic-bezier(0.87, 0, 0.13, 1);
  --flight: cubic-bezier(0.16, 0.84, 0.24, 1);

  /* Header ink: light over the dark sections, dark over green (body.ink-dark). */
  --hdr-ink: var(--mist);
  --hdr-contrast: #000;
}

@media (max-width: 699px) {
  :root {
    --hdr-h: 60px;
    --slot-h: 30px;
    --r-card: 16px;
    --r-sheet: 14px;
  }
}

body.ink-dark {
  --hdr-ink: var(--green-ink);
  --hdr-contrast: var(--green);
}

/* ======================================================================= 2. base + utilities */

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

html {
  background: var(--black);
  color-scheme: dark;
  overscroll-behavior-x: none; /* no browser back-swipe while swiping the ribbon */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scrollbar-width: none;
}
html::-webkit-scrollbar {
  display: none;
}

body {
  margin: 0;
  background: var(--black);
  color: var(--mist);
  font-family: var(--ui);
  font-size: 16px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, p, ul, ol, figure {
  margin: 0;
}
ul, ol {
  padding: 0;
  list-style: none;
}
a {
  color: inherit;
  text-decoration: none;
}
button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
img,
svg,
canvas {
  display: block;
}
/* The reset above would otherwise beat the UA's [hidden] rule (an unset <img> then paints
   Chrome's empty-image border). */
[hidden] {
  display: none !important;
}

::selection {
  background: var(--green);
  color: var(--ink);
}

/* Lenis */
html.lenis,
html.lenis body {
  height: auto;
}
.lenis.lenis-smooth {
  scroll-behavior: auto !important;
}
.lenis.lenis-smooth [data-lenis-prevent] {
  overscroll-behavior: contain;
}
html.is-locked {
  overflow: hidden;
}
/* Touch / native scrolling: the three sections snap gently instead of the desktop magnet. */
html.has-snap {
  scroll-snap-type: y proximity;
}
html.has-snap main > section {
  scroll-snap-align: start;
}

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

.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* Inline icons: 1.5px strokes with round caps at any size. */
.i {
  width: 1em;
  height: 1em;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  overflow: visible;
}
.i path {
  vector-effect: non-scaling-stroke;
}

.mono {
  font-family: var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
}

/* Masks for line reveals. Lines rise from 100% inside an overflow:hidden window; the small
   padding / negative margin keeps ascenders and descenders from being shaved by the mask. */
.mask,
.line {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding: 0.14em 0;
  margin: -0.14em 0;
}
.line {
  display: block;
}
.mask__inner,
.line__inner {
  display: inline-block;
  will-change: transform;
}
.line__inner {
  display: block;
}
.js [data-hero-lines]:not(.is-split) {
  opacity: 0;
}
.js .hero .mask__inner,
.js .work-hud .mask__inner {
  transform: translateY(110%);
}
.js [data-hud-fade] {
  opacity: 0;
}
/* Safety net: if the modules never boot, show everything. */
.boot-failed .mask__inner,
.boot-failed .line__inner,
.boot-failed [data-hero-lines],
.boot-failed [data-hud-fade],
.boot-failed .logo3d__stage {
  opacity: 1 !important;
  transform: none !important;
}

.skip {
  position: fixed;
  z-index: 95;
  left: var(--gutter);
  top: calc(var(--hdr-h) + 12px); /* just under the header line, clear of the wordmark */
  padding: 0.7em 1.2em;
  border-radius: 999px;
  background: var(--green);
  color: var(--green-ink);
  font: 400 12px/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
  transform: translateY(calc(-100% - var(--hdr-h) - 24px)); /* parked above the viewport */
  transition: transform 0.3s var(--expo-out);
}
.skip:focus {
  transform: none;
}

/* ======================================================================= 3. header */

.hdr {
  position: fixed;
  inset: 0 0 auto;
  z-index: 40;
  height: var(--hdr-h);
  color: var(--hdr-ink);
  pointer-events: none; /* only its controls take the pointer */
  transition: color 0.2s ease, opacity 0.45s ease;
}
/* One hairline in the current ink at ~28%. */
.hdr::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  opacity: 0.28;
  pointer-events: none;
}
body.contact-open .hdr {
  z-index: 80; /* above the green panel, with dark ink and "Close" */
}

.hdr__inner {
  height: 100%;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 0 var(--gutter);
}

.hdr__brand {
  justify-self: start;
  display: block;
  width: clamp(112px, 11vw, 176px);
  pointer-events: auto;
  border-radius: 4px;
}
.hdr__wordmark {
  width: 100%;
  height: auto;
  aspect-ratio: 744 / 103;
  fill: currentColor;
}

/* The docked 3D mark lands here: slot height = the docked mark height. */
.hdr__slot {
  display: block;
  width: calc(var(--slot-h) * 1.91);
  height: var(--slot-h);
  border-radius: 999px;
}
.hdr:has(.logo3d:focus-visible) .hdr__slot {
  outline: 2px solid var(--green);
  outline-offset: 5px;
}
body.ink-dark .hdr:has(.logo3d:focus-visible) .hdr__slot {
  outline-color: var(--green-ink);
}

.hud-quote {
  justify-self: end;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  pointer-events: auto;
  padding: 0.72em 1.3em;
  border: 1px solid var(--hdr-ink);
  border-radius: 999px;
  color: var(--hdr-ink);
  font: 400 12px/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
  white-space: nowrap;
  transition: border-color 0.2s ease, color 0.2s ease;
}
/* Pointer-origin flood (header.js places and scales the disc). */
.flood {
  position: absolute;
  z-index: -1;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  border-radius: 50%;
  background: var(--hdr-ink);
  transform: scale(0);
  pointer-events: none;
  will-change: transform;
}
.hud-quote__label {
  display: grid;
  transition: color 0.25s ease;
}
.hud-quote.is-flooded .hud-quote__label {
  color: var(--hdr-contrast);
}
.hud-quote__face {
  grid-area: 1 / 1;
  display: block;
  text-align: center;
}
.hud-quote__short {
  display: none;
}
@media (max-width: 699px) {
  .hud-quote__long {
    display: none;
  }
  .hud-quote__short {
    display: inline;
  }
  .hud-quote {
    font-size: 11px;
    padding: 0.75em 1.25em;
  }
}

/* ======================================================================= 4. the 3D mark */

/* Fixed; logo3d.js sets width/height and a translate+scale transform (origin top centre). */
.logo3d {
  position: fixed;
  z-index: 2;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  padding: 0;
  transform-origin: 50% 0;
  pointer-events: none;
  cursor: default;
  outline: none;
  will-change: transform;
}
.logo3d.is-docked {
  pointer-events: auto;
  cursor: pointer;
}
.logo3d__stage {
  position: absolute;
  inset: 0;
  display: block;
}
.js .logo3d__stage {
  opacity: 0; /* revealed once the mark is built */
}
/* The canvas holder is the box plus, below it, the hero reflection region (logo3d.js sets
   its height); the reflection is composited in WebGL, so there is no second canvas. */
.logo3d__canvas {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.logo3d__canvas canvas {
  width: 100%;
  height: 100%;
}
.logo3d__img {
  position: absolute;
  left: 10%;
  top: 10%;
  width: 80%;
  height: 80%;
  transition: filter 0.2s ease;
}
body.ink-dark .logo3d__img {
  filter: brightness(0);
}

/* ======================================================================= 5. hero */

.hero {
  position: relative;
  height: 100svh;
  min-height: 560px;
  background: var(--black);
}

.hero__foot {
  position: absolute;
  left: var(--gutter);
  right: var(--gutter);
  bottom: max(28px, 3vw);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px 32px;
  font: 400 12px/1.5 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
  color: var(--mist);
}
.hero__tagline {
  max-width: 40ch;
}
.hero__cue {
  display: inline-flex;
  flex: none;
  border-radius: 4px;
}
.hero__cue .mask__inner {
  display: inline-flex;
  align-items: center;
  gap: 0.7em;
}
.hero__cue .i {
  transition: transform 0.6s var(--expo-out);
}
@media (hover: hover) {
  .hero__cue:hover .i {
    transform: translateY(3px);
  }
}
@media (max-width: 699px) {
  .hero__foot {
    flex-wrap: wrap;
    font-size: 11px;
    bottom: max(24px, env(safe-area-inset-bottom));
  }
  .hero__tagline {
    flex: 1 1 100%;
    max-width: 46ch;
  }
  .hero__cue {
    margin-left: auto;
  }
}

/* ======================================================================= 6. #work */

.work {
  --card-h: min(46svh, 560px);
  --card-w: calc(var(--card-h) * 1.6); /* covers are 16:10 */
  --card-gap: 14px;
  position: relative;
  height: 100svh;
  min-height: 600px;
  background: var(--black);
  overflow: hidden;
}
@media (max-width: 699px) {
  .work {
    /* Phones show each site's real mobile layout: m1.webp cover-fit to 3:4. */
    --card-h: min(52svh, calc(78vw * 4 / 3));
    --card-w: calc(var(--card-h) * 0.75);
    --card-gap: 12px;
    min-height: 560px;
  }
}
/* With WebGL the section takes horizontal gestures itself; vertical swipes still scroll. */
.gl .work {
  touch-action: pan-y;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
/* Ribbon cursors (folio.js): grab over the section, pointer over a pane, grabbing mid-drag. */
@media (hover: hover) and (pointer: fine) {
  .gl .work[data-mode='featured'] {
    cursor: grab;
  }
  .gl .work[data-mode='featured'].is-over-card {
    cursor: pointer;
  }
  .gl .work.is-grabbing,
  .gl .work.is-grabbing * {
    cursor: grabbing !important;
  }
}

.folio-gl {
  position: absolute;
  z-index: 1;
  inset: 0;
  width: 100%;
  height: 100%;
}
.no-gl .folio-gl,
.no-js .folio-gl {
  display: none;
}

/* --- work list: visually hidden but focusable with WebGL, the visible row without --- */

.work-list {
  z-index: 2;
}
.js:not(.work-ready) .work-list {
  visibility: hidden; /* until main.js knows which of the two it is */
}
.gl .work-list {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.no-gl .work-list,
.no-js .work-list {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  gap: var(--card-gap);
  padding: 16px calc(50% - var(--card-w) / 2);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.no-gl .work-list::-webkit-scrollbar {
  display: none;
}
.work-list.is-dragging {
  scroll-snap-type: none;
  cursor: grabbing;
}
.work-list.is-dragging .work-card {
  cursor: grabbing;
}
.work-list__item {
  flex: none;
  scroll-snap-align: center;
}

.work-card {
  position: relative;
  display: block;
  width: var(--card-w);
  height: var(--card-h);
  border-radius: var(--r-card);
  overflow: hidden;
  background: #111;
  color: #fff;
  text-align: left;
  isolation: isolate;
  transform: translateZ(0);
}
.work-card__media,
.work-card__media picture,
.work-card__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.work-card__media img {
  object-fit: cover;
  object-position: 50% 0;
  transition: transform 1.2s var(--expo-out);
  -webkit-user-drag: none;
  user-select: none;
}
.work-card {
  -webkit-user-select: none;
  user-select: none;
}
/* Per-card caption scrim: darkens only the bottom of the card, never the screen. */
.work-card::after {
  content: '';
  position: absolute;
  z-index: 1;
  left: 0;
  right: 0;
  bottom: 0;
  height: 46%;
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.6) 0%,
    rgba(0, 0, 0, 0.36) 12%,
    rgba(0, 0, 0, 0.16) 24%,
    rgba(0, 0, 0, 0.04) 36%,
    rgba(0, 0, 0, 0) 100%
  );
  pointer-events: none;
}
/* Glass edge: a bright 1px rim and a faint inner bevel line. */
.work-card::before {
  content: '';
  position: absolute;
  z-index: 3;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16), inset 0 0 0 3px rgba(255, 255, 255, 0.035);
  pointer-events: none;
}
.work-card__pill {
  position: absolute;
  z-index: 2;
  left: 16px;
  top: 16px;
  padding: 0.55em 0.95em 0.5em;
  border-radius: 999px;
  background: var(--green);
  color: var(--green-ink);
  font: 500 10px/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.01em;
}
.work-card__cap {
  position: absolute;
  z-index: 2;
  left: 18px;
  right: 64px;
  bottom: 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.work-card__num {
  font: 400 11px/1 var(--mono);
  color: rgba(255, 255, 255, 0.6);
}
.work-card__name {
  font: 600 20px/1 var(--display);
  letter-spacing: -0.02em;
  color: #fff;
}
.work-card__line {
  position: absolute !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.work-card__go {
  position: absolute;
  z-index: 2;
  right: 16px;
  bottom: 14px;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: #fff;
  color: #000;
  font-size: 14px;
  transition: transform 0.6s var(--expo-out);
}
.work-card.is-featured .work-card__go {
  background: var(--green);
  color: var(--green-ink);
}
@media (hover: hover) and (pointer: fine) {
  .no-gl .work-list {
    cursor: grab;
  }
  .work-card:hover .work-card__media img {
    transform: scale(1.035);
  }
  .work-card:hover .work-card__go {
    transform: rotate(-45deg);
  }
  .work-card.is-featured:hover .work-card__go {
    transform: scale(1.12);
  }
}
@media (max-width: 699px) {
  .work-card__name {
    font-size: 17px;
  }
  .work-card__pill {
    left: 12px;
    top: 12px;
  }
  .work-card__cap {
    left: 14px;
    bottom: 14px;
  }
  .work-card__go {
    right: 12px;
    bottom: 12px;
  }
}

/* --- green liquid wipe at the bottom of #work (scrubbed by footer.js) --- */

.work-wipe {
  position: absolute;
  z-index: 3;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}
/* The liquid wipe, shared by the #work flood and the contact panel. Layer i has depth
   --d = 3 - i: it reaches 1 + d*.13 of the box, is blurred d*4px and is 1 - d*.18 opaque,
   so the deep layers lead as a soft smear and the crisp front layer lands last. The layers
   TRANSLATE up rather than scaleY, which keeps the blur (and the soft leading edge) the same
   width at every moment instead of squashing it into hard bands. JS sets --d and the y. */
.work-wipe > i,
.contact__wipe > i {
  --d: 0;
  position: absolute;
  left: -64px;
  right: -64px;
  bottom: -64px; /* hang below the box so the blurred bottom edge is clipped */
  height: calc(100% * (1 + var(--d) * 0.13) + 64px);
  background: linear-gradient(to bottom, rgba(0, 253, 1, 0) 0, var(--green) calc(var(--d) * 48px));
  opacity: calc(1 - var(--d) * 0.18);
  filter: blur(calc(var(--d) * 4px));
  transform: translateY(100%);
  will-change: transform;
}
.work-wipe > i:last-child,
.contact__wipe > i:last-child {
  filter: none; /* depth 0: the crisp front layer */
}

/* --- HUD --- */

.work-hud {
  position: absolute;
  z-index: 4;
  inset: 0;
  pointer-events: none;
  color: var(--mist);
  font: 400 12px/1.2 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
  /* Steps aside as the green floods up (--wipe is the wipe's scrub progress), and while a
     pane flies to / sits as the project sheet (--hud-a, tweened by folio.js). */
  opacity: calc((1 - var(--wipe, 0) * 6) * var(--hud-a, 1));
}
.work.is-sheet .work-hud,
.work.is-sheet .work-hud button {
  pointer-events: none;
}
.work-hud button {
  pointer-events: auto;
  text-transform: inherit;
  letter-spacing: inherit;
}

.work-hud__eyebrow {
  position: absolute;
  top: calc(var(--hdr-h) + 22px);
  left: var(--gutter);
  font: inherit;
}
.work-hud__count {
  opacity: 0.45;
}

.work-hud__bar {
  position: absolute;
  left: var(--gutter);
  right: var(--gutter);
  bottom: max(26px, 3vh);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
}

.work-hud__modes {
  justify-self: start;
  display: flex;
  align-items: center;
  gap: 0.5em;
}
.work-hud__modes[hidden] {
  display: none;
}
.work-hud__modes button {
  opacity: 0.45;
  border-radius: 3px;
  transition: opacity 0.5s ease;
}
.work-hud__modes button[aria-current] {
  opacity: 1;
}
@media (hover: hover) {
  .work-hud__modes button:hover {
    opacity: 1;
  }
}
.work-hud__slash {
  opacity: 0.45;
}

.work-hud__centre {
  justify-self: center;
  grid-column: 2;
  position: relative;
  display: grid;
  place-items: center;
}
.work-hud__hint,
.work-hud__focus {
  grid-area: 1 / 1;
  white-space: nowrap;
}
.work-hud__hint .mask__inner {
  display: inline-flex;
  align-items: center;
  gap: 0.8em;
}
.work-hud__hint .i {
  opacity: 0.6;
}
.work-hud__hint-touch {
  display: none;
}
.is-touch .work-hud__hint-mouse {
  display: none;
}
.is-touch .work-hud__hint-touch {
  display: inline;
}
@media (max-width: 699px) {
  .work-hud__hint-mouse {
    display: none;
  }
  .work-hud__hint-touch {
    display: inline;
  }
}
.work-hud__focus {
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.35s ease, transform 0.6s var(--expo-out);
}
.work-hud.is-focus .work-hud__focus {
  opacity: 1;
  transform: none;
}
.work-hud.is-focus .work-hud__hint {
  opacity: 0 !important;
}

.work-hud__nav {
  justify-self: end;
  grid-column: 3;
  display: flex;
  align-items: center;
  gap: 8px;
  transition: opacity 0.5s ease;
}
.work-hud__counter {
  margin-right: 10px;
  font-variant-numeric: tabular-nums;
}
.work-hud__counter .mask__inner {
  display: inline-flex;
  align-items: center;
}
.work-hud__digit {
  position: relative;
  display: inline-block;
  width: 1ch;
  height: 1.2em;
  overflow: hidden;
}
.work-hud__roll {
  position: absolute;
  inset: 0;
  text-align: center;
  line-height: 1.2em;
}
.work-hud__sep {
  margin: 0 0.45em;
  opacity: 0.45;
}
.work-hud__total {
  opacity: 0.45;
}
.work-hud__btn {
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--rule);
  font-size: 14px;
  transition: background-color 0.35s ease, color 0.35s ease, border-color 0.35s ease;
}
@media (hover: hover) {
  .work-hud__btn:hover {
    background: var(--mist);
    border-color: var(--mist);
    color: #000;
  }
}
.work-hud__btn:active {
  transform: scale(0.94);
}
/* The Index view has no "current card": the counter and arrows step away. */
.work[data-mode='index'] .work-hud__nav,
.work[data-mode='index'] .work-hud__centre {
  opacity: 0;
  pointer-events: none;
}
.work[data-mode='index'] .work-hud__nav button {
  pointer-events: none;
}

@media (max-width: 699px) {
  .work-hud {
    font-size: 11px;
  }
  .work-hud__eyebrow {
    top: calc(var(--hdr-h) + 18px);
  }
  .work-hud__bar {
    grid-template-columns: auto 1fr auto;
    bottom: max(20px, env(safe-area-inset-bottom));
  }
  .work-hud__counter {
    margin-right: 4px;
  }
}

/* ======================================================================= 7. footer + fan-down */

.footer {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--green);
  color: var(--green-ink);
}
.footer ::selection,
.contact ::selection {
  background: var(--green-ink);
  color: var(--green);
}

.footer__stack {
  --trail-progress: 0;
  --trail-skew: 0deg;
  --trail-breath: 1;
  --trail-step: 17%;
  --trail-stretch: 0.6;
  --stack-top: max(96px, 9vw);
  position: relative;
  isolation: isolate;
  padding: var(--stack-top) var(--gutter) 0;
}
.footer__logo {
  width: 100%;
  height: auto;
  aspect-ratio: 744 / 103;
  fill: currentColor;
}
.footer__logo--front {
  position: relative;
  z-index: 10;
}
/* The reflective fan-down: each copy is more stretched, more blurred and fainter than the
   last, all stretching downward from the front copy's top edge. The skew (a viewing angle
   from the pointer) and the breath (scroll velocity) are the new, subtle touches. */
.footer__logo--trail {
  --i: var(--trail-index);
  --p: calc(var(--trail-progress) * var(--trail-breath));
  position: absolute;
  left: var(--gutter);
  top: var(--stack-top);
  width: calc(100% - 2 * var(--gutter));
  color: var(--green-ink);
  transform-origin: 50% 0;
  transform: skewX(calc(var(--trail-skew) * var(--i) / 6))
    translateY(calc(var(--p) * var(--i) * var(--trail-step)))
    scaleY(calc(1 + var(--p) * var(--i) * var(--trail-stretch)));
  opacity: calc((0.46 - var(--i) * 0.055) * var(--trail-progress));
  filter: blur(calc(var(--trail-progress) * var(--i) * 2px));
  will-change: transform, opacity, filter;
  pointer-events: none;
}
@media (max-width: 699px) {
  .footer__stack {
    --trail-step: 30%;
    --trail-stretch: 1.06;
    --stack-top: calc(var(--hdr-h) + 40px);
  }
}

.footer__base {
  position: relative;
  z-index: 11;
  margin-top: auto;
  display: grid;
  grid-template-columns: 1fr 2fr;
  align-items: end;
  padding: 48px var(--gutter) max(3vw, 24px);
}
.footer__barcode {
  display: flex;
  align-items: flex-end;
}
.footer__barcode svg {
  width: clamp(140px, 52%, 180px);
  height: auto;
}
.footer__barcode text {
  font-family: var(--mono);
}

.footer__rows {
  display: flex;
  flex-direction: column;
  font: 400 clamp(14px, 1.2vw, 18px) / 1.2 var(--mono);
  letter-spacing: -0.02em;
}

/* The old .button__half row: a full-width line between hairlines; the ink wipes up from
   the bottom on hover and leaves through the top (footer.js drives --anim / origin). */
.button__half {
  --anim: 0;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 0.85em 0;
  border-bottom: 1px solid var(--rule-green);
  color: var(--green-ink);
  text-align: left;
}
.button__half:first-child {
  border-top: 1px solid var(--rule-green);
}
.button__half::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: calc(100% + 1px);
  background: var(--green-ink);
  transform: scaleY(var(--anim));
  transform-origin: 50% var(--button-origin, 100%);
  pointer-events: none;
}
.button__half > span {
  position: relative;
  display: inline-flex;
  align-items: center;
  transition: padding 0.3s ease, color 0.15s ease;
}
@media (hover: hover) {
  .button__half:hover > span {
    padding: 0 1vw;
    color: var(--green);
  }
}
.footer__icon {
  font-size: 1.05em;
}

.footer__meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 1.2em;
  font: 400 12px/1.2 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
}
.footer__copy {
  opacity: 0.5;
}
.footer__top {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  opacity: 0.8;
  border-radius: 3px;
  transition: opacity 0.3s ease;
}
@media (hover: hover) {
  .footer__top:hover {
    opacity: 1;
  }
}

@media (max-width: 699px) {
  .footer__base {
    grid-template-columns: auto minmax(0, 1fr);
    gap: 16px;
    padding-bottom: max(24px, env(safe-area-inset-bottom));
  }
  .footer__barcode svg {
    width: 75px;
  }
  .footer__rows {
    font-size: min(14px, calc(5.71vw - 7.8px));
  }
  .footer__meta {
    font-size: 10px;
  }
}

/* ======================================================================= 8. contact panel */

.contact {
  position: fixed;
  z-index: 70;
  inset: 0;
  color: var(--green-ink);
}
.contact[hidden] {
  display: none;
}
.contact__wipe {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.contact__scroll {
  position: absolute;
  inset: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.contact__scroll::-webkit-scrollbar {
  display: none;
}
.contact__grid {
  min-height: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: 6vw;
  align-items: start;
  padding: calc(var(--hdr-h) + clamp(40px, 6vw, 96px)) var(--gutter) clamp(32px, 4vw, 64px);
}
.contact__title {
  font: 600 clamp(48px, 8vw, 132px) / 0.9 var(--display);
  letter-spacing: -0.035em;
  margin: 0 0 0.4em -0.05em;
  outline: none;
}
.contact__pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 26px;
}
.contact__pills li {
  padding: 0.62em 1.1em 0.58em;
  border: 1px solid var(--green-ink);
  border-radius: 999px;
  font: 400 11px/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
}
.contact__email {
  display: inline-block;
  font: 400 14px/1.4 var(--mono);
  letter-spacing: -0.02em;
  border-bottom: 1px solid var(--rule-green);
  padding-bottom: 2px;
  transition: border-color 0.3s ease;
}
@media (hover: hover) {
  .contact__email:hover {
    border-color: var(--green-ink);
  }
}

.quoteForm {
  padding-top: 0.6vw;
}
.quoteForm__form {
  position: relative;
  max-width: 620px;
}
.quoteForm__field {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0 12px;
  margin-bottom: 22px;
}
.quoteForm__label {
  font: 400 min(13px, calc(3.6vw - 1px)) / 1.3 var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  opacity: 0.6;
}
.quoteForm__optional {
  text-transform: none;
  opacity: 0.7;
  margin-left: 0.4em;
}
.quoteForm__error {
  font: 400 12px/1.3 var(--mono);
  opacity: 0.5;
}
.quoteForm__error[hidden] {
  display: none;
}
.quoteForm__field.is-invalid .quoteForm__label {
  opacity: 1;
}
.quoteForm__field.is-invalid .quoteForm__label::before {
  content: '*';
  font-weight: 700;
  margin-right: 0.25em;
}
.quoteForm__input {
  flex: 1 0 100%;
  width: 100%;
  margin-top: 4px;
  padding: 0.6em 0;
  border: 0;
  border-bottom: 1px solid var(--rule-green);
  border-radius: 0;
  background: transparent;
  color: var(--green-ink);
  font: 400 16px/1.4 var(--mono); /* >= 16px: no iOS zoom */
  letter-spacing: -0.01em;
  outline: none;
  transition: border-color 0.25s ease, box-shadow 0.25s ease;
  -webkit-appearance: none;
  appearance: none;
}
/* Focus on an underline-only field: the rule thickens to a full-ink 3px line and the label
   comes up to full strength (a clear indicator without boxing the field in). */
.quoteForm .quoteForm__input:focus,
.quoteForm .quoteForm__input:focus-visible {
  outline: none;
  border-bottom-color: var(--green-ink);
  box-shadow: 0 2px 0 0 var(--green-ink);
}
.quoteForm__field:focus-within .quoteForm__label {
  opacity: 1;
}
.quoteForm__input--area {
  resize: vertical;
  min-height: 6.4em;
}
.quoteForm__input:-webkit-autofill {
  -webkit-text-fill-color: var(--green-ink);
  box-shadow: 0 0 0 100px var(--green) inset;
  transition: background-color 9999s;
}
.quoteForm .buttons {
  margin-top: 30px;
}
.button__pill {
  display: inline-flex;
  align-items: center;
  gap: 0.8em;
  min-height: 44px;
  padding: 0.8em 1.8em;
  border: 1px solid var(--green-ink);
  border-radius: 999px;
  background: var(--green-ink);
  color: var(--green);
  font: 400 13px/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
  transition: background-color 0.22s ease, color 0.22s ease;
}
@media (hover: hover) {
  .button__pill:hover {
    background: transparent;
    color: var(--green-ink);
  }
}
.quoteForm__form.is-busy .button__pill {
  opacity: 0.5;
  pointer-events: none;
}
.quoteForm__status {
  min-height: 1.4em;
  margin-top: 16px;
  font: 400 12px/1.4 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
}

@media (max-width: 899px) {
  .contact__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 40px;
    padding-top: calc(var(--hdr-h) + 36px);
    padding-bottom: max(40px, env(safe-area-inset-bottom));
  }
  .contact__title {
    font-size: clamp(48px, 14vw, 96px);
  }
}

/* ======================================================================= 9. SHEET
   The project sheet: #sheet[role=dialog], fixed, z 60, a mist rounded panel. No scrim and no
   darkening around it: the margins show the page itself (the black #work behind). During a GL
   flight the panel is transparent (.is-flying) so the content reveals over the flying plane;
   DOM flights clip the panel from the source rect with a washing image copy (.sheet__wash). */

.sheet {
  --sheet-pad: 40px;
  --sheet-ink-soft: rgba(17, 17, 17, 0.6);
  --sheet-rule: rgba(17, 17, 17, 0.16);
  position: fixed;
  z-index: 60;
  inset: 2.2svh 3vw;
  color: var(--ink);
  touch-action: pan-y pinch-zoom; /* horizontal swipes are prev / next */
}
.sheet[hidden] {
  display: none;
}
/* Laid out but unseen while the content is built and measured. (Opacity, not visibility: the
   reduced-motion rule gives every property a .01ms transition, and a visibility that is still
   "hidden" for that instant would refuse the h1's focus.) */
.sheet.is-measuring {
  opacity: 0;
  pointer-events: none;
}
.sheet ::selection {
  background: var(--ink);
  color: var(--mist);
}
/* The header steps aside under the sheet (it would otherwise sit over the flying plane); the
   contact panel opened from the sheet brings it back on top with "Close". */
body.sheet-open .hdr {
  opacity: 0;
  visibility: hidden;
  transition: color 0.2s ease, opacity 0.3s ease, visibility 0s linear 0.3s;
}
body.sheet-open.contact-open .hdr {
  opacity: 1;
  visibility: visible;
  transition: color 0.2s ease, opacity 0.3s ease;
}
.sheet__panel {
  position: absolute;
  inset: 0;
  overflow: hidden;
  isolation: isolate;
  border-radius: var(--r-sheet);
  background: var(--mist);
}
.sheet.is-flying .sheet__panel {
  background: transparent;
}
.sheet__wash {
  position: absolute;
  z-index: 2;
  display: none;
  overflow: hidden;
  pointer-events: none;
}
.sheet.is-washing .sheet__wash {
  display: block;
}
.sheet__wash img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0;
}

.sheet__body,
.sheet__media,
.sheet__copy {
  touch-action: pan-y pinch-zoom; /* (each scroller decides its own touch behaviour) */
}
.sheet__body {
  position: absolute;
  z-index: 1;
  inset: 0;
  display: grid;
  grid-template-columns: minmax(320px, 34%) minmax(0, 1fr);
}

/* --- left column: copy (stays put while the image column scrolls) --- */

.sheet__copy {
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 32px;
  padding: var(--sheet-pad);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
}
.sheet__copy::-webkit-scrollbar {
  display: none;
}
.sheet__eyebrow {
  margin-bottom: clamp(18px, 2.4vh, 28px);
  font: 400 12px/1.2 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
  color: var(--sheet-ink-soft);
}
.sheet__dash {
  margin: 0 0.15em;
}
.sheet__title {
  margin: 0 0 clamp(16px, 2.2vh, 26px) -0.045em;
  font: 600 clamp(40px, 5.2vw, 88px) / 0.92 var(--display);
  letter-spacing: -0.035em;
  outline: none;
  overflow-wrap: break-word;
  hyphens: manual;
}
/* The h1 takes programmatic focus on open (for screen readers): no ring around the title. */
.sheet__title:focus,
.sheet__title:focus-visible {
  outline: none;
}
/* Room for descenders inside the line masks at this tight line height. */
.sheet__title .line {
  padding: 0.04em 0 0.12em;
  margin: -0.04em 0 -0.12em;
}
.sheet__line {
  max-width: 36ch;
  font: 400 18px/1.35 var(--ui);
  letter-spacing: -0.012em;
}
.sheet__line .line {
  padding: 0.1em 0;
  margin: -0.1em 0;
}

.sheet__pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: clamp(22px, 3.2vh, 34px);
}
.pill {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  height: 32px;
  padding: 0 1.15em;
  border: 1px solid var(--ink);
  border-radius: 999px;
  color: var(--ink);
  font: 400 11px/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
  white-space: nowrap;
  transition: color 0.25s ease;
  transform-origin: 30% 50%;
}
.pill > :not(.flood) {
  position: relative;
}
.pill .flood {
  background: var(--ink);
}
.pill.is-flooded {
  color: var(--mist);
}
.pill .i {
  font-size: 13px;
}
.pill--visit {
  border-color: var(--green);
  background: var(--green);
  color: var(--green-ink);
}
.pill--visit .flood {
  background: var(--green-ink);
}
.pill--visit.is-flooded {
  color: var(--green);
}
.pill--visit:focus-visible {
  outline-color: var(--ink);
}
.pill--loc {
  border-color: rgba(17, 17, 17, 0.28);
  color: var(--sheet-ink-soft);
}

.sheet__notes {
  max-width: 40ch;
  margin-top: clamp(22px, 3.4vh, 36px);
  font: 400 11px/1.35 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
}
.sheet__notes li {
  padding: 10px 0 9px;
  border-top: 1px solid var(--sheet-rule);
}
.sheet__notes li:last-child {
  border-bottom: 1px solid var(--sheet-rule);
}
.sheet__start {
  display: inline-flex;
  align-items: center;
  gap: 0.7em;
  margin-top: clamp(18px, 2.6vh, 26px);
  padding: 0.35em 0;
  border-bottom: 1px solid currentColor;
  font: 400 12px/1.2 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
}
.sheet__start .i {
  transition: transform 0.6s var(--expo-out);
}
@media (hover: hover) {
  .sheet__start:hover .i {
    transform: translateX(4px);
  }
}

.sheet__foot {
  display: flex;
  align-items: center;
  gap: 18px;
  font: 400 12px/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
}
.sheet__ring {
  width: 28px;
  height: 28px;
  flex: none;
  transform: rotate(-90deg);
  overflow: visible;
}
.sheet__ring circle {
  fill: none;
  stroke: var(--ink);
  stroke-width: 2;
}
.sheet__ring-track {
  opacity: 0.16;
}
.sheet__nav {
  display: flex;
  align-items: center;
  gap: 0.75em;
}
.sheet__nav button {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.5em 0;
  border-radius: 3px;
  text-transform: inherit;
  letter-spacing: inherit;
  transition: opacity 0.3s ease;
}
.sheet__nav .i {
  transition: transform 0.6s var(--expo-out);
}
@media (hover: hover) {
  .sheet__nav button:hover .i {
    transform: translateX(3px);
  }
  .sheet__prev:hover .i {
    transform: translateX(-3px) !important;
  }
}
.sheet__slash {
  opacity: 0.4;
}

/* --- right column: the image stack scrolls inside the sheet --- */

.sheet__media {
  position: relative;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
  padding: var(--sheet-pad) 104px var(--sheet-pad) 8px;
  outline: none;
}
.sheet__media::-webkit-scrollbar {
  display: none;
}
.sheet__media:focus-visible {
  box-shadow: inset 0 0 0 2px var(--ink);
  border-radius: 12px;
}
.sheet__stack {
  display: flex;
  flex-direction: column;
  gap: clamp(24px, 4vw, 64px);
}
.sheet__frame,
.sheet__phone {
  position: relative;
  overflow: hidden;
  border: 1px solid rgba(17, 17, 17, 0.12);
  background: #c8cbcf;
}
.sheet__frame {
  aspect-ratio: 16 / 10;
  border-radius: 10px;
}
.sheet__frame img,
.sheet__phone img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0;
  opacity: 0;
  transition: opacity 0.6s ease;
  -webkit-user-drag: none;
  user-select: none;
}
.sheet__frame.is-loaded img,
.sheet__phone.is-loaded img {
  opacity: 1;
}
/* Loading: a soft light sweep across the empty frame (per-frame; stops once the image is in). */
.sheet__frame:not(.is-loaded)::after,
.sheet__phone:not(.is-loaded)::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, rgba(255, 255, 255, 0) 35%, rgba(255, 255, 255, 0.32) 50%, rgba(255, 255, 255, 0) 65%) 0 0 / 250% 100% no-repeat;
  animation: sheet-sheen 1.6s ease-in-out infinite;
}
@keyframes sheet-sheen {
  from {
    background-position: 130% 0;
  }
  to {
    background-position: -30% 0;
  }
}
.is-reduced .sheet__frame::after,
.is-reduced .sheet__phone::after {
  animation: none;
}
.sheet__phones {
  display: flex;
  justify-content: center;
  gap: clamp(16px, 2.2vw, 36px);
}
.sheet__phone {
  flex: 1 1 0;
  max-width: 260px;
  aspect-ratio: 540 / 1169;
  border-radius: 22px;
}
.sheet__nextrow {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
  width: 100%;
  padding: 26px 0 8px;
  border-top: 1px solid rgba(17, 17, 17, 0.2);
  text-align: left;
  color: var(--ink);
}
.sheet__nextrow-k {
  font: 400 12px/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: -0.02em;
  color: var(--sheet-ink-soft);
}
.sheet__nextrow-name {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  font: 600 40px/0.95 var(--display);
  letter-spacing: -0.03em;
}
.sheet__nextrow-name .i {
  font-size: 0.7em;
  transition: transform 0.7s var(--expo-out);
}
@media (hover: hover) {
  .sheet__nextrow:hover .sheet__nextrow-name .i {
    transform: translateX(8px);
  }
}

/* --- close: a round black button whose fill hollows to a ring on hover, the X turning 90° --- */

.sheet__close {
  position: absolute;
  z-index: 3;
  top: 24px;
  right: 24px;
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px var(--ink);
  color: var(--mist);
  font-size: 16px;
  transition: color 0.35s ease;
}
.sheet__close::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--ink);
  transition: transform 0.6s var(--expo-out);
}
.sheet__close .i {
  position: relative;
  transition: transform 0.7s var(--expo-out);
}
@media (hover: hover) {
  .sheet__close:hover {
    color: var(--ink);
  }
  .sheet__close:hover::before {
    transform: scale(0);
  }
  .sheet__close:hover .i {
    transform: rotate(90deg);
  }
}
.sheet__close:active .i {
  transform: rotate(90deg) scale(0.9);
}
.sheet :focus-visible {
  outline-color: var(--ink);
}

/* Mid widths: a narrower copy column and smaller gutters so long names still fit. */
@media (max-width: 1180px) and (min-width: 700px) {
  .sheet {
    --sheet-pad: 32px;
  }
  .sheet__body {
    grid-template-columns: minmax(300px, 36%) minmax(0, 1fr);
  }
  .sheet__title {
    font-size: clamp(36px, 4.8vw, 88px);
  }
  .sheet__media {
    padding-right: 92px;
  }
}

/* Compact: one column, the whole sheet scrolls, close fixed at the bottom-right. */
@media (max-width: 699px) {
  .sheet {
    inset: 12px;
  }
  .sheet__body {
    display: block;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: none;
  }
  .sheet__body::-webkit-scrollbar {
    display: none;
  }
  .sheet__copy {
    overflow: visible;
    gap: 28px;
    padding: 30px 22px 8px;
  }
  .sheet__title {
    font-size: clamp(34px, 10vw, 48px);
  }
  .sheet__line {
    font-size: 16px;
  }
  .sheet__ring {
    display: none;
  }
  .sheet__media {
    overflow: visible;
    padding: 28px 12px 100px;
  }
  .sheet__stack {
    gap: 24px;
  }
  .sheet__frame {
    border-radius: 8px;
  }
  .sheet__phones {
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 4% 0;
  }
  .sheet__phones--3 {
    justify-content: center;
    column-gap: 4%;
  }
  .sheet__phone {
    flex: 0 0 48%;
    max-width: none;
    border-radius: 18px;
  }
  .sheet__nextrow {
    padding-top: 22px;
  }
  .sheet__nextrow-name {
    font-size: 30px;
  }
  .sheet__close {
    top: auto;
    bottom: 14px;
    right: 14px;
    width: 52px;
    height: 52px;
  }
}

/* ======================================================================= 10. INDEX VIEW
   nav#work-index inside #work (z 2: above the canvas, below the wipe and HUD). Names centred and
   wrapped with superscript indices and green dots in the gaps; a cursor-following preview card
   sits behind them on desktop (indexview.js drives its transform). */

.work-index {
  --ix-gap: clamp(30px, 3.4vw, 60px);
  position: absolute;
  z-index: 2;
  inset: 0;
  display: grid;
  place-items: center;
  padding: calc(var(--hdr-h) + 64px) var(--gutter) 128px;
  pointer-events: none;
}
.work-index[hidden] {
  display: none;
}
.work-index__list {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  column-gap: var(--ix-gap);
  row-gap: 0.12em;
  max-width: min(1240px, 100%);
  margin-top: -6vh; /* sit a little above centre: the floor grid owns the lower half */
  font: 600 clamp(28px, 4.4vw, 68px) / 1.06 var(--display);
  letter-spacing: -0.03em;
  color: var(--mist);
  text-align: center;
}
.work-index__item {
  position: relative;
  white-space: nowrap;
}
.work-index__link {
  display: inline-block;
  border-radius: 6px;
  pointer-events: auto;
  transition: opacity 0.35s ease, color 0.35s ease;
}
.work-index__mask {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding: 0.06em 0.05em 0.12em;
  margin: -0.06em -0.05em -0.12em;
}
.work-index__inner {
  display: inline-block;
  will-change: transform;
}
.work-index__num {
  position: relative;
  top: 0.15em;
  margin-left: 0.3em;
  vertical-align: top;
  font: 400 clamp(10px, 0.85vw, 13px) / 1 var(--mono);
  letter-spacing: -0.02em;
  opacity: 0.55;
}
.work-index__dot {
  position: absolute;
  left: 100%;
  top: 54%;
  width: 7px;
  height: 7px;
  margin-left: calc(var(--ix-gap) / 2);
  border-radius: 50%;
  background: var(--green);
  translate: -50% -50%;
  pointer-events: none;
}
.work-index__item.no-dot .work-index__dot {
  display: none;
}
.work-index__list.has-hover .work-index__link {
  opacity: 0.35;
}
.work-index__list.has-hover .work-index__link.is-active {
  opacity: 1;
  color: #fff;
}
.js .work-index__inner {
  transform: translateY(110%); /* hidden until show() reveals it */
}

.work-index__preview {
  position: fixed;
  z-index: 0;
  left: 0;
  top: 0;
  width: 320px;
  height: 200px;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
}
.work-index__card {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 14px;
  background: #111;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
}
.work-index__card img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0;
  opacity: 0;
  filter: brightness(0.72); /* per-surface: keeps the white name readable over a bright cover */
  transition: opacity 0.35s ease;
}
.work-index__card img.is-on {
  opacity: 1;
}

/* No WebGL: the fallback row steps away while the Index shows, and while a sheet is up (its
   neighbours would otherwise peek into the sheet's margins). */
.no-gl .work-list {
  transition: opacity 0.5s ease, visibility 0s linear 0s;
}
.no-gl body.sheet-cover .work-list {
  opacity: 0;
  transition: opacity 0.35s ease;
}
.no-gl .work[data-mode='index'] .work-list {
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.4s ease, visibility 0s linear 0.4s;
}

@media (max-width: 699px) {
  .work-index {
    --ix-gap: 26px;
    padding: calc(var(--hdr-h) + 56px) 20px 110px;
  }
  .work-index__list {
    row-gap: 0.2em;
    margin-top: -4vh;
  }
  .work-index__dot {
    width: 6px;
    height: 6px;
  }
  .work-index__num {
    font-size: 10px;
  }
}

/* ======================================================================= 11. grain, focus, motion */

/* Film grain: a uniform overlay that jitters in steps. Not an edge effect: same everywhere. */
.grain {
  position: fixed;
  z-index: 100;
  top: -10rem;
  left: -10rem;
  width: calc(100% + 20rem);
  height: calc(100% + 20rem);
  background: url('../img/noise.png') 50% / 100px 100px repeat;
  mix-blend-mode: overlay;
  opacity: 0.22;
  pointer-events: none;
  animation: grain 0.5s steps(1) infinite;
}
@keyframes grain {
  0% { transform: translate3d(0, 9rem, 0); }
  10% { transform: translate3d(-1rem, -4rem, 0); }
  20% { transform: translate3d(-8rem, 2rem, 0); }
  30% { transform: translate3d(9rem, -9rem, 0); }
  40% { transform: translate3d(-2rem, 7rem, 0); }
  50% { transform: translate3d(-9rem, -4rem, 0); }
  60% { transform: translate3d(2rem, 6rem, 0); }
  70% { transform: translate3d(7rem, -8rem, 0); }
  80% { transform: translate3d(-9rem, 1rem, 0); }
  90% { transform: translate3d(6rem, -5rem, 0); }
  100% { transform: translate3d(-7rem, 0, 0); }
}
@media (max-width: 699px), (hover: none) {
  .grain {
    display: none; /* desktop only */
  }
}

:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 3px;
}
:focus:not(:focus-visible) {
  outline: none;
}
.footer :focus-visible,
.contact :focus-visible,
body.ink-dark .hdr :focus-visible {
  outline-color: var(--green-ink);
}
.work-card:focus-visible {
  outline-offset: 4px;
}
/* Sections receive programmatic focus after a skip / in-page jump: no ring around a whole screen. */
main > section[tabindex='-1']:focus {
  outline: none;
}

@media (prefers-reduced-motion: reduce) {
  .grain {
    animation: none;
  }
  html.has-snap {
    scroll-snap-type: none;
  }
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
.is-reduced .grain {
  animation: none;
}
