/* ================================================
   SAMOYA V11 — PREMIUM MOTION SYSTEM
   Creative Developer Build
   Inspired by: Locomotive, Active Theory, Aristide Benoist
   ================================================ */

/* ---- LENIS SMOOTH SCROLL ---- */
html.lenis, html.lenis body {
  height: auto;
}
.lenis.lenis-smooth {
  scroll-behavior: auto !important;
}
.lenis.lenis-smooth [data-lenis-prevent] {
  overscroll-behavior: contain;
}

/* ---- PRELOADER ---- */
.preloader {
  position: fixed;
  inset: 0;
  z-index: 100000;
  background: #F8F9F5;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: all;
  transition: opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.preloader.is-done {
  opacity: 0;
  pointer-events: none;
}
.preloader__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
}
.preloader__logo {
  width: 40px;
  height: 40px;
  opacity: 0.6;
  animation: preloaderPulse 1.5s ease-in-out infinite;
}
@keyframes preloaderPulse {
  0%, 100% { opacity: 0.4; transform: scale(1); }
  50% { opacity: 0.8; transform: scale(1.05); }
}
.preloader__counter {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.65rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(29, 43, 30, 0.35);
}

/* ---- PAGE TRANSITIONS ---- */
.page-transition {
  position: fixed;
  inset: 0;
  z-index: 99999;
  background: #1D2B1E;
  transform: scaleY(0);
  transform-origin: bottom;
  pointer-events: none;
  will-change: transform;
}

/* ---- FILM GRAIN OVERLAY ---- */
.grain-overlay {
  position: fixed;
  top: -50%;
  left: -50%;
  width: 200%;
  height: 200%;
  pointer-events: none;
  z-index: 9999;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
  animation: grainShift 0.5s steps(4) infinite;
}
@keyframes grainShift {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(-2%, -3%); }
  50%  { transform: translate(1%, 2%); }
  75%  { transform: translate(-1%, 1%); }
  100% { transform: translate(2%, -2%); }
}

/* ---- SCROLL PROGRESS BAR ---- */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 2px;
  background: linear-gradient(90deg, rgba(29, 43, 30, 0.08), rgba(29, 43, 30, 0.25));
  transform-origin: left;
  transform: scaleX(0);
  z-index: 10000;
  pointer-events: none;
  will-change: transform;
}

/* ---- CUSTOM CURSOR ---- */
.custom-cursor {
  width: 18px;
  height: 18px;
  border: 1.5px solid rgba(29, 43, 30, 0.25);
  border-radius: 50%;
  position: fixed;
  pointer-events: none;
  z-index: 99998;
  transition: width 0.4s cubic-bezier(0.16, 1, 0.3, 1),
              height 0.4s cubic-bezier(0.16, 1, 0.3, 1),
              border-color 0.3s ease,
              background 0.3s ease,
              opacity 0.3s ease;
  transform: translate(-50%, -50%);
  will-change: transform;
  mix-blend-mode: difference;
  opacity: 0;
}
.custom-cursor.is-visible {
  opacity: 1;
}
.custom-cursor.is-hovering {
  width: 56px;
  height: 56px;
  border-color: rgba(29, 43, 30, 0.5);
  background: rgba(29, 43, 30, 0.04);
}
/* Cursor label */
.custom-cursor__label {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-family: 'JetBrains Mono', monospace;
  font-size: 7px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(29, 43, 30, 0.7);
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.2s ease;
  pointer-events: none;
}
.custom-cursor.is-hovering .custom-cursor__label {
  opacity: 1;
}
@media (pointer: coarse) {
  .custom-cursor { display: none; }
}

/* ---- KEN BURNS + PARALLAX IMAGE BREAKS ---- */
.img-break {
  overflow: hidden;
  position: relative;
}
.img-break img {
  will-change: transform;
  transform: scale(1.15);
  transition: none;
}
.img-break .img-break__overlay {
  background: linear-gradient(
    to bottom,
    rgba(29, 43, 30, 0.15) 0%,
    rgba(29, 43, 30, 0.55) 50%,
    rgba(29, 43, 30, 0.15) 100%
  );
  mix-blend-mode: multiply;
}
.img-break__text {
  opacity: 0;
  transform: translateY(40px);
}
.img-break__text.is-visible {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 1.2s cubic-bezier(0.16, 1, 0.3, 1),
              transform 1.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.img-break--clip {
  clip-path: inset(8% 0);
  transition: clip-path 1s cubic-bezier(0.16, 1, 0.3, 1);
}
.img-break--clip.is-revealed {
  clip-path: inset(0% 0);
}

/* ---- SPLIT TEXT ANIMATION ---- */
.split-word {
  display: inline-block;
  overflow: hidden;
}
.split-word span {
  display: inline-block;
  transform: translateY(110%);
  will-change: transform;
}

/* ---- REVEAL SYSTEM ---- */
.reveal-up {
  opacity: 0;
  transform: translateY(24px);
  will-change: transform, opacity;
}
.reveal-up.is-visible {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
              transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}

/* Stagger delays for children */
.stagger-children > * { transition-delay: 0s; }
.stagger-children.is-visible > *:nth-child(1) { transition-delay: 0s; }
.stagger-children.is-visible > *:nth-child(2) { transition-delay: 0.08s; }
.stagger-children.is-visible > *:nth-child(3) { transition-delay: 0.16s; }
.stagger-children.is-visible > *:nth-child(4) { transition-delay: 0.24s; }
.stagger-children.is-visible > *:nth-child(5) { transition-delay: 0.32s; }
.stagger-children.is-visible > *:nth-child(6) { transition-delay: 0.40s; }

/* ---- NUMBER COUNTER ---- */
.counter-value {
  font-variant-numeric: tabular-nums;
}

/* ---- MAGNETIC BUTTONS ---- */
.mag-btn {
  position: relative;
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

/* ---- HORIZONTAL SCROLL SECTION ---- */
.h-scroll-container {
  overflow: hidden;
  position: relative;
}
.h-scroll-track {
  display: flex;
  flex-wrap: nowrap;
  gap: 2rem;
  will-change: transform;
  padding: 0 2rem;
}
.h-scroll-track > * {
  flex-shrink: 0;
  width: 340px;
}
@media (max-width: 768px) {
  .h-scroll-track > * {
    width: 85vw;
  }
}

/* ---- DOT GRID BREATHING ---- */
@keyframes breathe {
  0%, 100% { opacity: 0.06; }
  50% { opacity: 0.14; }
}
.dot-breathe {
  animation: breathe 8s ease-in-out infinite;
}

/* ---- TEXT SCRAMBLE ---- */
.text-scramble {
  font-variant-numeric: tabular-nums;
}
.text-scramble .char {
  display: inline-block;
  will-change: opacity, transform;
}

/* ---- SECTION TRANSITION BLEND ---- */
section {
  position: relative;
  z-index: 1;
}

/* ---- HERO GRADIENT NOISE CANVAS ----
   Sits behind the hero's transparent text column so the sage noise field is
   actually visible. Masked away from the vertical middle so it never sits
   behind the headline/paragraph and erodes text contrast (global rule 51). */
.hero-shader-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
  opacity: 0.16;
  mix-blend-mode: overlay;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,0.12) 34%, rgba(0,0,0,0.12) 66%, #000 100%);
  mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,0.12) 34%, rgba(0,0,0,0.12) 66%, #000 100%);
}

/* ================================================
   HERO STAGE (2026-07-23 depth pass)
   ================================================ */

/* Fine engineering grid on the hero's text column. Fades out before it
   reaches the copy so it reads as atmosphere, not as a table. */
.hero-grid {
  z-index: 0;
  background-image:
    linear-gradient(to right, rgba(29,43,30,0.055) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(29,43,30,0.055) 1px, transparent 1px);
  background-size: 88px 88px;
  -webkit-mask-image: radial-gradient(120% 90% at 0% 100%, #000 0%, transparent 72%);
  mask-image: radial-gradient(120% 90% at 0% 100%, #000 0%, transparent 72%);
}

/* Live-status dot on the hero eyebrow. */
.hero-pulse {
  position: relative;
  width: 6px;
  height: 6px;
  flex-shrink: 0;
  border-radius: 50%;
  background: #2C422E;
}
.hero-pulse::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  border: 1px solid rgba(44,66,46,0.5);
  animation: hero-pulse-ring 2.8s cubic-bezier(0.16,1,0.3,1) infinite;
}
@keyframes hero-pulse-ring {
  0%   { transform: scale(0.6); opacity: 0.9; }
  70%  { transform: scale(1.6); opacity: 0; }
  100% { transform: scale(1.6); opacity: 0; }
}

/* Hairline lattice over the hero painting: reads as an instrument overlay
   while keeping the image clearly legible (global rule 53). */
.hero-media__lattice {
  z-index: 1;
  background-image:
    linear-gradient(to right, rgba(248,249,245,0.10) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(248,249,245,0.10) 1px, transparent 1px);
  background-size: 88px 88px;
  -webkit-mask-image: linear-gradient(200deg, #000 0%, transparent 58%);
  mask-image: linear-gradient(200deg, #000 0%, transparent 58%);
}

/* Depth on the painting: darkened outer edges, seam shadow at the left join. */
.hero-media__vignette {
  z-index: 2;
  background:
    linear-gradient(to right, rgba(29,43,30,0.30) 0%, transparent 14%),
    radial-gradient(130% 110% at 50% 45%, transparent 42%, rgba(29,43,30,0.34) 100%);
}

/* The hero image itself gets a slow scale so it is never dead-still. */
.hero-media__img {
  transform: scale(1.06);
  transform-origin: 60% 50%;
  will-change: transform;
}

/* Instrument rail across the base of the hero. */
.hero-rail__line {
  display: block;
  width: 56px;
  height: 1px;
  background: rgba(248,249,245,0.28);
  position: relative;
  overflow: hidden;
}
.hero-rail__line::after {
  content: "";
  position: absolute;
  inset: 0;
  background: #8cd98c;
  transform: translateX(-100%);
  animation: hero-rail-sweep 3.4s cubic-bezier(0.65,0,0.35,1) infinite;
}
@keyframes hero-rail-sweep {
  0%   { transform: translateX(-100%); }
  55%  { transform: translateX(100%); }
  100% { transform: translateX(100%); }
}

@media (prefers-reduced-motion: reduce) {
  .hero-pulse::after,
  .hero-rail__line::after { animation: none; }
}

/* Client-results cells: a hairline grid rather than floating cards, so the
   numerals read as instrument readouts. */
.stat-cell {
  transition: background-color 0.4s cubic-bezier(0.16,1,0.3,1);
  position: relative;
}
.stat-cell::before {
  content: "";
  position: absolute;
  left: 0;
  top: -1px;
  width: 0;
  height: 1px;
  background: #8cd98c;
  transition: width 0.5s cubic-bezier(0.16,1,0.3,1);
}
.stat-cell:hover { background-color: rgba(140,217,140,0.05); }
.stat-cell:hover::before { width: 100%; }

/* ---- SUBPAGE HERO ATMOSPHERE (2026-07-23) ----
   Standard page heroes were flat cream with nothing in them. This puts the
   same engineering grid used on the homepage into the OUTER GUTTERS only:
   the mask is fully transparent across the middle 60% of the section, so no
   grid line can ever sit behind centred copy and pull it under 4.5:1
   (global rule 51). Structure is untouched. */
.hero-atmos {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image:
    linear-gradient(to right, rgba(29,43,30,0.06) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(29,43,30,0.06) 1px, transparent 1px);
  background-size: 88px 88px;
  -webkit-mask-image:
    linear-gradient(to right, #000 0%, transparent 20%, transparent 80%, #000 100%),
    linear-gradient(to bottom, #000 0%, #000 62%, transparent 96%);
  mask-image:
    linear-gradient(to right, #000 0%, transparent 20%, transparent 80%, #000 100%),
    linear-gradient(to bottom, #000 0%, #000 62%, transparent 96%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}
/* On dark heroes the grid must be drawn in light, not in sage-900 on sage-900. */
.bg-sage-900 .hero-atmos {
  background-image:
    linear-gradient(to right, rgba(230,235,225,0.07) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(230,235,225,0.07) 1px, transparent 1px);
}

/* <header> heroes are not covered by the blanket section{position:relative}. */
.hero-atmos-host { position: relative; }
.hero-atmos-host > *:not(.hero-atmos):not(.hero-field__canvas) {
  position: relative;
  z-index: 1;
}

/* ================================================
   LIVING SYSTEM MAP (2026-07-23)
   Nodes are real anchors laid over a canvas. Before JS runs they sit in
   normal flow as a readable list, so the section is never a blank box.
   ================================================ */
.system-map {
  position: relative;
  width: 100%;
  /* Constrained so the nodes cluster and read as one connected system.
     At full 1400px width they spread out and look like scattered dots. */
  max-width: 1040px;
  margin: 0 auto;
  min-height: 560px;
  overflow: hidden;
}
.system-map__canvas {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.system-map__nodes {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: center;
  align-content: center;
  min-height: 560px;
  padding: 1.5rem;
}
/* Once the script takes over, the nodes are absolutely placed by transform. */
.system-map.is-live .system-map__nodes { display: block; padding: 0; }
.system-map.is-live .system-map__node {
  position: absolute;
  top: 0;
  left: 0;
  will-change: transform;
}

.system-map__node {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  border-radius: 999px;
  border: 1px solid rgba(138,154,138,0.35);
  background: rgba(29,43,30,0.82);
  backdrop-filter: blur(3px);
  color: #E6EBE1;
  text-decoration: none;
  width: 132px;
  height: 132px;
  padding: 0.5rem;
  transition: border-color 0.35s cubic-bezier(0.16,1,0.3,1),
              background-color 0.35s cubic-bezier(0.16,1,0.3,1),
              box-shadow 0.35s cubic-bezier(0.16,1,0.3,1);
}
.system-map__node .sm-label {
  font-family: "Space Grotesk", Inter, sans-serif;
  font-size: 0.95rem;
  line-height: 1.15;
  letter-spacing: -0.01em;
}
.system-map__node .sm-kicker {
  font-family: "JetBrains Mono", monospace;
  font-size: 8px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #8A9A8A;
  margin-top: 0.35rem;
}
.system-map__node:hover,
.system-map__node:focus-visible {
  border-color: rgba(140,217,140,0.85);
  background: rgba(44,66,46,0.92);
  box-shadow: 0 0 0 6px rgba(140,217,140,0.10);
  outline: none;
}
.system-map__node:hover .sm-kicker,
.system-map__node:focus-visible .sm-kicker { color: #8cd98c; }

.system-map__node--core {
  width: 168px;
  height: 168px;
  border-color: rgba(140,217,140,0.55);
  background: rgba(44,66,46,0.95);
}
.system-map__node--core .sm-label { font-size: 1.1rem; color: #fff; }
/* The hub sits on a lighter plate than the other nodes, where sage-400
   drops to 3.7:1. The accent green clears it at 6.3:1 and suits the hub. */
.system-map__node--core .sm-kicker { color: #8cd98c; }

@media (max-width: 759px) {
  .system-map, .system-map__nodes { min-height: 560px; }
  .system-map__node { width: 104px; height: 104px; }
  .system-map__node .sm-label { font-size: 0.72rem; }
  .system-map__node .sm-kicker { display: none; }
  .system-map__node--core { width: 124px; height: 124px; }
  .system-map__node--core .sm-label { font-size: 0.85rem; }
}

/* Day One capability cards: lift on hover instead of a flat colour swap. */
.day-card {
  transition: border-color 0.4s cubic-bezier(0.16,1,0.3,1),
              transform 0.4s cubic-bezier(0.16,1,0.3,1),
              box-shadow 0.4s cubic-bezier(0.16,1,0.3,1);
}
@media (hover: hover) {
  .day-card:hover {
    border-color: rgba(29,43,30,0.28);
    transform: translateY(-4px);
    box-shadow: 0 18px 40px -24px rgba(29,43,30,0.35);
  }
  /* On the dark chapter the cards float on a dark field, so they lift with a
     green edge and a glow rather than a drop shadow nobody can see. */
  .bg-sage-900 .day-card:hover {
    border-color: rgba(140,217,140,0.45);
    box-shadow: 0 18px 50px -22px rgba(0,0,0,0.75);
  }
}

/* ---- LIQUID DISTORTION CANVAS ---- */
.liquid-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 2;
  opacity: 0;
  transition: opacity 0.5s ease;
}
.img-break:hover .liquid-canvas,
div[class*="h-["]:hover .liquid-canvas {
  opacity: 1;
}
@media (pointer: coarse) {
  .liquid-canvas { display: none !important; }
  .hero-shader-canvas { display: none !important; }
}

/* ---- PINNED SECTION HELPERS ---- */
.pin-spacer {
  /* GSAP adds this automatically, but we need overflow visible */
  overflow: visible !important;
}

/* ---- VARIABLE FONT WEIGHT ANIMATION ---- */
.vf-weight {
  font-variation-settings: 'wght' 300;
  transition: font-variation-settings 0.1s ease-out;
}
.vf-weight.is-focused {
  font-variation-settings: 'wght' 500;
}

/* ---- MOBILE SCROLL FIX ---- */
/* Ensure native touch scrolling is never hijacked on mobile */
@media (pointer: coarse) {
  html, body {
    overflow-x: hidden;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-y: auto;
  }

  /* Kill GSAP pin spacers on mobile — they can trap scroll */
  .pin-spacer {
    padding: 0 !important;
    height: auto !important;
    overflow: visible !important;
  }

  /* Disable film grain on mobile (GPU overhead causes jank) */
  .grain-overlay {
    display: none !important;
  }

  /* Ensure sections are visible even if ScrollTrigger hasn't fired */
  section {
    opacity: 1 !important;
    transform: none !important;
    visibility: visible !important;
  }

  /* Prevent scroll-smooth from conflicting with touch */
  html.scroll-smooth {
    scroll-behavior: auto !important;
  }

  /* Simplify image break transitions on mobile */
  .img-break img {
    transform: none !important;
    will-change: auto;
  }
}

/* ---- MOBILE MENU (staggered entrance, pure CSS, touch-safe) ---- */
#mobile-menu .mm-item {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .5s cubic-bezier(0.16, 1, 0.3, 1), transform .5s cubic-bezier(0.16, 1, 0.3, 1);
}
#mobile-menu.opacity-100 .mm-item { opacity: 1; transform: none; }
#mobile-menu.opacity-100 nav .mm-item:nth-child(1) { transition-delay: .06s; }
#mobile-menu.opacity-100 nav .mm-item:nth-child(2) { transition-delay: .12s; }
#mobile-menu.opacity-100 nav .mm-item:nth-child(3) { transition-delay: .18s; }
#mobile-menu.opacity-100 nav .mm-item:nth-child(4) { transition-delay: .24s; }
#mobile-menu.opacity-100 nav .mm-item:nth-child(5) { transition-delay: .30s; }
#mobile-menu.opacity-100 .grid.mm-item { transition-delay: .38s; }
#mobile-menu.opacity-100 div > .mm-item:last-child { transition-delay: .44s; }

/* ================================================
   ADAPTIVE NAV (2026-07-23)
   Driven entirely by #nav data-attributes and custom properties so the
   existing Tailwind classes across 44 pages did not need rewriting.
   #nav is an ID selector, so it outranks the utility classes it overrides.
   ================================================ */
#nav.nav-adaptive {
  --nav-bg: rgba(248, 249, 245, 0.86);
  --nav-fg: #1D2B1E;
  --nav-fg-dim: rgba(29, 43, 30, 0.62);
  --nav-line: rgba(29, 43, 30, 0.18);
  --nav-cta-bg: #2C422E;
  --nav-cta-fg: #F8F9F5;
  --nav-ind: rgba(29, 43, 30, 0.07);

  background-color: var(--nav-bg);
  -webkit-backdrop-filter: saturate(1.4) blur(14px);
  backdrop-filter: saturate(1.4) blur(14px);
  border-bottom: 1px solid var(--nav-line);
  translate: 0 0;
  transition:
    background-color 0.5s cubic-bezier(0.16, 1, 0.3, 1),
    border-color 0.5s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.45s cubic-bezier(0.16, 1, 0.3, 1),
    width 0.5s cubic-bezier(0.16, 1, 0.3, 1),
    top 0.5s cubic-bezier(0.16, 1, 0.3, 1),
    border-radius 0.5s cubic-bezier(0.16, 1, 0.3, 1),
    box-shadow 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}

#nav.nav-adaptive[data-theme="dark"] {
  --nav-bg: rgba(20, 31, 21, 0.72);
  --nav-fg: #E6EBE1;
  --nav-fg-dim: rgba(230, 235, 225, 0.7);
  --nav-line: rgba(230, 235, 225, 0.16);
  --nav-cta-bg: #F8F9F5;
  --nav-cta-fg: #1D2B1E;
  --nav-ind: rgba(230, 235, 225, 0.12);
}

/* text + logo follow the theme */
#nav.nav-adaptive a { color: var(--nav-fg); }
#nav.nav-adaptive .logo-sage {
  filter: none;
  transition: filter 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
#nav.nav-adaptive[data-theme="light"] .logo-sage {
  filter: brightness(0) saturate(100%) invert(13%) sepia(13%) saturate(1476%)
          hue-rotate(76deg) brightness(94%) contrast(88%);
}
#nav.nav-adaptive[data-theme="dark"] .logo-sage {
  filter: brightness(0) invert(1);
}
#nav.nav-adaptive #mobile-menu-btn svg { color: var(--nav-fg); }

/* The Book a Call pill is CONSTANT and matches the site's primary buttons
   exactly: dark-green background, cream text (~9:1). Two earlier versions each
   had a readability problem: the theme-inverting one washed out through a muddy
   olive midpoint mid-scroll, and the bright-green-with-dark-text one read as
   ambiguous "blue-ish, hard to see" text (Greg, three times). Cream on dark
   green is unmistakable, never transitions through a low-contrast state, and is
   the same treatment used on every other CTA on the site. `!important` guards
   the colour against the generic `#nav a { color: var(--nav-fg) }` rule and
   any Tailwind utility on the element, so it can never fall back to a link
   default. A hairline light ring separates it from the plate on dark navs. */
#nav.nav-adaptive a[href="book.html"] {
  background-color: #2C422E !important;
  color: #F8F9F5 !important;
  box-shadow: inset 0 0 0 1px rgba(248, 249, 245, 0.22);
  transition: background-color 0.3s ease, box-shadow 0.3s ease;
}
#nav.nav-adaptive a[href="book.html"]:hover {
  background-color: #1D2B1E !important;
  box-shadow: inset 0 0 0 1px rgba(248, 249, 245, 0.35);
}

/* condensed: leaves the top edge and becomes a floating bar */
#nav.nav-adaptive.is-condensed {
  top: 10px;
  left: 50%;
  translate: -50% 0;
  width: min(94%, 1380px);
  border-radius: 999px;
  border: 1px solid var(--nav-line);
  box-shadow: 0 18px 40px -30px rgba(0, 0, 0, 0.55);
}
#nav.nav-adaptive.is-condensed > div { padding-left: 1.5rem; padding-right: 1rem; }

/* hide on scroll down, return on scroll up */
#nav.nav-adaptive.is-hidden { transform: translateY(-140%); }

/* morphing hover/active indicator */
#nav.nav-adaptive .nav-links { position: relative; }
#nav.nav-adaptive .nav-ind {
  position: absolute;
  left: 0;
  top: 50%;
  height: 30px;
  margin-top: -15px;
  border-radius: 999px;
  background: var(--nav-ind);
  opacity: 0;
  pointer-events: none;
  z-index: 0;
  transition: transform 0.45s cubic-bezier(0.16, 1, 0.3, 1),
              width 0.45s cubic-bezier(0.16, 1, 0.3, 1),
              opacity 0.3s ease,
              background-color 0.5s ease;
}
#nav.nav-adaptive .nav-links > a {
  position: relative;
  z-index: 1;
  padding: 0.4rem 0.7rem;
  margin: 0 -0.2rem;
  border-radius: 999px;
}
#nav.nav-adaptive .nav-links > a.is-active { color: var(--nav-fg); }
#nav.nav-adaptive .nav-links > a:hover { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  #nav.nav-adaptive,
  #nav.nav-adaptive .nav-ind,
  #nav.nav-adaptive .logo-sage { transition: none; }
  #nav.nav-adaptive.is-hidden { transform: none; }
}

/* ================================================
   CROSS-DOCUMENT VIEW TRANSITIONS (2026-07-23)
   Real page-to-page morphing, done by the browser rather than by a scripted
   overlay. The nav and footer are named, so they stay PUT across navigation
   while the content between them cross-fades and lifts. motion.js stands down
   from intercepting clicks wherever this is supported.
   ================================================ */
@view-transition { navigation: auto; }

#nav { view-transition-name: site-nav; }
footer { view-transition-name: site-footer; }

::view-transition-old(root) {
  animation: vt-leave 240ms cubic-bezier(0.4, 0, 1, 1) both;
}
::view-transition-new(root) {
  animation: vt-enter 420ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes vt-leave {
  to { opacity: 0; transform: translateY(-10px) scale(0.994); }
}
@keyframes vt-enter {
  from { opacity: 0; transform: translateY(16px); }
}

/* The persistent chrome should not be animated by the group at all. */
::view-transition-group(site-nav),
::view-transition-group(site-footer) { animation-duration: 320ms; }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

/* ---- SYSTEM MAP: lead trace ---- */
.map-trace-dot {
  width: 6px; height: 6px; border-radius: 50%; background: #8cd98c;
  animation: console-dot-pulse 2.4s cubic-bezier(0.16,1,0.3,1) infinite;
}
/* A node the traced lead has reached. */
.system-map__node.is-hot {
  border-color: rgba(140,217,140,0.95);
  background: rgba(44,66,46,0.98);
  box-shadow: 0 0 0 8px rgba(140,217,140,0.12), 0 0 34px -6px rgba(140,217,140,0.5);
}
.system-map__node.is-hot .sm-kicker { color: #8cd98c; }
@media (prefers-reduced-motion: reduce) {
  .map-trace-dot { animation: none; }
}
/* Defined here as well as inline on index.html so the trace button works on
   any page the system map is later added to. */
@keyframes console-dot-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(140,217,140,0.6); }
  70%  { box-shadow: 0 0 0 7px rgba(140,217,140,0); }
  100% { box-shadow: 0 0 0 0 rgba(140,217,140,0); }
}

/* ================================================
   HERO PARTICLE DISSOLVE (2026-07-23)
   The canvas is layered over the still photo. Progressive enhancement: it is
   only revealed once the sim confirms it is running, and the photo underneath
   is dimmed (never hidden), so a WebGL failure just shows the painting.
   ================================================ */
.hero-dissolve__canvas {
  position: absolute;
  inset: 0;
  z-index: 3;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}
.hero-media.dissolve-live .hero-dissolve__canvas { opacity: 1; }
.hero-media.dissolve-live .hero-media__img {
  /* substrate the particles sit on, dimmed as the scroll morph completes */
  filter: saturate(0.92) brightness(0.96);
  opacity: var(--photo-fade, 1);
}
/* a dark backing so the sage lattice reads once the photo fades out */
.hero-media.dissolve-live::before {
  content: "";
  position: absolute; inset: 0; z-index: 2;
  background: radial-gradient(120% 100% at 60% 40%, #22331f 0%, #131f12 100%);
  opacity: calc(1 - var(--photo-fade, 1));
  pointer-events: none;
}
@media (pointer: coarse) {
  .hero-dissolve__canvas { display: none !important; }
}

/* ================================================
   HERO FIELD (2026-07-23) — reusable ambient node-field for dark heroes
   ================================================ */
.hero-field__canvas {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.1s cubic-bezier(0.16, 1, 0.3, 1);
}
.hero-field-live .hero-field__canvas { opacity: 1; }
/* the field sits above the flat plate but below the dot-grid texture + copy */
[data-hero-field] > *:not(.hero-field__canvas):not(.hero-atmos) { position: relative; z-index: 1; }
@media (pointer: coarse) {
  /* keep it, but it renders a calmer still-ish field via reduced node motion */
}

/* ================================================
   MOBILE MENU: fit one screen, no scroll (2026-07-24)
   The overlay markup is identical on all 44 pages, so this is styled by ID
   (beats the inline Tailwind utilities) rather than editing every file.
   Everything sizes off viewport height (svh/vh clamps) so the whole menu,
   nav + secondary links + CTA, fits a single screen on typical phones and
   scales down gracefully on short ones. Falls back to scroll only on very
   short viewports so content is never clipped or trapped (global rule 20).
   ================================================ */
#mobile-menu {
  height: 100svh;
  overflow: hidden;
}
/* middle block distributes the space between the main nav and the sub-links */
#mobile-menu > .flex-1 {
  justify-content: space-between;
  padding-top: clamp(0.75rem, 2.4vh, 2rem);
  padding-bottom: clamp(0.75rem, 2.4vh, 2rem);
  gap: clamp(0.5rem, 1.8vh, 1.5rem);
  min-height: 0;
}
/* primary nav links scale with the viewport */
#mobile-menu nav a {
  padding-top: clamp(0.3rem, 1.35vh, 0.9rem);
  padding-bottom: clamp(0.3rem, 1.35vh, 0.9rem);
}
#mobile-menu nav a > span:last-child {
  font-size: clamp(1.35rem, 4.4vh, 1.9rem);
  line-height: 1.04;
}
/* secondary link grid tightens up */
#mobile-menu .grid { margin-top: clamp(0.5rem, 1.6vh, 1.5rem); padding-top: clamp(0.5rem, 1.6vh, 1.5rem); }
#mobile-menu .grid a {
  padding-top: clamp(0.2rem, 0.85vh, 0.625rem);
  padding-bottom: clamp(0.2rem, 0.85vh, 0.625rem);
}
/* CTA footer */
#mobile-menu > [class*="pb-8"] { padding-bottom: clamp(0.9rem, 2.6vh, 2rem); }
#mobile-menu > [class*="pb-8"] .mm-item { padding-top: clamp(0.75rem, 2vh, 1.5rem); }
#mobile-menu > [class*="pb-8"] p {
  font-size: clamp(1.05rem, 2.9vh, 1.5rem);
  margin-bottom: clamp(0.6rem, 1.5vh, 1.25rem);
}
#mobile-menu > [class*="pb-8"] a[href="book.html"] {
  height: clamp(3rem, 6.4vh, 3.5rem);
}
/* only the tightest viewports (small landscape) may scroll, never trapped */
@media (max-height: 558px) { #mobile-menu { overflow-y: auto; } }
