/* =========================================================================
   Parya Bahrami — shared stylesheet
   Loaded after the Tailwind CDN. Tailwind handles layout utilities;
   everything here is component + cinematic layer work that utilities
   cannot express (blend modes, keyframes, clip-path, scroll-driven state).
   ========================================================================= */

:root {
  --paper: #f6f3ef;
  --night: #050505;
  --ink: #151210;
  --neon: #d6ff58;
  --badge: #ccff00;
  --shadow-nav: 0 12px 35px rgba(35, 24, 18, 0.08);
  --hero-filter: saturate(0.82) contrast(1.08) brightness(0.72);
  /* Case-study brand accents — used by .case-hero[data-brand] */
  --brand-seenova: #bb202e;
  --brand-directam: #be0183;
  --brand-airplus: #610fc9;
  --brand-airplus-2: #e3c044;
}

html {
  scroll-behavior: smooth;
  /* the fixed header must not cover anchor targets */
  scroll-padding-top: 6.5rem;
}

body {
  font-family: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  font-weight: 400;
  letter-spacing: -0.011em;
  background: var(--paper);
  color: var(--ink);
}

/* Page transition — fade in on load, no router. */
body {
  opacity: 0;
  transition: opacity 0.6s ease;
}
body.is-ready {
  opacity: 1;
}

.font-display,
.display {
  font-family: "Cormorant Garamond", "Times New Roman", serif;
  font-weight: 400;
  letter-spacing: -0.02em;
}

::selection {
  background: #2b170d;
  color: #fff;
}

.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  z-index: 100;
  background: var(--neon);
  color: #000;
  padding: 0.65rem 1.1rem;
  border-radius: 999px;
  font-size: 0.8rem;
}
.skip-link:focus {
  left: 1rem;
  top: 1rem;
}

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

/* =========================================================================
   1. Header / navigation
   ========================================================================= */

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  /* Matches the content container's px-6 so the pill sits on the same column. */
  padding: 1rem 1.5rem 0;
  pointer-events: none;
}

/* Three tracks — brand, links, actions — so the link row is optically centred
   in the pill rather than wherever the two side groups leave it. */
.nav-shell {
  pointer-events: auto;
  margin: 0 auto;
  /* Same 72rem column as every section, with a left padding equal to the
     container's px-6 — so the brand sits on the exact vertical line the body
     copy starts from, instead of a third margin of its own. */
  max-width: 72rem;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1.5rem;
  padding: 0.55rem 0.6rem 0.55rem 1.5rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.55);
  /* Opaque enough that the nav keeps AA contrast over the black hero, not just
     over the paper sections. */
  background: rgba(246, 243, 239, 0.82);
  -webkit-backdrop-filter: blur(24px);
  backdrop-filter: blur(24px);
  box-shadow: var(--shadow-nav);
  transition: padding 0.35s cubic-bezier(0.22, 1, 0.36, 1),
    background 0.35s ease, box-shadow 0.35s ease;
}
/* Settles once the page has moved: a little tighter, a little more solid. */
.site-header.is-scrolled .nav-shell {
  padding-block: 0.4rem;
  background: rgba(246, 243, 239, 0.93);
  box-shadow: 0 10px 30px rgba(35, 24, 18, 0.13);
}

.nav-brand {
  /* Every item is pinned to its own column. Without this, auto-placement puts
     .nav-actions in column 2 whenever .nav-links is display:none — a
     display:none item is not a grid item at all, so it leaves no column
     behind. That is what parked the CTA and the hamburger in the middle of the
     pill on every screen below 1024px. */
  grid-column: 1;
  justify-self: start;
  min-width: 0;
  white-space: nowrap;
  font-family: "Cormorant Garamond", serif;
  font-weight: 500;
  font-size: 1.3rem;
  line-height: 1;
  letter-spacing: 0.004em;
  transition: opacity 0.25s ease;
}
.nav-brand:hover {
  opacity: 0.7;
}

.nav-links {
  grid-column: 2;
  display: none;
  justify-self: center;
  align-items: center;
  gap: 1.75rem;
  /* The pill's padding is asymmetric (text on the left, a button on the right),
     so the content box centre sits 0.375rem right of the pill's true centre.
     This puts the links back on the pill's axis. */
  margin-right: 0.75rem;
}
@media (min-width: 1024px) {
  .nav-links {
    display: flex;
  }
}

.nav-link {
  position: relative;
  font-size: 0.79rem;
  font-weight: 400;
  letter-spacing: 0.015em;
  color: rgba(21, 18, 16, 0.85);
  padding-bottom: 0.18rem;
  transition: color 0.25s ease;
}
.nav-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--neon);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
.nav-link:hover {
  color: var(--ink);
}
.nav-link:hover::after {
  transform: scaleX(1);
}

/* Active state is driven entirely by body[data-nav]; the header markup is
   byte-identical on every page. */
body[data-nav="about"] .nav-link[data-key="about"]::after,
body[data-nav="work"] .nav-link[data-key="work"]::after,
body[data-nav="journal"] .nav-link[data-key="journal"]::after,
body[data-nav="lab"] .nav-link[data-key="lab"]::after {
  transform: scaleX(1);
}
body[data-nav="about"] .nav-link[data-key="about"],
body[data-nav="work"] .nav-link[data-key="work"],
body[data-nav="journal"] .nav-link[data-key="journal"],
body[data-nav="lab"] .nav-link[data-key="lab"] {
  color: var(--ink);
}

.nav-actions {
  grid-column: 3;
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Music toggle — !important beats Tailwind CDN preflight injected later. */
button.nav-music {
  position: relative !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  width: 2.55rem !important;
  height: 2.55rem !important;
  flex-shrink: 0 !important;
  margin: 0 !important;
  padding: 0 !important;
  border: 0 !important;
  border-radius: 999px !important;
  background: #d4d8df !important;
  background-image: none !important;
  color: #151210 !important;
  box-shadow: inset 0 0 0 1px rgba(21, 18, 16, 0.08) !important;
  cursor: pointer !important;
  -webkit-appearance: none !important;
  appearance: none !important;
  transition: background 0.2s ease, transform 0.2s ease !important;
}
button.nav-music:hover {
  background: #c7ccd5 !important;
  transform: translateY(-1px);
}
button.nav-music:focus-visible {
  outline: 2px solid var(--neon);
  outline-offset: 2px;
}
button.nav-music .nav-music-wave {
  display: block !important;
  overflow: hidden !important;
  width: 1.15rem !important;
  height: 1.15rem !important;
  pointer-events: none !important;
}
button.nav-music .nav-music-flat,
button.nav-music .nav-music-sine {
  transition: opacity 0.15s ease;
}
button.nav-music .nav-music-flat {
  opacity: 1;
}
button.nav-music .nav-music-sine {
  opacity: 0;
  will-change: transform;
}
button.nav-music.is-playing {
  background: #d6ff58 !important;
}
button.nav-music.is-playing .nav-music-flat {
  opacity: 0;
}
button.nav-music.is-playing .nav-music-sine {
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  button.nav-music.is-playing .nav-music-sine {
    transform: none !important;
  }
}

.pill-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1.1rem;
  border-radius: 999px;
  background: var(--ink);
  color: #fff;
  font-size: 0.8rem;
  font-weight: 500;
  transition: background 0.3s ease, color 0.3s ease, transform 0.3s ease;
}
.pill-cta iconify-icon {
  font-size: 1.05rem;
}
.pill-cta:hover {
  background: var(--neon);
  color: #000;
  transform: translateY(-1px);
}

.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 999px;
  border: 1px solid rgba(21, 18, 16, 0.12);
  color: var(--ink);
  font-size: 1.3rem;
}
@media (min-width: 1024px) {
  .nav-toggle {
    display: none;
  }
}

.nav-drawer {
  pointer-events: auto;
  margin: 0.6rem auto 0;
  max-width: 72rem;
  border-radius: 1.5rem;
  border: 1px solid rgba(255, 255, 255, 0.55);
  background: rgba(246, 243, 239, 0.94);
  -webkit-backdrop-filter: blur(24px);
  backdrop-filter: blur(24px);
  box-shadow: var(--shadow-nav);
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  transition: max-height 0.4s ease, opacity 0.3s ease;
}
.nav-drawer.is-open {
  max-height: 24rem;
  opacity: 1;
}
.nav-drawer ul {
  display: grid;
  padding: 0.75rem;
  gap: 0.15rem;
}
.nav-drawer a {
  display: block;
  padding: 0.7rem 0.9rem;
  border-radius: 0.9rem;
  font-size: 0.95rem;
}
.nav-drawer a:hover {
  background: rgba(21, 18, 16, 0.05);
}
/* The drawer is a clone of .nav-links, so it inherits the underline the header
   uses for the active page. On a full-width block link that underline stretches
   across the whole drawer and reads as a stray rule. Same state, different
   shape: a marker at the start of the row. */
.nav-drawer .nav-link::after {
  display: none;
}
.nav-drawer .nav-link {
  position: relative;
  padding-left: 1.6rem;
}
body[data-nav="about"] .nav-drawer .nav-link[data-key="about"]::before,
body[data-nav="work"] .nav-drawer .nav-link[data-key="work"]::before,
body[data-nav="journal"] .nav-drawer .nav-link[data-key="journal"]::before,
body[data-nav="lab"] .nav-drawer .nav-link[data-key="lab"]::before {
  content: "";
  position: absolute;
  left: 0.75rem;
  top: 50%;
  width: 0.4rem;
  height: 0.4rem;
  margin-top: -0.2rem;
  background: var(--neon);
}

/* =========================================================================
   2. Buttons, chips, eyebrows
   ========================================================================= */

.eyebrow {
  font-size: 0.65rem;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.85rem 1.5rem;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 500;
  transition: transform 0.3s ease, background 0.3s ease, color 0.3s ease,
    border-color 0.3s ease;
}
.btn:hover {
  transform: translateY(-2px);
}
.btn-neon {
  background: var(--neon);
  color: #0a0a0a;
}
.btn-neon:hover {
  background: #e6ff86;
}
/* Carries its own ground: a bare outline disappears over bright hero media. */
.btn-ghost {
  border: 1px solid rgba(255, 255, 255, 0.45);
  background: rgba(8, 10, 8, 0.32);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: #fff;
}
.btn-ghost:hover {
  border-color: var(--neon);
  color: var(--neon);
  background: rgba(8, 10, 8, 0.5);
}
.btn-ink {
  background: var(--ink);
  color: #fff;
}
.btn-ink:hover {
  background: var(--neon);
  color: #000;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.75rem;
  border-radius: 999px;
  font-size: 0.66rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border: 1px solid rgba(255, 255, 255, 0.18);
  color: rgba(255, 255, 255, 0.7);
}
.chip iconify-icon {
  font-size: 0.9rem;
  flex-shrink: 0;
  opacity: 0.85;
}
.chip-ink {
  border-color: rgba(21, 18, 16, 0.14);
  color: rgba(21, 18, 16, 0.65);
}
.chip-neon {
  border-color: rgba(214, 255, 88, 0.45);
  color: var(--neon);
}
/* Metric highlight chip on light backgrounds (case-study Overview strip). */
.chip-metric {
  border-color: rgba(214, 255, 88, 0.55);
  background: rgba(214, 255, 88, 0.28);
  color: #5f7317;
  font-weight: 500;
}

/* Tools stage — Design → Build → Sense as an interactive loop. */
.tool-loop {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55rem 0.7rem;
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(21, 18, 16, 0.35);
}
.tool-loop iconify-icon {
  font-size: 0.85rem;
  color: rgba(21, 18, 16, 0.28);
}
.tool-loop span:nth-child(odd) {
  color: rgba(21, 18, 16, 0.55);
}

.tool-groups {
  align-items: start;
}
.tool-groups:hover .tool-group,
.tool-groups:focus-within .tool-group {
  opacity: 0.38;
  filter: grayscale(0.15);
}
.tool-groups:hover .tool-group:hover,
.tool-groups:focus-within .tool-group:focus-within,
.tool-groups .tool-group:focus-within {
  opacity: 1;
  filter: none;
}

.tool-group {
  padding: 1.35rem 1.25rem 1.15rem;
  border: 1px solid rgba(21, 18, 16, 0.1);
  border-radius: 1.25rem;
  background: rgba(255, 255, 255, 0.35);
  transition:
    opacity 0.4s cubic-bezier(0.22, 1, 0.36, 1),
    filter 0.4s ease,
    border-color 0.4s cubic-bezier(0.22, 1, 0.36, 1),
    background-color 0.4s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.45s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}
.tool-groups:hover .tool-group:hover,
.tool-groups:focus-within .tool-group:focus-within {
  border-color: rgba(21, 18, 16, 0.2);
  background: rgba(255, 255, 255, 0.88);
  box-shadow: 0 14px 36px rgba(35, 24, 18, 0.08);
  transform: translateY(-4px);
}

.tool-group-head {
  display: flex;
  gap: 0.9rem;
  align-items: flex-start;
  margin-bottom: 1.1rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid rgba(21, 18, 16, 0.08);
}
.tool-group-index {
  font-family: "Cormorant Garamond", serif;
  font-size: 1.35rem;
  line-height: 1;
  color: rgba(21, 18, 16, 0.3);
  min-width: 1.6rem;
}
.tool-group-head p {
  margin-top: 0.4rem;
  font-size: 0.82rem;
  font-weight: 300;
  line-height: 1.45;
  color: rgba(21, 18, 16, 0.48);
}

.tool-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.2rem;
}
.tool-item {
  width: 100%;
  display: block;
  text-align: left;
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  background: transparent;
  font-family: inherit;
  cursor: pointer;
  padding: 0.55rem 0.55rem;
  margin: 0 -0.55rem;
  border-radius: 0.75rem;
  transition: background-color 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
.tool-item-row {
  display: flex;
  align-items: center;
  gap: 0.7rem;
}
.tool-item-row iconify-icon {
  font-size: 1rem;
  color: rgba(21, 18, 16, 0.38);
  flex-shrink: 0;
  transition: color 0.35s ease, transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.tool-item-name {
  font-size: 0.92rem;
  font-weight: 400;
  color: rgba(21, 18, 16, 0.78);
  transition: color 0.35s ease;
}
.tool-item-note {
  display: block;
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  margin: 0;
  padding-left: 1.7rem;
  font-size: 0.78rem;
  font-weight: 300;
  line-height: 1.45;
  color: rgba(21, 18, 16, 0.5);
  transition:
    max-height 0.4s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.35s ease,
    margin 0.35s ease;
}
.tool-item:hover,
.tool-item:focus-visible {
  background: rgba(214, 255, 88, 0.22);
  outline: none;
}
.tool-item:hover .tool-item-row iconify-icon,
.tool-item:focus-visible .tool-item-row iconify-icon {
  color: var(--ink);
  transform: scale(1.08);
}
.tool-item:hover .tool-item-name,
.tool-item:focus-visible .tool-item-name {
  color: var(--ink);
}
.tool-item:hover .tool-item-note,
.tool-item:focus-visible .tool-item-note {
  max-height: 4.5rem;
  opacity: 1;
  margin-top: 0.35rem;
}

@media (prefers-reduced-motion: reduce) {
  .tool-group,
  .tool-item,
  .tool-item-note,
  .tool-item-row iconify-icon {
    transition: none;
  }
  .tool-groups:hover .tool-group:hover,
  .tool-groups:focus-within .tool-group:focus-within {
    transform: none;
  }
}

/* Legacy chip cloud (kept for any remaining chip uses / home). */
.tool-cloud {
  list-style: none;
  margin: 0;
  padding: 0;
}
.tool-cloud > li {
  display: inline-flex;
}
.tool-chip {
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  background: rgba(255, 255, 255, 0.35);
  font-family: inherit;
  line-height: 1.2;
  transition:
    transform 0.45s cubic-bezier(0.22, 1, 0.36, 1),
    background-color 0.45s cubic-bezier(0.22, 1, 0.36, 1),
    border-color 0.45s cubic-bezier(0.22, 1, 0.36, 1),
    color 0.35s ease,
    box-shadow 0.45s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.35s ease;
}
.tool-chip iconify-icon {
  transition: opacity 0.35s ease, transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}
.tool-cloud:hover .tool-chip,
.tool-cloud:focus-within .tool-chip {
  opacity: 0.38;
}
.tool-cloud:hover .tool-chip:hover,
.tool-cloud .tool-chip:focus-visible,
.tool-cloud:focus-within .tool-chip:focus {
  opacity: 1;
  transform: translateY(-3px);
  background: #fff;
  border-color: rgba(21, 18, 16, 0.28);
  color: var(--ink);
  box-shadow: 0 10px 28px rgba(35, 24, 18, 0.08);
}
.tool-cloud:hover .tool-chip:hover iconify-icon,
.tool-cloud .tool-chip:focus-visible iconify-icon,
.tool-cloud:focus-within .tool-chip:focus iconify-icon {
  opacity: 1;
  transform: scale(1.08);
}
.reveal.is-visible .tool-chip {
  animation: tool-chip-in 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.reveal.is-visible .tool-cloud > li:nth-child(1) .tool-chip { animation-delay: 0.04s; }
.reveal.is-visible .tool-cloud > li:nth-child(2) .tool-chip { animation-delay: 0.08s; }
.reveal.is-visible .tool-cloud > li:nth-child(3) .tool-chip { animation-delay: 0.12s; }
.reveal.is-visible .tool-cloud > li:nth-child(4) .tool-chip { animation-delay: 0.16s; }
.reveal.is-visible .tool-cloud > li:nth-child(5) .tool-chip { animation-delay: 0.2s; }
.reveal.is-visible .tool-cloud > li:nth-child(6) .tool-chip { animation-delay: 0.24s; }
.reveal.is-visible .tool-cloud > li:nth-child(7) .tool-chip { animation-delay: 0.28s; }
.reveal.is-visible .tool-cloud > li:nth-child(8) .tool-chip { animation-delay: 0.32s; }
.reveal.is-visible .tool-cloud > li:nth-child(9) .tool-chip { animation-delay: 0.36s; }
.reveal.is-visible .tool-cloud > li:nth-child(10) .tool-chip { animation-delay: 0.4s; }
.reveal.is-visible .tool-cloud > li:nth-child(11) .tool-chip { animation-delay: 0.44s; }
.reveal.is-visible .tool-cloud > li:nth-child(12) .tool-chip { animation-delay: 0.48s; }
.reveal.is-visible .tool-cloud > li:nth-child(13) .tool-chip { animation-delay: 0.52s; }
@keyframes tool-chip-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.badge-lime {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.65rem;
  border-radius: 0.5rem;
  background: var(--badge);
  color: #0a0a0a;
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* Underline-on-hover link used by cards and lists. */
.link-rule {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.8rem;
  padding-bottom: 0.15rem;
}
.link-rule::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--neon);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}
.link-rule:hover::after,
a:hover .link-rule::after,
article:hover .link-rule::after {
  transform: scaleX(1);
}

/* Any href that is still a {TOKEN} is inert rather than a 404 (see site.js). */
a[href^="{"] {
  cursor: not-allowed;
  opacity: 0.72;
}

/* =========================================================================
   3. Cinematic stage (home hero, case hero, lab hero)
   ========================================================================= */

.stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background: #000;
  isolation: isolate;
}

.rig {
  position: absolute;
  inset: 0;
  transform-origin: 50% 52%;
  /* will-change is toggled by hero.js only while the journey is on-screen */
}

.video-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* translateZ keeps scrubbing on its own compositor layer. */
  transform: translateZ(0) scale(1.08);
  filter: var(--hero-filter);
  backface-visibility: hidden;
}

/* Ambient hero loop (the Lab). Same family as .video-layer, but graded harder:
   the source is a fresco — bright, warm, and busy edge to edge — where the home
   hero's source was already dark. --hero-filter alone left white type sitting
   on painted highlights. */
.ambient-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.03);
  /* Barely graded. The picture is the point here — the earlier
     brightness(.46) plus the neon light and fog layers had turned a fresco
     into a dark green wash. */
  filter: saturate(0.96) contrast(1.02) brightness(0.7);
}
/* One black gradient and nothing else over the frame: strongest where the type
   block sits, gone by the right edge, and never reaching the bottom — a floor
   of black there would read as the video stopping short of the section. */
.ambient-scrim {
  position: absolute;
  inset: 0;
  background:
    /* A soft pool under the type block. Measured, not guessed: without it the
       fresco's brightest highlight drifts under the headline and white drops
       to 2.1:1. Local darkening buys the contrast that a heavier wash over the
       whole frame would have cost the picture. */
    radial-gradient(
      58% 62% at 26% 50%,
      rgba(0, 0, 0, 0.8) 0%,
      rgba(0, 0, 0, 0.52) 45%,
      transparent 78%
    ),
    linear-gradient(
      86deg,
      rgba(0, 0, 0, 0.62) 0%,
      rgba(0, 0, 0, 0.5) 30%,
      rgba(0, 0, 0, 0.27) 58%,
      rgba(0, 0, 0, 0.12) 82%,
      rgba(0, 0, 0, 0.05) 100%
    );
}
@media (max-width: 900px) {
  /* One column: the type crosses the whole frame, so the gradient turns to run
     with it rather than across it. */
  .ambient-scrim {
    background: linear-gradient(
      170deg,
      rgba(0, 0, 0, 0.3) 0%,
      rgba(0, 0, 0, 0.62) 45%,
      rgba(0, 0, 0, 0.72) 100%
    );
  }
}

/* Neutral atmosphere. Same layers, same shapes, none of the neon: over a
   painting the #d6ff58 bloom reads as a colour cast rather than light. Used by
   the /lab hero, and by anything else that ever sits atmosphere over an image
   with colour of its own. */
.atmos-neutral .lights {
  background:
    radial-gradient(38% 42% at 22% 32%, rgba(255, 246, 224, 0.16), transparent 70%),
    radial-gradient(46% 50% at 78% 62%, rgba(150, 190, 235, 0.14), transparent 72%);
}
.atmos-neutral .fog-back {
  background:
    radial-gradient(52% 60% at 30% 50%, rgba(190, 205, 220, 0.22), transparent 72%),
    radial-gradient(48% 54% at 74% 44%, rgba(235, 228, 210, 0.14), transparent 70%);
  opacity: 0.42;
}
.atmos-neutral .fog-front {
  opacity: 0.4;
}
.atmos-neutral .rays {
  opacity: 0.3;
}
/* The particles drift, so any one of them can land inside the headline as a
   bright point. Halved here: still visible against the fresco, no longer the
   brightest thing behind a letter. */
.atmos-neutral .particle-canvas {
  opacity: 0.34;
}
/* Softer than the standard vignette, which put a hard black band across the
   bottom of the frame. */
.atmos-neutral .vignette {
  background:
    linear-gradient(180deg, rgba(0, 0, 0, 0.34) 0%, transparent 22%),
    linear-gradient(0deg, rgba(0, 0, 0, 0.42) 0%, transparent 26%),
    radial-gradient(120% 90% at 50% 45%, transparent 52%, rgba(0, 0, 0, 0.42) 100%);
}

/* Type sitting directly on moving media. The scrim does most of the work; this
   is the last few points of contrast for the frames where a bright highlight
   drifts under a letter. */
.on-media {
  text-shadow: 0 2px 26px rgba(0, 0, 0, 0.55), 0 1px 3px rgba(0, 0, 0, 0.45);
}

/* Duplicated, blurred copy of the frame that reads as depth-of-field haze. */
.depth-layer {
  position: absolute;
  inset: -6%;
  background-size: cover;
  background-position: center;
  mix-blend-mode: screen;
  filter: blur(1.5rem) saturate(1.1);
  opacity: 0.38;
  pointer-events: none;
}

.rays,
.lights {
  pointer-events: none;
  position: absolute;
  /* Overscanned so the progress-driven transforms in hero.js never expose an
     edge as the layers drift, scale and rotate through the fly-through. */
  inset: -12%;
  mix-blend-mode: screen;
}
.lights {
  background:
    radial-gradient(38% 42% at 22% 32%, rgba(214, 255, 88, 0.22), transparent 70%),
    radial-gradient(46% 50% at 78% 62%, rgba(120, 190, 255, 0.18), transparent 72%);
}
.rays {
  background: repeating-linear-gradient(
    102deg,
    rgba(255, 255, 255, 0.075) 0px,
    rgba(255, 255, 255, 0.075) 2px,
    transparent 2px,
    transparent 46px
  );
  filter: blur(2px);
  opacity: 0.5;
}

.fog {
  pointer-events: none;
  position: absolute;
  inset-inline: -15%;
  mix-blend-mode: screen;
}
.fog-back {
  top: 8%;
  height: 62%;
  background: radial-gradient(
      52% 60% at 30% 50%,
      rgba(180, 200, 220, 0.3),
      transparent 72%
    ),
    radial-gradient(48% 54% at 74% 44%, rgba(214, 255, 88, 0.14), transparent 70%);
  filter: blur(2.4rem);
  opacity: 0.55;
}
.fog-front {
  bottom: -10%;
  height: 58%;
  background: radial-gradient(
      60% 70% at 50% 90%,
      rgba(255, 255, 255, 0.24),
      transparent 74%
    ),
    radial-gradient(40% 46% at 18% 70%, rgba(150, 190, 255, 0.2), transparent 70%);
  filter: blur(3rem);
  opacity: 0.6;
}

.particle-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0.7;
  pointer-events: none;
}

.impact-flash {
  pointer-events: none;
  position: absolute;
  inset: 0;
  z-index: 25;
  opacity: 0;
  mix-blend-mode: screen;
  background: radial-gradient(
      60% 60% at 50% 50%,
      rgba(255, 255, 255, 0.95),
      transparent 70%
    ),
    linear-gradient(180deg, rgba(150, 200, 255, 0.55), rgba(255, 255, 255, 0.2));
}

/* Anchors the frame and buys back contrast for the white type. The hero media
   can be bright — a daylit sky leaves white text with almost nothing to sit
   against — so this adds a top and bottom band on top of the radial falloff.
   It stays below the text layers (z-20) and above the figure (z-15). */
.vignette {
  pointer-events: none;
  position: absolute;
  inset: 0;
  z-index: 18;
  background: linear-gradient(
      180deg,
      rgba(0, 0, 0, 0.42) 0%,
      rgba(0, 0, 0, 0.1) 26%,
      rgba(0, 0, 0, 0.08) 52%,
      rgba(0, 0, 0, 0.55) 100%
    ),
    radial-gradient(120% 100% at 50% 45%, transparent 40%, rgba(0, 0, 0, 0.72) 100%);
}

/* Case-study / Lab mini-hero cover — graded a touch harder than the home
   video layer: case heroes sit type on stills that are often bright paintings
   or product shots, not already-dark footage. */
.case-cover {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.06);
  filter: saturate(0.88) contrast(1.12) brightness(0.58);
}

/* Light key visuals (product/system boards) — no grade, no dark wash. */
.case-cover--clean {
  transform: none;
  filter: none;
  object-fit: contain;
  object-position: center;
}

/* Full-bleed case cover without the dark grade (e.g. Seenova black hero). */
.case-cover--flat {
  transform: none;
  filter: none;
}

/* Case mini-hero scrim. Type lives on the floor of the frame (title + meta
   bar), so the wash runs upward from the bottom — same rule as .ambient-scrim
   on /lab: it must sit ABOVE the screen-blend atmosphere, or the fog/lights
   brighten it right back and white drops below AA. */
.case-scrim {
  pointer-events: none;
  position: absolute;
  inset: 0;
  z-index: 19;
  background: linear-gradient(
    0deg,
    rgba(0, 0, 0, 0.82) 0%,
    rgba(0, 0, 0, 0.62) 26%,
    rgba(0, 0, 0, 0.32) 52%,
    rgba(0, 0, 0, 0.1) 72%,
    transparent 88%
  );
}

/* Case-study brand banners — solid brand fill only. No cover, fog, or wash. */
.case-hero[data-brand] {
  --brand: var(--neon);
  background: var(--brand) !important;
}
.case-hero[data-brand="seenova"] {
  --brand: var(--brand-seenova);
}
.case-hero[data-brand="directam"] {
  --brand: var(--brand-directam);
}
.case-hero[data-brand="airplus"] {
  --brand: var(--brand-airplus);
}

.case-hero[data-brand] .case-cover,
.case-hero[data-brand] .fog,
.case-hero[data-brand] .lights,
.case-hero[data-brand] .vignette,
.case-hero[data-brand] .case-cover-rive,
.case-hero[data-brand] .case-cover-poster {
  display: none !important;
}

.case-hero[data-brand] dl {
  border-color: rgba(255, 255, 255, 0.28);
}

/* Interactive Rive cover (Seenova). Poster underneath; canvas takes over on load.
   Copy stays clickable for the back-link; the rest of the hero passes pointer
   events through so the state machine can track the cursor. */
.case-cover-rive {
  display: block;
  object-fit: unset;
  opacity: 0;
  transition: opacity 0.45s ease;
  /* Sits under fog/lights (DOM order) but still receives the pointer because
     those atmosphere layers use pointer-events: none. */
  pointer-events: auto;
}
.case-cover-rive.is-ready {
  opacity: 1;
}
.case-cover-poster.is-replaced {
  opacity: 0;
  transition: opacity 0.45s ease;
}
.case-hero-copy {
  pointer-events: none;
}
.case-hero-copy a {
  pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
  .case-cover-rive {
    display: none;
  }
  .case-cover-poster.is-replaced {
    opacity: 1;
  }
}

/* In-page Rive stage (Seenova black section) — framed canvas, no hero grade. */
.rive-stage {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: 1.5rem;
  overflow: hidden;
  background:
    radial-gradient(70% 60% at 50% 0%, rgba(214, 255, 88, 0.06), transparent 70%),
    #0a0a0a;
  border: 1px solid rgba(255, 255, 255, 0.08);
}
.rive-stage-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  opacity: 0;
  transition: opacity 0.45s ease;
  pointer-events: auto;
  cursor: crosshair;
}
.rive-stage-canvas.is-ready {
  opacity: 1;
}
.rive-stage-fallback {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  margin: 0;
  padding: 2rem;
  text-align: center;
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.35);
  transition: opacity 0.45s ease;
  pointer-events: none;
}
.rive-stage-fallback.is-replaced {
  opacity: 0;
}
@media (prefers-reduced-motion: reduce) {
  .rive-stage-canvas {
    display: none;
  }
  .rive-stage-fallback.is-replaced {
    opacity: 1;
  }
}

/* --- HUD ---------------------------------------------------------------- */

.hud {
  position: absolute;
  z-index: 30;
  color: rgba(255, 255, 255, 0.82);
  font-size: 0.62rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}
.hud-left {
  top: 6.5rem;
  left: 1.75rem;
}
.hud-right {
  top: 6.5rem;
  right: 1.75rem;
  text-align: right;
}
@media (min-width: 768px) {
  .hud-left {
    left: 2.75rem;
  }
  .hud-right {
    right: 2.75rem;
  }
}
/* The chapter word sits directly under the nav card on a phone and repeats the
   eyebrow of whichever scene is on screen. The progress bar alone keeps the
   position readable without the crowding. */
@media (max-width: 767px) {
  #hudChapter {
    display: none;
  }
  .hud-right .hud-bar {
    margin-top: 0;
    width: 5rem;
  }
}
.hud-bar {
  margin-top: 0.6rem;
  width: 7.5rem;
  height: 2px;
  background: rgba(255, 255, 255, 0.18);
  overflow: hidden;
}
.hud-bar span {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--neon);
  transform: scaleX(0);
  transform-origin: left;
}

/* --- Scroll cue --------------------------------------------------------- */

.scroll-cue {
  position: absolute;
  z-index: 30;
  bottom: 2.4rem;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  pointer-events: none;
  color: rgba(255, 255, 255, 0.82);
  font-size: 0.6rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55), 0 0 18px rgba(0, 0, 0, 0.35);
}
.scroll-cue-line {
  position: relative;
  display: block;
  width: 1px;
  height: 3.5rem;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.22);
}
/* A lit segment falling down the track — the movement is the instruction. */
.scroll-cue-line i {
  position: absolute;
  left: 0;
  right: 0;
  top: -45%;
  height: 45%;
  background: #fff;
  animation: cue-travel 2.3s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
@keyframes cue-travel {
  0% {
    top: -45%;
  }
  65%,
  100% {
    top: 100%;
  }
}
@media (max-width: 767px) {
  .scroll-cue {
    bottom: 1.6rem;
  }
  .scroll-cue-line {
    height: 2.6rem;
  }
}

/* Mobile / coarse pointers: cheaper atmosphere. Large CSS blurs on full-bleed
   layers are the dominant GPU cost beside the video itself. */
@media (max-width: 900px), (pointer: coarse) {
  .depth-layer {
    filter: blur(0.85rem) saturate(1.05);
    opacity: 0.28;
  }
  .fog-back {
    filter: blur(1.4rem);
    opacity: 0.42;
  }
  .fog-front {
    filter: blur(1.6rem);
    opacity: 0.45;
  }
  .rays {
    filter: none;
    opacity: 0.35;
  }
}

@media (prefers-reduced-data: reduce) {
  .depth-layer,
  .fog,
  .rays {
    display: none;
  }
}

/* --- Scenes ------------------------------------------------------------- */

.scene {
  position: absolute;
  inset: 0;
  z-index: 20;
  display: flex;
  pointer-events: none;
}
.scene-final {
  z-index: 30;
}
.scene-final a {
  pointer-events: auto;
}

/* On a portrait phone the closing scene is read as a title card: the figure
   holds the top band, the copy is anchored low, and the landscape breathes
   between them instead of leaving a third of the screen empty under the
   buttons. */
@media (max-width: 767px) {
  .scene.scene-final {
    align-items: flex-end;
    padding-bottom: 8rem;
  }
  /* The copy now lands on the lit hillside — the one place in the frame where
     white type loses contrast. The scrim fades in and out with the scene. */
  .scene.scene-final::before {
    content: "";
    position: absolute;
    z-index: -1;
    inset: auto 0 0;
    height: 48%;
    background: linear-gradient(
      to top,
      rgba(3, 7, 9, 0.66),
      rgba(3, 7, 9, 0.28) 45%,
      rgba(3, 7, 9, 0)
    );
  }
}

.scene-title {
  font-family: "Cormorant Garamond", serif;
  font-weight: 500;
  color: #fff;
  line-height: 0.94;
  letter-spacing: -0.03em;
  text-shadow: 0 2px 26px rgba(0, 0, 0, 0.5), 0 1px 3px rgba(0, 0, 0, 0.42);
}

/* Sub-lines and eyebrows are small and thin — they need the shadow more than
   the headlines do. */
.scene p,
.scene .eyebrow,
.hud {
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55), 0 0 18px rgba(0, 0, 0, 0.35);
}

/* Sized by width with a height cap, so the slot works for a landscape figure
   flying in from the right as well as for a standing portrait — object-fit
   keeps either one undistorted inside the box. */
.portrait-layer {
  position: absolute;
  z-index: 15;
  /* Pulled in off the right edge so the whole figure reads inside the frame
     instead of flying out of it, while staying clear of the text on the left. */
  right: 9%;
  bottom: 16%;
  width: clamp(20rem, 44vw, 40rem);
  pointer-events: none;
  will-change: transform, opacity;
}
.portrait-layer img {
  width: 100%;
  height: auto;
  max-height: 78vh;
  object-fit: contain;
  object-position: right bottom;
  filter: drop-shadow(0 30px 60px rgba(0, 0, 0, 0.6)) contrast(1.05)
    saturate(0.95);
}
@media (max-width: 767px) {
  .portrait-layer {
    width: 88vw;
    right: 6%;
    /* Centred in the frame and sitting directly above the copy, so the figure
       and the text read as one stack instead of two separate corners. */
    top: 38%;
    bottom: auto;
    opacity: 0.85;
  }
}

/* =========================================================================
   4. Reveals
   ========================================================================= */

.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.9s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}
.reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* =========================================================================
   5. Cards
   ========================================================================= */

/* Selected Work cards.
   The whole card is one link, so it carries the border and the hover state and
   the children stay decoration. Nothing here describes the project — the cover,
   the discipline line and the name are enough to choose from; the reading
   happens on the case study page. */
.series-card {
  display: block;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 1.75rem;
  padding: 0.75rem 0.75rem 1.35rem;
  background: rgba(255, 255, 255, 0.02);
  transition: border-color 0.6s cubic-bezier(0.22, 1, 0.36, 1),
    background-color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
/* Hover stays colourless on purpose: the only thing that changes chromatically
   is the cover, which goes from grayscale to its own colour. A neon frame here
   would compete with that — the photograph is the reward, not the border. */
.work-card:hover .series-card,
.work-card:focus-within .series-card {
  border-color: rgba(255, 255, 255, 0.3);
  background: rgba(255, 255, 255, 0.05);
}

.series-media {
  overflow: hidden;
  border-radius: 1.25rem;
  aspect-ratio: 4 / 5;
  background: #0d0d0d;
}

.series-kicker {
  margin: 1.15rem 0 0;
  padding-inline: 0.5rem;
  color: var(--neon);
  font-size: 0.6rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

.series-title {
  margin: 0.5rem 0 0;
  padding-inline: 0.5rem;
  font-family: "Cormorant Garamond", serif;
  font-size: clamp(1.6rem, 2.4vw, 2rem);
  font-weight: 300;
  line-height: 1.1;
  color: #fff;
}

/* Section headline. One line, set on the same 72rem column as everything else,
   sized to sit under an eyebrow without competing with the hero. */
.section-title {
  font-family: "Cormorant Garamond", serif;
  font-weight: 400;
  font-size: clamp(2rem, 4.4vw, 3.2rem);
  line-height: 1.04;
  letter-spacing: -0.01em;
  max-width: 34rem;
  /* A two-line headline should break where the sentence does, not wherever the
     column runs out. */
  text-wrap: balance;
}

/* A small neon square set before a section eyebrow. */
.section-mark {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
}
.section-mark::before {
  content: "";
  width: 0.4rem;
  height: 0.4rem;
  background: var(--neon);
  flex: none;
}

.work-card figure {
  overflow: hidden;
}
.work-card img {
  filter: grayscale(1);
  transition: filter 1s cubic-bezier(0.22, 1, 0.36, 1),
    transform 1s cubic-bezier(0.22, 1, 0.36, 1);
}
.work-card:hover img,
.work-card:focus-within img {
  filter: grayscale(0);
  transform: scale(1.05);
}

.work-card--brand .work-poster {
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
}
.work-card--brand[data-brand="directam"] .chip {
  border-color: color-mix(in srgb, var(--brand-directam) 45%, transparent);
}
.work-card--brand[data-brand="airplus"] .chip {
  border-color: color-mix(in srgb, var(--brand-airplus-2) 50%, transparent);
}
.work-card--brand[data-brand="seenova"] .chip {
  border-color: color-mix(in srgb, var(--brand-seenova) 45%, transparent);
}

/* /work is a full night page — keep body bg black even if html defaults to paper. */
body.page-work {
  background: var(--night);
  color: #fff;
}

/* Lab project cards share a row height; meta + links sit at the bottom. */
.lab-grid > .work-card {
  display: flex;
  flex-direction: column;
  height: 100%;
}
.lab-grid .lab-card-body {
  display: flex;
  flex-direction: column;
  flex: 1;
}
.lab-grid .lab-card-foot {
  margin-top: auto;
}

/* Portrait frame for a transparent cutout.
   A cutout has no background of its own, so the frame supplies one — a warm
   panel with a soft shadow pooled at the base, which reads as the figure
   standing on it rather than floating. object-fit is contain so the whole
   subject survives; anchoring to the bottom keeps the feet on the panel and
   the headroom above. A rectangular photo dropped in here instead should use
   object-cover — swap .img-cutout for `h-full w-full object-cover`. */
.figure-portrait {
  background:
    radial-gradient(90% 55% at 50% 100%, rgba(21, 18, 16, 0.14), transparent 72%),
    linear-gradient(180deg, #efe9e2 0%, #e2d9cd 100%);
}
.img-cutout {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;
}

/* Capability loop — stations on a track + one content stage.
   Nodes carry only index/icon/label. Titles live once in the panel.
   A courier runs the track; on first view it closes the loop once. */
.cap-loop {
  --cap-count: 4;
  --cap-active: 0;
  --cap-progress: 0;
  position: relative;
}

.cap-stations {
  position: relative;
}
.cap-orbit {
  position: absolute;
  left: 0;
  right: 0;
  top: 0.35rem;
  height: 3.1rem;
  pointer-events: none;
  z-index: 0;
}
.cap-track {
  position: absolute;
  left: 12.5%;
  right: 12.5%;
  top: 50%;
  height: 2px;
  margin-top: -1px;
  background: rgba(21, 18, 16, 0.1);
  border-radius: 999px;
  overflow: visible;
}
.cap-track-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: calc(var(--cap-progress) * 100%);
  background: linear-gradient(90deg, rgba(214, 255, 88, 0.35), var(--neon));
  border-radius: inherit;
  transition: width 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}
.cap-courier {
  position: absolute;
  top: 50%;
  left: 0;
  width: 0.7rem;
  height: 0.7rem;
  margin-top: -0.35rem;
  margin-left: -0.35rem;
  border-radius: 999px;
  background: var(--ink);
  box-shadow: 0 0 0 4px rgba(214, 255, 88, 0.55);
  transition: left 0.55s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: left;
}
.cap-return {
  position: absolute;
  left: 12.5%;
  right: 12.5%;
  top: 50%;
  height: 1.6rem;
  border: 2px solid rgba(21, 18, 16, 0.08);
  border-top: 0;
  border-radius: 0 0 1.35rem 1.35rem;
  opacity: 0;
  transform: scaleY(0.35);
  transform-origin: top center;
  transition:
    opacity 0.5s ease,
    transform 0.55s cubic-bezier(0.22, 1, 0.36, 1),
    border-color 0.45s ease;
}
.cap-loop.is-closing .cap-return,
.cap-loop[data-step="build"] .cap-return {
  opacity: 1;
  transform: scaleY(1);
  border-color: rgba(214, 255, 88, 0.55);
}

.cap-nodes {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.5rem;
  position: relative;
  z-index: 1;
  padding-bottom: 0.35rem;
}
.cap-node {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.7rem;
  padding: 0.35rem 0.4rem 0.5rem;
  border: 0;
  background: transparent;
  font: inherit;
  color: inherit;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  outline: none;
  transition: opacity 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.cap-loop.is-engaged .cap-node:not(.is-active):not(.is-preview) {
  opacity: 0.38;
}
.cap-node-ring {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 3.1rem;
  height: 3.1rem;
  border-radius: 999px;
  border: 1px solid rgba(21, 18, 16, 0.14);
  background: #f6f3ef;
  box-shadow: 0 0 0 0 rgba(214, 255, 88, 0);
  transition:
    border-color 0.4s cubic-bezier(0.22, 1, 0.36, 1),
    background-color 0.4s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.45s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}
.cap-icon {
  font-size: 1.2rem;
  color: rgba(21, 18, 16, 0.45);
  transition: color 0.35s ease, transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}
.cap-node-meta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
}
.cap-node-num {
  font-family: "Cormorant Garamond", serif;
  font-size: 0.95rem;
  line-height: 1;
  color: rgba(21, 18, 16, 0.3);
  transition: color 0.35s ease;
}
.cap-node-label {
  font-size: 0.58rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(21, 18, 16, 0.4);
  transition: color 0.35s ease;
}

.cap-node.is-preview .cap-node-ring {
  border-color: rgba(21, 18, 16, 0.22);
  transform: translateY(-2px);
}
.cap-node.is-active .cap-node-ring {
  border-color: transparent;
  background: var(--badge);
  box-shadow: 0 10px 28px rgba(35, 24, 18, 0.12), 0 0 0 6px rgba(214, 255, 88, 0.22);
  transform: translateY(-3px) scale(1.06);
}
.cap-node.is-active .cap-icon,
.cap-node.is-preview .cap-icon {
  color: var(--ink);
}
.cap-node.is-active .cap-icon {
  transform: scale(1.06);
}
.cap-node.is-active .cap-node-num,
.cap-node.is-active .cap-node-label,
.cap-node.is-preview .cap-node-num,
.cap-node.is-preview .cap-node-label {
  color: var(--ink);
}
.cap-node.is-done .cap-node-ring {
  border-color: rgba(214, 255, 88, 0.65);
  background: rgba(214, 255, 88, 0.18);
}
.cap-node:focus-visible .cap-node-ring {
  outline: 2px solid var(--neon);
  outline-offset: 4px;
}

.cap-panel {
  position: relative;
  margin-top: 1.35rem;
  padding: 1.45rem 1.5rem 1.55rem;
  border: 1px solid rgba(21, 18, 16, 0.1);
  border-radius: 1.2rem;
  background:
    linear-gradient(165deg, rgba(255, 255, 255, 0.88), rgba(255, 255, 255, 0.5)),
    rgba(246, 243, 239, 0.7);
  overflow: hidden;
  min-height: 11.25rem;
}
.cap-panel::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  background: var(--neon);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}
.cap-loop.is-engaged .cap-panel::before {
  transform: scaleY(1);
}
.cap-panel-inner {
  display: grid;
  gap: 0.55rem;
  max-width: 38rem;
  transition:
    opacity 0.28s ease,
    transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
.cap-panel.is-switching .cap-panel-inner {
  opacity: 0;
  transform: translateY(10px);
}
.cap-panel-kicker {
  margin: 0;
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(21, 18, 16, 0.4);
}
.cap-panel-title {
  margin: 0;
  font-family: "Cormorant Garamond", serif;
  font-weight: 400;
  font-size: clamp(1.55rem, 2.4vw, 2.05rem);
  line-height: 1.08;
}
.cap-panel-lead {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 300;
  line-height: 1.45;
  color: rgba(21, 18, 16, 0.55);
}
.cap-panel-list {
  list-style: none;
  margin: 0.55rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.4rem;
}
.cap-panel-list li {
  position: relative;
  padding-left: 0.95rem;
  font-size: 0.86rem;
  font-weight: 300;
  line-height: 1.45;
  color: rgba(21, 18, 16, 0.62);
  opacity: 0;
  transform: translateY(6px);
  transition:
    opacity 0.35s ease,
    transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.cap-panel:not(.is-switching) .cap-panel-list li {
  opacity: 1;
  transform: none;
}
.cap-panel:not(.is-switching) .cap-panel-list li:nth-child(1) { transition-delay: 0.05s; }
.cap-panel:not(.is-switching) .cap-panel-list li:nth-child(2) { transition-delay: 0.12s; }
.cap-panel:not(.is-switching) .cap-panel-list li:nth-child(3) { transition-delay: 0.19s; }
.cap-panel-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 0.4rem;
  height: 1px;
  background: rgba(21, 18, 16, 0.35);
}

@media (max-width: 639px) {
  .cap-orbit {
    display: none;
  }
  .cap-nodes {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.65rem;
  }
  .cap-node {
    padding: 0.85rem 0.7rem;
    border: 1px solid rgba(21, 18, 16, 0.1);
    border-radius: 1rem;
    background: rgba(255, 255, 255, 0.4);
    flex-direction: row;
    justify-content: flex-start;
    gap: 0.75rem;
  }
  .cap-node-meta {
    align-items: flex-start;
  }
  .cap-node.is-active {
    background: rgba(255, 255, 255, 0.95);
    border-color: rgba(21, 18, 16, 0.16);
    box-shadow: 0 12px 28px rgba(35, 24, 18, 0.08);
  }
  .cap-node.is-active .cap-node-ring {
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cap-track-fill,
  .cap-courier,
  .cap-return,
  .cap-node,
  .cap-node-ring,
  .cap-icon,
  .cap-node-num,
  .cap-node-label,
  .cap-panel::before,
  .cap-panel-inner,
  .cap-panel-list li {
    transition: none;
  }
  .cap-node.is-active .cap-node-ring,
  .cap-node.is-preview .cap-node-ring,
  .cap-node.is-active .cap-icon {
    transform: none;
  }
  .cap-panel.is-switching .cap-panel-inner,
  .cap-panel-list li {
    opacity: 1;
    transform: none;
  }
}

.snap-row {
  display: flex;
  gap: 1.25rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.25) transparent;
  padding-bottom: 1rem;
}
.snap-row > * {
  scroll-snap-align: start;
  flex: 0 0 auto;
}
.snap-row::-webkit-scrollbar {
  height: 4px;
}
.snap-row::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.25);
  border-radius: 999px;
}

.empty-slot {
  border: 1px dashed rgba(255, 255, 255, 0.28);
  border-radius: 1.25rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-end;
  gap: 0.5rem;
  padding: 1.5rem;
  min-height: 17rem;
  color: rgba(255, 255, 255, 0.62);
  background: repeating-linear-gradient(
    -45deg,
    rgba(255, 255, 255, 0.03) 0px,
    rgba(255, 255, 255, 0.03) 8px,
    transparent 8px,
    transparent 18px
  );
}
.empty-slot-ink {
  border-color: rgba(21, 18, 16, 0.22);
  color: rgba(21, 18, 16, 0.55);
  background: repeating-linear-gradient(
    -45deg,
    rgba(21, 18, 16, 0.03) 0px,
    rgba(21, 18, 16, 0.03) 8px,
    transparent 8px,
    transparent 18px
  );
}

/* =========================================================================
   6. Marquee
   ========================================================================= */

.marquee {
  overflow: hidden;
  background: #000;
  border-block: 1px solid rgba(214, 255, 88, 0.18);
  padding: 0.85rem 0;
}
.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee 32s linear infinite;
}
.marquee-track span {
  font-family: "Cormorant Garamond", serif;
  font-size: 1.5rem;
  letter-spacing: 0.14em;
  color: var(--neon);
  padding-right: 1.5rem;
  white-space: nowrap;
}
@keyframes marquee {
  to {
    transform: translateX(-50%);
  }
}

/* =========================================================================
   7. Long-form prose (about, case studies, journal articles)
   ========================================================================= */

.prose-col {
  max-width: 48rem;
  margin-inline: auto;
}
.prose-col > .eyebrow {
  margin-bottom: 0;
}
.prose-col p {
  font-size: 1.03rem;
  line-height: 1.78;
  color: rgba(21, 18, 16, 0.78);
  margin-bottom: 1.15rem;
  font-weight: 300;
}
.prose-col p:last-child {
  margin-bottom: 0;
}
.prose-col h2 {
  font-family: "Cormorant Garamond", serif;
  font-size: clamp(2rem, 4vw, 2.9rem);
  line-height: 1.06;
  letter-spacing: -0.02em;
  margin-top: 1rem;
  margin-bottom: 1.1rem;
}
.prose-col h3 {
  font-family: "Cormorant Garamond", serif;
  font-size: 1.6rem;
  margin: 1.75rem 0 0.6rem;
}
.prose-col ul,
.prose-col ol {
  margin: 0 0 1.4rem;
  display: grid;
  gap: 0.55rem;
  padding: 0;
  list-style: none;
}
.prose-col li {
  position: relative;
  padding-left: 1.3rem;
  font-weight: 300;
  line-height: 1.7;
  color: rgba(21, 18, 16, 0.78);
}
.prose-col ul > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.72em;
  width: 0.45rem;
  height: 1px;
  background: rgba(21, 18, 16, 0.45);
}
/* Numbered process list — same measure as prose, shared across case studies */
.prose-col ol.case-steps {
  margin-top: 2rem;
  gap: 1.75rem;
  counter-reset: case-step;
}
.prose-col ol.case-steps > li {
  padding-left: 0;
  display: grid;
  grid-template-columns: 3.25rem minmax(0, 1fr);
  gap: 0.85rem 1.1rem;
  align-items: start;
  counter-increment: case-step;
}
.prose-col ol.case-steps > li::before {
  content: counter(case-step, decimal-leading-zero);
  font-family: "Cormorant Garamond", serif;
  font-size: 2.1rem;
  line-height: 1;
  color: rgba(21, 18, 16, 0.18);
  grid-row: 1 / span 2;
}
.prose-col ol.case-steps h3 {
  margin: 0;
  font-size: 1.45rem;
  line-height: 1.2;
}
.prose-col ol.case-steps p {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.65;
  color: rgba(21, 18, 16, 0.62);
}
.prose-col .case-metrics {
  display: flex;
  flex-wrap: wrap;
  gap: 0.65rem;
  margin-top: 2rem;
}
.prose-col .case-figure {
  margin: 2rem 0 0;
  overflow: hidden;
  border-radius: 1.25rem;
  background: #fff;
}
.prose-col .case-figure img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: top;
}
.prose-col a:not(.btn):not(.link-rule) {
  border-bottom: 1px solid rgba(21, 18, 16, 0.25);
}
.prose-col a:not(.btn):not(.link-rule):hover {
  border-color: var(--neon);
}

/* Same prose layout on dark case bands */
.prose-col--on-dark p,
.prose-col--on-dark li {
  color: rgba(255, 255, 255, 0.58);
}
.prose-col--on-dark h2,
.prose-col--on-dark h3 {
  color: #fff;
}
.prose-col--on-dark .eyebrow {
  color: var(--neon);
}
.prose-col--on-dark ul > li::before {
  background: rgba(214, 255, 88, 0.55);
}
.prose-col--on-dark ol.case-steps > li::before {
  color: rgba(255, 255, 255, 0.18);
}
.prose-col--on-dark ol.case-steps p {
  color: rgba(255, 255, 255, 0.5);
}
.prose-col--on-dark .case-figure {
  background: rgba(255, 255, 255, 0.06);
}

/* About storytelling — reading measure aligned to page content start. */
.about-story {
  max-width: 42rem;
}
.about-chapter + .about-chapter {
  margin-top: 3.25rem;
  padding-top: 3.25rem;
  border-top: 1px solid rgba(21, 18, 16, 0.08);
}
.about-chapter-mark {
  font-size: 0.62rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(21, 18, 16, 0.35);
  margin-bottom: 0.85rem;
}
.about-chapter h2 {
  font-family: "Cormorant Garamond", serif;
  font-size: clamp(1.85rem, 3.5vw, 2.55rem);
  line-height: 1.08;
  letter-spacing: -0.02em;
  margin-bottom: 1.15rem;
  color: var(--ink);
}
.about-chapter p {
  font-size: 1.03rem;
  line-height: 1.78;
  font-weight: 300;
  color: rgba(21, 18, 16, 0.72);
  margin-bottom: 1.1rem;
}
.about-chapter p:last-child {
  margin-bottom: 0;
}
.about-chapter .pull-quote {
  margin: 1.75rem 0;
}

.pull-quote {
  font-family: "Cormorant Garamond", serif;
  font-style: italic;
  font-size: clamp(1.6rem, 3.2vw, 2.3rem);
  line-height: 1.28;
  letter-spacing: -0.02em;
  border-left: 2px solid var(--neon);
  padding-left: 1.6rem;
  margin: 2.5rem 0;
  color: rgba(21, 18, 16, 0.88);
}

.placeholder-block {
  border: 1px dashed rgba(21, 18, 16, 0.28);
  border-radius: 1rem;
  padding: 1.25rem 1.4rem;
  background: rgba(21, 18, 16, 0.02);
  font-size: 0.85rem;
  line-height: 1.65;
  color: rgba(21, 18, 16, 0.6);
  margin: 1.6rem 0;
}
.placeholder-block code {
  font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
  font-size: 0.78rem;
  color: rgba(21, 18, 16, 0.85);
  background: rgba(214, 255, 88, 0.35);
  padding: 0.1rem 0.35rem;
  border-radius: 0.3rem;
}

/* A {TOKEN} standing in for a headline must not be *set* like the headline —
   at 3rem of monospace it reads as the design rather than as a hole in it.
   Shrink it to a chip that sits on the heading's baseline. */
h1 code,
h2 code,
h3 code {
  font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
  font-size: max(0.4em, 0.8rem);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1;
  display: inline-block;
  padding: 0.3em 0.5em;
  border-radius: 0.4rem;
  background: rgba(214, 255, 88, 0.18);
  border: 1px dashed currentColor;
  opacity: 0.7;
}

/* Home About teaser — two-column: greeting + thesis | portrait. */
.about-teaser-grid {
  display: grid;
  gap: 2.75rem;
  align-items: center;
}
.about-teaser-copy {
  max-width: 32rem;
}
.about-teaser-hello {
  margin: 1.25rem 0 0;
  font-family: "Cormorant Garamond", "Times New Roman", serif;
  font-size: clamp(1.55rem, 3.2vw, 2.1rem);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.about-teaser-title {
  margin-top: 0.75rem;
}
.about-teaser-lede {
  margin-top: 1.2rem;
  max-width: 28rem;
  font-size: 0.98rem;
  font-weight: 300;
  line-height: 1.7;
  color: rgba(21, 18, 16, 0.55);
  text-wrap: pretty;
}
.about-teaser-foot {
  margin-top: 1.75rem;
  padding-top: 1.2rem;
  border-top: 1px solid rgba(21, 18, 16, 0.12);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.25rem;
}
.about-teaser-meta {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 0.55rem;
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(21, 18, 16, 0.4);
  line-height: 1.5;
}
.about-teaser-meta-domains {
  display: none;
}
.about-teaser-cta {
  display: inline-flex;
}
.about-teaser-portrait {
  width: 100%;
  max-width: 22rem;
  margin-inline: auto;
  box-shadow: 0 32px 64px -36px rgba(21, 18, 16, 0.38);
}
@media (min-width: 900px) {
  .about-teaser-grid {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
    gap: clamp(3rem, 7vw, 5.5rem);
  }
  .about-teaser-meta-domains {
    display: inline;
  }
  .about-teaser-portrait {
    max-width: min(100%, 26rem);
    margin-inline: 0 0 0 auto;
  }
}

/* Personal marks on /about when laid as a row. Kept for that page only. */
.about-notes {
  margin-top: 1.75rem;
}
.about-notes > div {
  padding: 0.7rem 0;
  border-top: 1px solid rgba(21, 18, 16, 0.1);
}
.about-notes dt {
  font-family: "Cormorant Garamond", serif;
  font-size: 1.15rem;
  line-height: 1.15;
  color: var(--ink);
}
.about-notes dd {
  margin: 0.2rem 0 0;
  font-size: 0.78rem;
  font-weight: 300;
  line-height: 1.4;
  color: rgba(21, 18, 16, 0.5);
}
@media (min-width: 768px) {
  .about-notes-row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 2.5rem;
  }
  .about-notes-row > div {
    padding-bottom: 0;
  }
  .about-notes-row dt {
    font-size: 1.5rem;
  }
  .about-notes-row dd {
    font-size: 0.875rem;
    max-width: 22rem;
  }
  .about-notes-wide {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 2rem 2.5rem;
  }
  .about-notes-wide > div {
    padding-bottom: 0;
  }
  .about-notes-wide dt {
    font-size: 1.45rem;
  }
  .about-notes-wide dd {
    font-size: 0.875rem;
    max-width: 22rem;
  }
}

/* Marks placeholder writing so it can never pass for the real thing. Paired
   with a data-sample attribute on the same element: the flag is what a reader
   sees, the attribute is what `grep data-sample` finds on the way out. */
.sample-flag {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.5rem;
  border: 1px dashed rgba(21, 18, 16, 0.35);
  border-radius: 0.4rem;
  background: rgba(214, 255, 88, 0.3);
  font-size: 0.55rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(21, 18, 16, 0.7);
  white-space: nowrap;
}

/* Same block, inverted for the dark sections. */
.placeholder-block.placeholder-dark {
  border-color: rgba(255, 255, 255, 0.24);
  background: rgba(255, 255, 255, 0.03);
  color: rgba(255, 255, 255, 0.6);
}
.placeholder-block.placeholder-dark code {
  color: rgba(255, 255, 255, 0.9);
  background: rgba(214, 255, 88, 0.18);
}

/* Interactive prototype frame — the slot a live Framer/Figma file drops into.
   Until then it holds a designed empty state rather than a broken iframe. */
.prototype-frame {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: 1.5rem;
  overflow: hidden;
  border: 1px dashed rgba(255, 255, 255, 0.2);
  background:
    radial-gradient(70% 60% at 50% 0%, rgba(214, 255, 88, 0.06), transparent 70%),
    rgba(255, 255, 255, 0.03);
}
.prototype-frame iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}
.prototype-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 2rem;
  color: var(--neon);
}
.prototype-empty code {
  font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
  color: rgba(255, 255, 255, 0.8);
  background: rgba(214, 255, 88, 0.16);
  padding: 0.1rem 0.35rem;
  border-radius: 0.3rem;
}

/* Pages with a sticky sub-nav need extra anchor clearance. */
html.has-subnav {
  scroll-padding-top: 9.5rem;
}

/* Case-study sub-nav — sits below the floating header pill. */
.subnav {
  position: sticky;
  top: 5.25rem;
  z-index: 40;
  -webkit-backdrop-filter: blur(24px);
  backdrop-filter: blur(24px);
  background: rgba(246, 243, 239, 0.78);
  border-bottom: 1px solid rgba(21, 18, 16, 0.07);
}
.subnav-inner {
  display: flex;
  gap: 1.5rem;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 0.9rem 1.5rem;
  margin-inline: auto;
  max-width: 78rem;
}
.subnav-inner::-webkit-scrollbar {
  display: none;
}
.subnav a {
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(21, 18, 16, 0.55);
  padding-bottom: 0.2rem;
  border-bottom: 1px solid transparent;
  transition: color 0.25s ease, border-color 0.25s ease;
}
.subnav a:hover,
.subnav a.is-current {
  color: var(--ink);
  border-color: var(--neon);
}

/* Reading progress */
.read-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  z-index: 70;
  background: transparent;
}
.read-progress span {
  display: block;
  height: 100%;
  background: var(--neon);
  transform: scaleX(0);
  transform-origin: left;
}

/* =========================================================================
   8. Before / after slider
   ========================================================================= */

.ba {
  position: relative;
  overflow: hidden;
  border-radius: 1.25rem;
  touch-action: pan-y;
  user-select: none;
  --x: 50%;
}
.ba img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.ba-after {
  position: absolute;
  inset: 0;
  clip-path: inset(0 0 0 var(--x));
}
.ba-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--x);
  width: 2px;
  background: var(--neon);
  transform: translateX(-1px);
  cursor: ew-resize;
}
.ba-handle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 2.6rem;
  height: 2.6rem;
  transform: translate(-50%, -50%);
  border-radius: 999px;
  background: var(--neon);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}
.ba-knob {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 0.05rem;
  color: #0a0a0a;
  font-size: 0.9rem;
}
.ba-knob iconify-icon:last-child {
  transform: rotate(180deg);
}
.ba-label {
  position: absolute;
  bottom: 0.9rem;
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  font-size: 0.6rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

/* =========================================================================
   9. Journal
   ========================================================================= */

.filter-pill {
  padding: 0.5rem 1.05rem;
  border-radius: 999px;
  border: 1px solid rgba(21, 18, 16, 0.14);
  font-size: 0.78rem;
  color: rgba(21, 18, 16, 0.65);
  transition: background 0.3s ease, color 0.3s ease, border-color 0.3s ease;
}
.filter-pill:hover {
  border-color: rgba(21, 18, 16, 0.35);
}
.filter-pill.is-active {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

.journal-row {
  transition: opacity 0.4s ease;
}
.journal-row[hidden] {
  display: none;
}

/* =========================================================================
   10. Footer
   ========================================================================= */

/* Footer — three bands: the ask, the index, the legal line.
   It ends every page on the site, so it has to be complete without becoming
   the longest thing on a short page. */
.site-footer {
  background: var(--night);
  color: rgba(255, 255, 255, 0.82);
}
.footer-lede {
  padding: 5rem 0 3.5rem;
}
.footer-mail {
  font-size: 0.95rem;
  font-weight: 300;
  color: rgba(255, 255, 255, 0.75);
  border-bottom: 1px solid rgba(255, 255, 255, 0.2);
  padding-bottom: 0.2rem;
  transition: color 0.35s ease, border-color 0.35s ease;
}
.footer-mail:hover {
  color: var(--neon);
  border-color: var(--neon);
}

.footer-grid {
  display: grid;
  gap: 2.5rem;
  padding: 2.75rem 0;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}
@media (min-width: 640px) {
  .footer-grid {
    grid-template-columns: 1.4fr 1fr 1fr;
    gap: 3rem;
  }
}
.footer-label {
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.4);
  margin-bottom: 1.1rem;
}
.footer-note {
  font-size: 0.85rem;
  font-weight: 300;
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.55);
}
.footer-list {
  display: grid;
  gap: 0.6rem;
}
.footer-link {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.85rem;
  font-weight: 300;
  color: rgba(255, 255, 255, 0.68);
  transition: color 0.35s ease;
}
.footer-link:hover {
  color: var(--neon);
}
.footer-link iconify-icon {
  font-size: 0.75em;
  opacity: 0.55;
}
/* Back to top reuses the left arrow, turned to point up — one icon fewer to
   ship for a control that appears once per page. */
.footer-up {
  transform: rotate(90deg);
}

.footer-base {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  padding: 1.5rem 0 2rem;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  font-size: 0.72rem;
  color: rgba(255, 255, 255, 0.35);
}
.footer-colophon {
  font-family: "Cormorant Garamond", serif;
  font-size: 0.9rem;
  letter-spacing: 0.02em;
}

/* =========================================================================
   11. Reduced motion
   ========================================================================= */

/* =========================================================================
   11. Small screens
   The nav pill and the hero HUD are the two places where fixed-position
   content runs out of room first.
   ========================================================================= */

@media (max-width: 640px) {
  .site-header {
    padding: 0.75rem 0.75rem 0;
  }
  .nav-shell {
    gap: 0.5rem;
    padding: 0.5rem 0.5rem 0.5rem 1.1rem;
  }
  .nav-brand {
    font-size: 1.12rem;
  }
  .pill-cta {
    padding: 0.6rem 0.7rem;
  }
  /* Icon-only CTA; the anchor keeps its aria-label. */
  .pill-cta-label {
    display: none;
  }

  .hud {
    font-size: 0.55rem;
    letter-spacing: 0.16em;
  }
  .hud-left {
    top: 5.4rem;
    left: 1.1rem;
    max-width: 52%;
    white-space: normal;
    line-height: 1.5;
  }
  .hud-right {
    top: 5.4rem;
    right: 1.1rem;
  }
  .hud-bar {
    width: 5rem;
  }
}

/* =========================================================================
   12. 404 — page not found
   One screen, two columns: the apology and the ways out on the left, the
   guide on the right, both standing in the same still. The only page on the
   site that sets dark type over photography, so the scrim does the work the
   vignette does on the dark sections — and in the opposite direction.
   ========================================================================= */

.nf-stage {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 100vh;
  min-height: 100svh;
  /* Clears the fixed header pill at the top; breathing room at the bottom. */
  padding: 8.5rem 0 4.5rem;
  overflow: hidden;
  isolation: isolate;
  background: var(--paper);
}

/* A portrait still on a landscape stage, so the crop is pinned rather than
   centred: the sky has to stay behind the headline and the stepping stones
   have to stay in frame, and centring loses one or the other. */
.nf-scene {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 68%;
}

/* Ground for the type. Strongest under the copy column and gone by the time
   it reaches the figure: a wash over the whole frame would have cost the
   still the thing it was chosen for. */
.nf-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(
      58% 66% at 24% 48%,
      rgba(246, 243, 239, 0.94) 0%,
      rgba(246, 243, 239, 0.6) 48%,
      transparent 80%
    ),
    linear-gradient(
      92deg,
      rgba(246, 243, 239, 0.9) 0%,
      rgba(246, 243, 239, 0.62) 34%,
      rgba(246, 243, 239, 0.22) 64%,
      transparent 88%
    );
}

.nf-inner {
  position: relative;
  z-index: 2;
}

.nf-grid {
  display: grid;
  gap: 3rem;
  align-items: center;
}
@media (min-width: 900px) {
  .nf-grid {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    gap: clamp(2.5rem, 6vw, 5rem);
  }
}

.nf-copy {
  max-width: 34rem;
}

/* The number names the error at a glance, the sentence under it says what to
   do about it. Set the way the case studies set their step numerals — large
   and quiet — so it can be the first thing seen without being the thing that
   has to be read. It lives in the copy column rather than behind the figure:
   over grass and water an outline this size stops reading as a backdrop and
   starts reading as a smudge. */
.nf-mark {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 1rem;
}
.nf-mark-num {
  font-family: "Cormorant Garamond", serif;
  font-weight: 500;
  font-size: clamp(4rem, 9.5vw, 7.5rem);
  line-height: 0.78;
  letter-spacing: -0.04em;
  color: rgba(21, 18, 16, 0.28);
  text-shadow: 0 1px 18px rgba(246, 243, 239, 0.7);
}
.nf-mark-label {
  color: rgba(21, 18, 16, 0.48);
}

.nf-title {
  margin-top: 1.15rem;
  font-family: "Cormorant Garamond", serif;
  font-weight: 500;
  font-size: clamp(2.5rem, 6.2vw, 4.4rem);
  line-height: 0.98;
  letter-spacing: -0.03em;
  color: var(--ink);
  text-wrap: balance;
  /* The lift is paper-coloured, not black: over a bright still a dark shadow
     only gives the letters a dirty edge. */
  text-shadow: 0 1px 20px rgba(246, 243, 239, 0.8);
}

.nf-lede {
  margin-top: 1.2rem;
  max-width: 30rem;
  font-size: 0.98rem;
  font-weight: 300;
  line-height: 1.7;
  color: rgba(21, 18, 16, 0.68);
  text-wrap: pretty;
}

/* The one diagnostic on the page: what the visitor actually asked for. */
.nf-path {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.55rem;
  margin-top: 1.5rem;
  font-size: 0.6rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(21, 18, 16, 0.42);
}
.nf-path code {
  font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
  font-size: 0.72rem;
  letter-spacing: 0;
  text-transform: none;
  color: #4f6114;
  background: rgba(214, 255, 88, 0.42);
  border: 1px solid rgba(214, 255, 88, 0.75);
  border-radius: 0.4rem;
  padding: 0.2rem 0.5rem;
  max-width: 100%;
  overflow-wrap: anywhere;
}

.nf-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 2rem;
}

/* The four real destinations. A 404 that only offers "home" makes the visitor
   start their search over; these are the same four the nav carries, each with
   the one line that says whether it is the one they wanted. */
.nf-routes {
  list-style: none;
  display: grid;
  gap: 0.15rem;
  margin: 2.25rem 0 0;
  padding: 1.35rem 0 0;
  border-top: 1px solid rgba(21, 18, 16, 0.16);
}
@media (min-width: 640px) {
  .nf-routes {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.15rem 1.25rem;
  }
}

.nf-route {
  display: grid;
  grid-template-columns: 1.25rem minmax(0, 1fr) 1rem;
  align-items: center;
  gap: 0.8rem;
  padding: 0.7rem 0.8rem;
  margin-inline: -0.8rem;
  border-radius: 0.9rem;
  transition: background-color 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
.nf-route:hover,
.nf-route:focus-visible {
  background: rgba(255, 255, 255, 0.72);
}
.nf-route-icon {
  font-size: 1.15rem;
  color: rgba(21, 18, 16, 0.42);
  transition: color 0.35s ease;
}
.nf-route-name {
  display: block;
  font-size: 0.95rem;
  color: rgba(21, 18, 16, 0.9);
}
.nf-route-note {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.72rem;
  font-weight: 300;
  line-height: 1.4;
  color: rgba(21, 18, 16, 0.6);
}
.nf-route-go {
  font-size: 0.9rem;
  color: var(--ink);
  opacity: 0;
  transform: translateX(-0.35rem);
  transition: opacity 0.35s ease, transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.nf-route:hover .nf-route-icon,
.nf-route:focus-visible .nf-route-icon {
  color: var(--ink);
}
.nf-route:hover .nf-route-go,
.nf-route:focus-visible .nf-route-go {
  opacity: 1;
  transform: none;
}

.nf-help {
  margin-top: 1.6rem;
  font-size: 0.78rem;
  font-weight: 300;
  color: rgba(21, 18, 16, 0.58);
}
.nf-help a {
  color: rgba(21, 18, 16, 0.8);
  border-bottom: 1px solid rgba(21, 18, 16, 0.28);
  padding-bottom: 0.1rem;
  transition: color 0.3s ease, border-color 0.3s ease;
}
.nf-help a:hover {
  color: var(--ink);
  border-color: var(--neon);
}

/* --- The guide ---------------------------------------------------------- */

.nf-figure {
  position: relative;
  justify-self: center;
  display: flex;
  justify-content: center;
  width: 100%;
  max-width: 30rem;
  margin: 0;
}
/* A contact shadow on the grass. A cutout over a photographed ground floats
   without one, and the figure has to belong to the scene for the pointing to
   mean anything. It stays put while she drifts, which is what a shadow does. */
.nf-shadow {
  position: absolute;
  z-index: 0;
  left: 50%;
  bottom: 1%;
  width: 58%;
  height: 9%;
  transform: translateX(-50%);
  pointer-events: none;
  background: radial-gradient(
    50% 50% at 50% 50%,
    rgba(28, 40, 20, 0.34) 0%,
    rgba(28, 40, 20, 0.14) 46%,
    transparent 74%
  );
  filter: blur(0.5rem);
}
.nf-angel {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%;
  height: auto;
  max-height: 68svh;
  object-fit: contain;
  filter: drop-shadow(0 26px 44px rgba(21, 24, 16, 0.32)) contrast(1.02);
  animation: nf-float 9s ease-in-out infinite;
}
@keyframes nf-float {
  0%,
  100% {
    transform: translate3d(0, 0.5%, 0);
  }
  50% {
    transform: translate3d(0, -1.6%, 0);
  }
}

/* One column: the guide leads, the copy follows. Kept short enough that the
   headline and the first action still land above the fold on a phone. */
@media (max-width: 899px) {
  .nf-stage {
    padding: 7rem 0 3.5rem;
  }
  /* The still is portrait already, so it needs no pinning here — and the type
     now crosses the whole frame, so the wash runs with it instead of across. */
  .nf-scene {
    object-position: 50% 50%;
  }
  .nf-scrim {
    background: linear-gradient(
      180deg,
      rgba(246, 243, 239, 0.06) 0%,
      rgba(246, 243, 239, 0.34) 24%,
      rgba(246, 243, 239, 0.82) 44%,
      rgba(246, 243, 239, 0.9) 100%
    );
  }
  .nf-grid {
    gap: 1.75rem;
  }
  .nf-figure {
    order: -1;
    max-width: 16rem;
  }
  .nf-angel {
    max-height: 27svh;
  }
  .nf-mark-num {
    font-size: 3.6rem;
  }
  .nf-title {
    margin-top: 0.7rem;
  }
  .nf-routes {
    margin-top: 1.9rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .nf-angel {
    animation: none;
  }
  .nf-route,
  .nf-route-icon,
  .nf-route-go {
    transition: none;
  }
  .nf-route-go {
    opacity: 1;
    transform: none;
  }
}

/* =========================================================================
   13. Reduced motion
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .marquee-track {
    animation: none;
  }
  .scroll-cue-line i {
    animation: none;
    top: 35%;
  }
  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .work-card img,
  .series-card,
  .cap-card,
  .btn,
  .pill-cta,
  .tool-chip {
    transition: none;
  }
  .reveal.is-visible .tool-chip {
    animation: none;
  }
  body {
    transition: none;
    opacity: 1;
  }
  /* Video heroes: JS detaches sources; posters stay on the <video> element.
     Keep atmosphere cheap — no animated cue, no heavy blur stack. */
  .depth-layer {
    filter: none;
  }
  .fog,
  .rays,
  .lights,
  .particle-canvas {
    display: none;
  }
}
