/* Site-specific styles layered on top of ui.css (the UI-kit defaults) */

/* Tweaks panel */
.tweaks {
  position: fixed;
  right: 20px;
  bottom: 20px;
  width: 260px;
  background: var(--bg);
  border: 1px solid var(--hairline-strong);
  box-shadow: 0 8px 24px rgba(0,0,0,0.08);
  padding: 16px 18px 18px;
  z-index: 50;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--fg);
}
[data-theme="night"] .tweaks { box-shadow: 0 8px 24px rgba(0,0,0,0.5); background: var(--bg-panel); }
.tweaks__title {
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--fg-subtle);
  padding-bottom: 10px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--hairline);
  display: flex; justify-content: space-between; align-items: baseline;
}
.tweaks__row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 0;
  gap: 12px;
  border-bottom: 1px dotted var(--hairline);
}
.tweaks__row:last-child { border-bottom: 0; }
.tweaks__label {
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.tweaks__seg {
  display: inline-flex;
  border: 1px solid var(--hairline-strong);
}
.tweaks__seg button {
  background: transparent;
  border: 0;
  padding: 4px 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-subtle);
  cursor: pointer;
  border-right: 1px solid var(--hairline-strong);
}
.tweaks__seg button:last-child { border-right: 0; }
.tweaks__seg button.on { background: var(--fg); color: var(--bg); }

/* Site foot center slot */
.site-foot span + span { margin-left: auto; }
.site-foot .ctr {
  margin: 0 auto;
  color: var(--fg-faint);
}

/* ---------- Sit Detail Page (/sits/[slug]) ---------- */

/* Detail section (metadata + blurb) — sits BELOW the 70vh hero,
   introduced with the same quiet fade-up used for sit entry. */
/* DEAD as of 2026-04-18: .sit-page__* and .sit-media* rules below are
   from the original SitPage detail/gallery/nav design. The slide-up
   overlay redesign (see "SIT OVERLAY" section near end of file) renders
   .sit-overlay / .sit-grid / .sit-grid__tile instead, so these selectors
   match nothing. Left in place to make revert easier; clean up later. */
.sit-page__detail {
  max-width: 1200px;
  margin: 0 auto;
  padding: 96px 48px 64px;
  border-bottom: 1px solid var(--hairline);
  animation: sitIn 560ms var(--ease-out);
}
.sit-page__back {
  background: transparent; border: 0; padding: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-muted);
  cursor: pointer;
  margin-bottom: 48px;
}
.sit-page__back:hover { color: var(--fg); }
.sit-page__location {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 72px;
  line-height: 1.02;
  letter-spacing: -0.02em;
  margin: 0 0 20px;
  text-wrap: balance;
}
.sit-page__meta {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin-bottom: 32px;
}
.sit-page__meta .sep { margin: 0 10px; color: var(--fg-faint); }
.sit-page__blurb {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 24px;
  line-height: 1.5;
  color: var(--fg);
  max-width: 62ch;
  margin: 0;
  text-wrap: pretty;
}

.sit-page__gallery {
  max-width: 1200px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 96px 32px;
  padding: 80px 48px 96px;
}
.sit-media { margin: 0; --ar: 3/2; }
.sit-media--full { grid-column: 1 / -1; }
.sit-media--half { grid-column: span 6; }
.sit-media > video,
.sit-media__img {
  display: block;
  width: 100%;
  aspect-ratio: var(--ar);
  object-fit: cover;
  background-size: cover;
  background-position: center;
  background-color: #111;
}
.sit-media figcaption {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin-top: 14px;
  max-width: 64ch;
}

.sit-page__nav {
  max-width: 1200px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 24px;
  align-items: center;
  padding: 48px 48px 96px;
  border-top: 1px solid var(--hairline);
}
.sit-page__nav button {
  background: transparent; border: 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg);
  text-align: left;
}
.sit-page__nav button:last-child { text-align: right; align-items: flex-end; }
.sit-page__nav-center {
  justify-self: center;
  color: var(--fg-muted) !important;
  font-size: 10px !important;
  letter-spacing: 0.2em !important;
}
.sit-page__nav-label { color: var(--fg-muted); font-size: 10px; }
.sit-page__nav-loc { font-family: var(--font-display); text-transform: none; letter-spacing: 0; font-size: 24px; font-style: italic; color: var(--fg); }

@keyframes sitIn {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---------- Info Page (/info) — full viewport width per design refinement
   2026-05-01. The 920px container cap was clipping the hero name and review
   masonry on wide displays; removed in favor of section-level horizontal
   padding so hero / biography / contact / reviews each control their own
   inset against the viewport edge. ---------- */
.info-page {
  margin: 0;
  padding: 120px 0 128px;
}
.info-page__head {
  display: flex; justify-content: space-between;
  padding-bottom: 48px;
  margin-bottom: 64px;
  border-bottom: 1px solid var(--hairline);
}
.info-page__head .mono-label {
  /* Inherit canonical label spec from .mono-caps — this rule exists
     only to tint the color for on-paper context. */
  color: var(--fg-muted);
}
.info-page__section { margin-bottom: 72px; }
.info-page__lead {
  font-family: var(--font-display);
  font-size: 32px;
  line-height: 1.35;
  letter-spacing: -0.005em;
  color: var(--fg);
  margin: 0 0 24px;
  max-width: 32ch;
  text-wrap: pretty;
}
.info-page__lead--muted {
  color: var(--fg-muted);
  font-style: italic;
  font-size: 22px;
  margin-bottom: 0;
}
.info-page__dl {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 20px 32px;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
}
.info-page__dl dt {
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.info-page__dl dd { margin: 0; color: var(--fg); }
.info-page__colophon {
  border-top: 1px solid var(--hairline);
  padding-top: 40px;
}
.info-page__colophon-body {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 16px;
  line-height: 1.6;
  color: var(--fg-muted);
  max-width: 56ch;
  margin: 16px 0 0;
}

/* Mobile */
@media (max-width: 900px) {
  .tweaks { right: 10px; bottom: 10px; width: auto; left: 10px; }
  .sit-page, .info-page { padding: 80px 20px 64px; }
  .sit-page__location { font-size: 48px; }
  .sit-page__gallery { gap: 48px 16px; }
  .sit-media--half { grid-column: 1 / -1; }
  .info-page__lead { font-size: 22px; }
  .info-page__dl { grid-template-columns: 1fr; gap: 4px 0; }
  .info-page__dl dt { margin-top: 16px; }
}


/* ============================================================
   ONE-SIT FEED — full-viewport vertical scroll.
   Each sit frame is 100vh and scroll-snaps into place.
   Text is corner marks only; the image does the talking.
   ============================================================ */

.onesit {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  /* Scroll-snap so every sit locks to the viewport. Proximity (not
     mandatory) so mid-sit scroll doesn't feel jerky on trackpads. */
  scroll-snap-type: y proximity;
  background: #000;
  color: #fafaf7;
}

.onesit-frame {
  position: relative;
  width: 100vw;
  height: 100vh;
  scroll-snap-align: start;
  overflow: hidden;
  cursor: pointer;
  isolation: isolate;
  background: #000;
  /* Defaults for cursor parallax — overridden by onmousemove. */
  --mx: 0;
  --my: 0;
  --sweep: 0;
  /* 23 full-viewport frames × heavy media = lots of offscreen paint
     and layout work. content-visibility: auto tells the browser to
     skip rendering any frame outside the viewport; the intrinsic-size
     hint keeps scroll math stable so scrollbars don't jump as frames
     unlock. Supported in all current evergreen browsers. */
  content-visibility: auto;
  contain-intrinsic-size: 100vw 100vh;
}

/* --- Media layer ---------------------------------------------
   Owns the full frame. Variants read --mx/--my to translate/
   scale. --sweep (drag) is additive on top — only sit.sweep frames
   actually get it moved. */
.onesit-frame__media {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  transition: transform 540ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.onesit-frame__media > video,
.onesit-frame__img {
  /* Both layers must be absolutely positioned so the video overlays the
     plate instead of stacking below it in normal flow. Without this, at
     ultrawide viewports the container's intrinsic height grows large
     enough that a static <video> is pushed below the absolutely-positioned
     plate and falls off-screen. */
  position: absolute; inset: 0;
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  background-size: cover;
  background-position: center;
  background-color: #141414;
}

/* Vignette — pulls the corners into shadow, keeps the marks readable. */
.onesit-frame__vignette {
  position: absolute; inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(0,0,0,0.32) 0%, rgba(0,0,0,0) 22%, rgba(0,0,0,0) 62%, rgba(0,0,0,0.55) 100%),
    radial-gradient(ellipse at center, rgba(0,0,0,0) 50%, rgba(0,0,0,0.32) 100%);
  z-index: 2;
}

/* --- Parallax variants ---------------------------------------- */

/* Orientation biases how far X travels. Landscape/wide media has more
   image to the left and right of the crop, so we push X harder; portrait
   covers are tighter on the sides, so ease off. --pan-x / --pan-y are
   multipliers (base = 1.0) that each variant pulls into its transform. */
.onesit-frame                       { --pan-x: 1;   --pan-y: 1; }
.onesit-frame[data-orient="wide"]      { --pan-x: 1.8; --pan-y: 0.7;  --pan-scale: 1.06; }
.onesit-frame[data-orient="landscape"] { --pan-x: 1.4; --pan-y: 0.85; --pan-scale: 1.03; }
.onesit-frame[data-orient="portrait"]  { --pan-x: 0.6; --pan-y: 1.1;  --pan-scale: 1.0; }
.onesit-frame                          { --pan-scale: 1.0; }

/* Subtle — no scale, tiny translate. For users who hate motion.
   Biased: more X travel than Y, because most sit media is wider than tall. */
.onesit[data-parallax="subtle"] .onesit-frame[data-active="true"] .onesit-frame__media {
  transform:
    translate3d(calc(var(--mx) * var(--pan-x) * -22px), calc(var(--my) * var(--pan-y) * -6px), 0);
  transition: transform 720ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* Cinematic — default. Wider X travel, light Y, gentle zoom.
   Zoom bumped to 1.10 so there's more room for X to travel without
   showing edges on 16:9+ media. */
.onesit[data-parallax="cinematic"] .onesit-frame[data-active="true"] .onesit-frame__media {
  transform:
    scale(calc(1.10 * var(--pan-scale)))
    translate3d(calc(var(--mx) * var(--pan-x) * -70px), calc(var(--my) * var(--pan-y) * -16px), 0)
    rotateY(calc(var(--mx) * var(--pan-x) * 1.4deg))
    rotateX(calc(var(--my) * var(--pan-y) * -0.4deg));
  transform-origin: center;
  transition: transform 560ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* Aggressive — near horizon sweep. Heavy X, modest Y, large zoom
   so the photo can travel farther laterally without showing seams. */
.onesit[data-parallax="aggressive"] .onesit-frame[data-active="true"] .onesit-frame__media {
  transform:
    scale(calc(1.20 * var(--pan-scale)))
    translate3d(calc(var(--mx) * var(--pan-x) * -160px), calc(var(--my) * var(--pan-y) * -32px), 0)
    rotateY(calc(var(--mx) * var(--pan-x) * 3.2deg))
    rotateX(calc(var(--my) * var(--pan-y) * -1.2deg));
  transform-origin: center;
  transition: transform 420ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* Vignette counter-moves so corners stay anchored. */
.onesit[data-parallax="aggressive"] .onesit-frame[data-active="true"] .onesit-frame__vignette {
  transform: translate3d(calc(var(--mx) * 14px), calc(var(--my) * 4px), 0);
  transition: transform 420ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* --- Pseudo-360 sweep ----------------------------------------
   On sit.sweep frames, --sweep (-1..1) translates the media
   horizontally and shifts its background position so it reads as
   "looking around" a wide scene. Combined with parallax above. */
.onesit-frame--sweep .onesit-frame__media {
  /* Start pre-scaled so there's photo to the left AND right. */
  transform: scale(1.32) translate3d(calc(var(--sweep) * 18%), 0, 0);
  transition: transform 180ms linear;
}
.onesit-frame--sweep .onesit-frame__img {
  /* Also pan background-position so edges reveal more scene. */
  background-position: calc(50% + var(--sweep) * -22%) center;
}
.onesit-frame--sweep.is-sweeping { cursor: grabbing; }
.onesit-frame--sweep:not(.is-sweeping) { cursor: grab; }

/* Override the parallax active-state transform for sweep frames —
   they have their own motion vocabulary (drag). */
.onesit[data-parallax] .onesit-frame--sweep[data-active="true"] .onesit-frame__media {
  transform: scale(1.32) translate3d(
    calc(var(--sweep) * 18% + var(--mx) * -14px),
    calc(var(--my) * -8px),
    0
  );
  transition: transform 180ms linear;
}

/* --- Corner marks --------------------------------------------
   Fixed-position-ish text on each frame. Fades on inactive frames
   so the eye knows which one is "live". */
.onesit-frame__mark {
  position: absolute;
  z-index: 3;
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(250,250,247,0.9);
  text-shadow: 0 1px 12px rgba(0,0,0,0.45);
  transition: opacity 420ms var(--ease-out);
  opacity: 0.4;
}
.onesit-frame[data-active="true"] .onesit-frame__mark { opacity: 1; }
.onesit-frame__mark--tl { top: 80px; left: 32px; }
.onesit-frame__mark--bl { bottom: 40px; left: 32px; }
.onesit-frame__mark--br { bottom: 40px; right: 32px; }
.onesit-frame__sweep-hint {
  padding: 6px 10px;
  background: rgba(0,0,0,0.35);
  border: 1px solid rgba(250,250,247,0.2);
  backdrop-filter: blur(6px);
  border-radius: 2px;
  animation: sweepHintPulse 2600ms ease-in-out infinite;
}
@keyframes sweepHintPulse {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 1; }
}



/* --- HUD overlay (progress, count) ---------------------------- */
.onesit__hud {
  position: fixed;
  z-index: 45;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(250,250,247,0.85);
  text-shadow: 0 1px 10px rgba(0,0,0,0.45);
  pointer-events: none;
}
/* Cleared of the nav's Book-a-sit + Bark cluster. The right-hand nav group
   runs ~200–230px in from the viewport edge at desktop widths; positioning
   the counter below the nav row keeps it readable regardless of width. */
.onesit__hud--tr { top: 72px; right: 32px; }
.onesit__hud--br { bottom: 40px; right: 50%; transform: translateX(50%); display: flex; align-items: center; gap: 12px; }
.onesit__hud--bl { bottom: 40px; left: 32px; }
.onesit__hud-hint {
  opacity: 0.7;
  /* Gently breathe before the first scroll — a quiet "this surface
     scrolls" cue that rewards attention without demanding it. The
     viewer stops noticing it once they engage. */
  animation: scroll-hint-breathe 3200ms ease-in-out infinite;
}
@keyframes scroll-hint-breathe {
  0%, 100% { opacity: 0.45; }
  50%      { opacity: 0.85; }
}
@media (prefers-reduced-motion: reduce) {
  .onesit__hud-hint { animation: none; opacity: 0.7; }
}

/* --- Trust chip — pinned proof that survives the summary fade ---- */
.onesit__trust-chip {
  /* Reset button chrome so it reads as a HUD element, not a UI control. */
  background: none;
  border: 0;
  padding: 6px 10px 6px 12px;
  margin: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  pointer-events: auto;              /* overrides .onesit__hud's disabled pointer-events */
  color: inherit;
  font: inherit;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  border-radius: 999px;
  /* Subtle dark plate so the chip stays legible on bright hero frames
     without breaking the monochrome discipline. */
  background: rgba(10, 10, 9, 0.22);
  backdrop-filter: blur(6px) saturate(115%);
  -webkit-backdrop-filter: blur(6px) saturate(115%);
  box-shadow: inset 0 0 0 1px rgba(250, 250, 247, 0.16);
  transition: background 220ms ease, box-shadow 220ms ease, transform 220ms cubic-bezier(.2,.7,.2,1);
}
.onesit__trust-chip:hover,
.onesit__trust-chip:focus-visible {
  background: rgba(10, 10, 9, 0.42);
  box-shadow: inset 0 0 0 1px rgba(250, 250, 247, 0.32);
  transform: translateY(-1px);
  outline: none;
}
.onesit__trust-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.95;
  /* Soft pulse — signals "alive / verified" without looking like a notification. */
  animation: trust-pulse 2.4s ease-in-out infinite;
}
.onesit__trust-arrow {
  font-size: 10px;
  opacity: 0.7;
  transition: transform 220ms cubic-bezier(.2,.7,.2,1), opacity 220ms ease;
}
.onesit__trust-chip:hover .onesit__trust-arrow,
.onesit__trust-chip:focus-visible .onesit__trust-arrow {
  transform: translate(2px, -2px);
  opacity: 1;
}
@keyframes trust-pulse {
  0%, 100% { opacity: 0.45; transform: scale(0.9); }
  50%      { opacity: 1;    transform: scale(1.05); }
}
@media (prefers-reduced-motion: reduce) {
  .onesit__trust-chip,
  .onesit__trust-chip:hover,
  .onesit__trust-arrow { transition: none; transform: none; }
  .onesit__trust-dot { animation: none; }
}
.onesit__hud-bar {
  display: inline-block;
  width: 180px; height: 1px;
  background: rgba(250,250,247,0.2);
  position: relative;
  overflow: hidden;
}
.onesit__hud-bar::after {
  content: '';
  position: absolute; top: 0; left: 0; bottom: 0;
  /* --scroll-p is set by OneSitFeed's scroll handler directly on the
     container ref — no React rerender per tick. */
  width: calc(var(--scroll-p, 0) * 100%);
  background: rgba(250,250,247,0.9);
  transition: width 60ms linear;
}

/* --- Nav + footer adjustments in feed mode -------------------
   The feed is its own world. The nav floats with no plate and the
   wordmark + link text use mix-blend-mode: difference so they invert
   automatically over bright vs dark photos — a single CSS rule that
   replaces the old gradient-plate + text-shadow approach. CTAs and
   the BARK button keep their own treatments (blend would mangle
   the pill). */
body:has(.onesit) .site-nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 40;
  background: transparent;
  border-bottom-color: transparent;
  color: #ffffff;
  padding-top: 18px; padding-bottom: 18px;
}
body:has(.onesit) .site-nav .wm,
body:has(.onesit) .site-nav__links a {
  color: #ffffff;
  mix-blend-mode: difference;
}
/* Book-a-sit + BARK stay on their own layer — the pill needs a solid
   plate, the bark button has its own inherited color. Explicit reset
   in case any descendant selector tries to inherit the blend mode. */
body:has(.onesit) .site-nav__cta,
body:has(.onesit) .bark-btn {
  mix-blend-mode: normal;
  color: #fafaf7;
}
body:has(.onesit) .site-foot { display: none; }

/* ============================================================
   BARK BUTTON — spammable. Clicking stacks 'WOOF' words
   that drift up and fade. Visual feedback for the chaos.
   ============================================================ */
/* Bark — tertiary charm. Demoted from outline button to plain text so
   it doesn't compete with the commercial "Book a sit" CTA next to it. */
.bark-btn {
  appearance: none;
  background: transparent;
  border: 0;
  color: inherit;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  text-transform: uppercase;
  padding: 7px 10px;
  cursor: pointer;
  user-select: none;
  position: relative;
  opacity: 0.55;
  transition: opacity 180ms var(--ease-out), transform 120ms var(--ease-out);
}
.bark-btn:hover { opacity: 1; }
.bark-btn:active { transform: scale(0.94); }
.bark-btn.is-barking { animation: barkShake 140ms linear; }
@keyframes barkShake {
  0%   { transform: translate(0,0); }
  25%  { transform: translate(-1.5px, 1px) rotate(-0.6deg); }
  50%  { transform: translate(1.5px, -1px) rotate(0.6deg); }
  75%  { transform: translate(-1px, 0) rotate(-0.3deg); }
  100% { transform: translate(0,0); }
}

/* The drifting WOOFs live in a fixed overlay so they can stack
   without constraining layout. */
.bark-stage {
  position: fixed;
  top: 60px; left: 0; right: 0; bottom: 0;
  pointer-events: none;
  z-index: 50;
  overflow: hidden;
}
.bark-pop {
  position: absolute;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  color: #fafaf7;
  text-shadow: 0 2px 18px rgba(0,0,0,0.45);
  white-space: nowrap;
  animation: barkDrift 1800ms cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
  will-change: transform, opacity;
}
@keyframes barkDrift {
  0%   { opacity: 0;   transform: translate(var(--dx-start, 0), 0)     scale(0.6) rotate(var(--rot, 0deg)); }
  18%  { opacity: 1;   transform: translate(var(--dx-mid,   0), -24px) scale(1.05) rotate(var(--rot, 0deg)); }
  100% { opacity: 0;   transform: translate(var(--dx-end,   0), -220px) scale(1.15) rotate(var(--rot, 0deg)); }
}


/* --- Hover variants (no affordance, just subtle feedback) ----
   Selected via .onesit[data-hover="..."]. Applied only to the
   active frame on hover, so inactive frames never react. */

/* darken — three intensities */
.onesit[data-hover="darken-sm"]   .onesit-frame[data-active="true"]:hover .onesit-frame__vignette { background: rgba(0,0,0,0.06); transition: background 300ms var(--ease-out); }
.onesit[data-hover="darken-md"]   .onesit-frame[data-active="true"]:hover .onesit-frame__vignette { background: rgba(0,0,0,0.14); transition: background 300ms var(--ease-out); }
.onesit[data-hover="darken-lg"]   .onesit-frame[data-active="true"]:hover .onesit-frame__vignette { background: rgba(0,0,0,0.26); transition: background 300ms var(--ease-out); }

/* lighten — raise exposure slightly */
.onesit[data-hover="lighten"]     .onesit-frame[data-active="true"]:hover .onesit-frame__media { filter: brightness(1.08) contrast(1.04); transition: filter 300ms var(--ease-out); }

/* desat — subtle drain of color */
.onesit[data-hover="desat"]       .onesit-frame[data-active="true"]:hover .onesit-frame__media { filter: saturate(0.55); transition: filter 400ms var(--ease-out); }

/* warmth — shift color temperature warmer */
.onesit[data-hover="warmth"]      .onesit-frame[data-active="true"]:hover .onesit-frame__media { filter: saturate(1.15) hue-rotate(-8deg) brightness(1.04); transition: filter 400ms var(--ease-out); }

/* soft-zoom — tiny additional zoom layered on top of parallax */
.onesit[data-hover="zoom"]        .onesit-frame[data-active="true"]:hover .onesit-frame__media { transform: scale(1.03); transition: transform 600ms var(--ease-out); }
/* note: overrides parallax transform; acceptable because the user explicitly picks one mode. */

/* edge-hairlines — two faint vertical lines descend down L/R edges */
.onesit-frame__edges {
  position: absolute; inset: 0; pointer-events: none; z-index: 3;
  opacity: 0; transition: opacity 400ms var(--ease-out);
}
.onesit-frame__edges::before,
.onesit-frame__edges::after {
  content: '';
  position: absolute; top: 60px; bottom: 60px;
  width: 1px;
  background: linear-gradient(180deg, rgba(250,250,247,0) 0%, rgba(250,250,247,0.6) 40%, rgba(250,250,247,0.6) 60%, rgba(250,250,247,0) 100%);
}
.onesit-frame__edges::before { left: 24px; }
.onesit-frame__edges::after  { right: 24px; }
.onesit[data-hover="edges"] .onesit-frame[data-active="true"]:hover .onesit-frame__edges { opacity: 1; }

/* none — literally no hover feedback */
.onesit[data-hover="none"] .onesit-frame__media { /* nothing */ }


/* ============================================================
   Sit page color-wash backdrop — fixed behind everything.
   ============================================================ */
.sit-backdrop {
  position: fixed; inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
  background: #141414;
}
.sit-backdrop__layer {
  position: absolute; inset: 0;
  transition: opacity 900ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.sit-backdrop__img,
.sit-backdrop__video {
  position: absolute;
  inset: -8%;  /* over-expand so the blur doesn't show seams */
  width: 116%; height: 116%;
  object-fit: cover;
  background-size: cover;
  background-position: center;
  /* Blur responds to reel scroll position — sharper when a slide is
     centered, softer in transit. Brightness barely drops so the
     natural palette carries the page instead of heavy dimming. */
  filter: blur(var(--bg-blur, 40px)) saturate(0.85) brightness(0.6);
  transform: scale(1.08);
  transition: filter 420ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.sit-backdrop__veil {
  position: absolute; inset: 0;
  /* Softer veil — lets color come through, still keeps text legible. */
  background:
    radial-gradient(ellipse at 50% 30%, rgba(0,0,0,0.15) 0%, rgba(0,0,0,0.32) 60%, rgba(0,0,0,0.52) 100%);
}

/* DEAD as of 2026-04-18: same as the earlier marker — these inverted-
   color sit-page rules (lines below until the next "Reviews" section)
   are unused by the slide-up overlay. The .sit-backdrop rules ABOVE
   are still used (SitPage's SitBackdrop component renders them). */
/* Sit page content now sits on a dark wash — invert colors for
   readability. The hero keeps its own white text; we only need
   to invert the detail, gallery, and nav sections. */
.sit-page { position: relative; }
.sit-page__detail {
  background: transparent;
  border-bottom-color: rgba(250,250,247,0.12);
}
.sit-page__back,
.sit-page__meta,
.sit-page__meta .sep {
  color: rgba(250,250,247,0.55);
}
.sit-page__back:hover { color: #fafaf7; }
.sit-page__location { color: #fafaf7; }
.sit-page__blurb { color: rgba(250,250,247,0.9); }

.sit-media figcaption { color: rgba(250,250,247,0.55); }

.sit-page__nav { border-top-color: rgba(250,250,247,0.12); }
.sit-page__nav button { color: rgba(250,250,247,0.9); }
.sit-page__nav-label { color: rgba(250,250,247,0.5); }
.sit-page__nav-center { color: rgba(250,250,247,0.5) !important; }
.sit-page__nav-loc { color: #fafaf7; }

/* Hide the white footer on sit pages — doesn't fit the wash. */
body:has(.sit-page) .site-foot { display: none; }

/* Nav styling for sit-page lives in the consolidated dark-glass
   ruleset further down (search: "Dark-glass floating nav"). */


/* Fix: body paints bg white by default; on sit pages we want the
   fixed dark backdrop to show, so make the body transparent there. */
body:has(.sit-page) { background: transparent; }
html:has(.sit-page) { background: #141414; }

/* Raise backdrop from -1 (hidden behind body bg) to 0. */
.sit-backdrop { z-index: 0 !important; }
.sit-page { z-index: 1; }


/* ======================================================================
   Sit page — click-advance stage + scroll-reveal detail sheet.
   --sheet (0..1) is set on .sit-page by scroll progress.
   ====================================================================== */

.sit-stage {
  position: relative;
  width: 100vw;
  height: 100vh;
  margin-left: calc(50% - 50vw);
  background: #000;
  overflow: hidden;
  color: #fafaf7;
  cursor: pointer;
  isolation: isolate;
  z-index: 1;
  /* Sheet progress shrinks + blurs the stage */
  transform: scale(calc(1 - 0.12 * var(--sheet, 0)));
  filter: blur(calc(var(--sheet, 0) * 10px)) brightness(calc(1 - 0.35 * var(--sheet, 0)));
  transform-origin: center 35%;
  transition: transform 180ms linear, filter 320ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

.sit-stage__layers {
  position: absolute; inset: 0;
}
.sit-stage__layer {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity 420ms cubic-bezier(0.2, 0.7, 0.2, 1);
  pointer-events: none;
}
.sit-stage__layer.is-active { opacity: 1; }

.sit-stage__video,
.sit-stage__img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
}
.sit-stage__video { object-fit: cover; background: #000; }
/* `contain` (not `cover`) so portrait photos on a landscape viewport stay
   whole — the plate colour shows in the unfilled bars instead of the
   photo getting cropped top-and-bottom. */
.sit-stage__img  { background-size: contain; background-position: center; background-repeat: no-repeat; background-color: #0b0907; }

.sit-stage__vignette {
  position: absolute; inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(0,0,0,0.32) 0%, rgba(0,0,0,0) 22%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.55) 100%),
    radial-gradient(ellipse at center, rgba(0,0,0,0) 55%, rgba(0,0,0,0.35) 100%);
}

.sit-stage__hud {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 3;
  opacity: calc(1 - var(--sheet, 0) * 1.4);
  transition: opacity 240ms var(--ease-out);
}
.sit-stage__tl,
.sit-stage__tr,
.sit-stage__counter,
.sit-stage__hint {
  position: absolute;
  color: rgba(250,250,247,0.88);
  font-size: 11px;
  letter-spacing: 0.2em;
}
.sit-stage__tl { top: 72px; left: 32px; }
.sit-stage__tr { top: 72px; right: 32px; }
.sit-stage__counter {
  bottom: 32px; left: 32px;
  color: rgba(250,250,247,0.9);
}
.sit-stage__hint {
  bottom: 32px; left: 50%; transform: translateX(-50%);
  font-size: 10px; letter-spacing: 0.28em;
  color: rgba(250,250,247,0.6);
  /* Reuses the `scroll-hint-breathe` keyframe from the feed's SCROLL
     hint — a consistent "this surface is interactive" cue across
     routes. Slightly slower period (3.6s vs 3.2s on the feed) because
     the sit stage is more cinematic and the cue should be quieter. */
  animation: scroll-hint-breathe 3600ms ease-in-out infinite;
  opacity: 0.6;
}
@media (prefers-reduced-motion: reduce) {
  .sit-stage__hint { animation: none; opacity: 0.6; }
}

/* Nav on dark sit-page stays readable */
body:has(.sit-page) .site-nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 40;
  background: linear-gradient(180deg, rgba(0,0,0,0.45), rgba(0,0,0,0));
  border-bottom-color: transparent;
  color: #fafaf7;
  backdrop-filter: blur(4px);
}
body:has(.sit-page) .site-nav a,
body:has(.sit-page) .site-nav .wm { color: #fafaf7; }

/* Page scroll runway — 140vh gives the sheet its 40vh rise-range. */
.sit-page {
  position: relative;
  min-height: 140vh;
}

/* ---- Sheet ---- */
.sit-sheet {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 10;
  min-height: 62vh;
  /* Stay visually tied to the media behind. Darkness spreads gradually
     from the top (same as the blurred media) down to ~20% darker at
     the very bottom — no hard transition, no flat slab. */
  background: linear-gradient(180deg,
    rgba(10, 9, 8, 0) 0%,
    rgba(10, 9, 8, 0) 22%,
    rgba(10, 9, 8, 0.04) 42%,
    rgba(10, 9, 8, 0.10) 68%,
    rgba(10, 9, 8, 0.20) 100%);
  backdrop-filter: blur(22px) saturate(0.95);
  -webkit-backdrop-filter: blur(22px) saturate(0.95);
  color: #fafaf7;
  transform: translateY(calc((1 - var(--sheet, 0)) * 100%));
  transition: transform 320ms cubic-bezier(0.2, 0.7, 0.2, 1);
  will-change: transform;
  padding: 28px 48px 56px;
  pointer-events: auto;
}
.sit-sheet__handle {
  width: 40px; height: 3px;
  border-radius: 2px;
  background: rgba(250,250,247,0.28);
  margin: 0 auto 28px;
}
.sit-sheet__body {
  max-width: 1200px;
  margin: 0 auto;
}
.sit-sheet__kicker {
  display: block;
  color: rgba(250,250,247,0.55);
  font-size: 11px;
  letter-spacing: 0.22em;
  margin-bottom: 12px;
}
.sit-sheet__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 64px;
  line-height: 1.02;
  letter-spacing: -0.02em;
  margin: 0 0 14px;
  text-wrap: balance;
}
.sit-sheet__meta {
  font-size: 12px;
  letter-spacing: 0.18em;
  color: rgba(250,250,247,0.65);
  margin: 0 0 32px;
}
.sit-sheet__meta .sep { margin: 0 10px; color: rgba(250,250,247,0.35); }
.sit-sheet__blurb {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 22px;
  line-height: 1.5;
  color: rgba(250,250,247,0.92);
  max-width: 64ch;
  margin: 0 0 48px;
  text-wrap: pretty;
}
/* Removed .sit-sheet__blurb--empty / ::before — absence-beats-placeholder.
   Also: the broader .sit-sheet__* block is orphan (legacy OneSitFeed detail
   pattern; SitPage uses .sit-grid__*). Leaving the rest for a scoped cleanup. */
.sit-sheet__nav {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 24px;
  align-items: center;
  padding-top: 32px;
  border-top: 1px solid rgba(250,250,247,0.12);
}
.sit-sheet__nav button {
  background: transparent; border: 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(250,250,247,0.9);
  text-align: left;
}
.sit-sheet__nav button:last-child { text-align: right; align-items: flex-end; }
.sit-sheet__nav-center {
  justify-self: center;
  color: rgba(250,250,247,0.5) !important;
  font-size: 10px !important;
  letter-spacing: 0.22em !important;
}
.sit-sheet__nav-label { color: rgba(250,250,247,0.5); font-size: 10px; }
.sit-sheet__nav-loc {
  font-family: var(--font-display);
  text-transform: none; letter-spacing: 0;
  font-size: 22px;
  font-style: italic;
  color: #fafaf7;
}

/* FLIP entry — briefly disable stage transitions while positioning. */
.sit-stage.is-flipping { transition: none !important; }

/* ======================================================================
   Reviews — pull-quote component used inline on SitPage (dark) and on
   the InfoPage (light). Featured grid + full archive below.
   ====================================================================== */

.review {
  position: relative;
  margin: 48px 0;
  max-width: 56ch;
  padding-left: 36px;
}
/* On the sit overlay (dark variant), widen the review measure so the
   pull-quote takes less vertical space — user call. Still capped for
   reading comfort (80ch ≈ upper end of Butterick's 45–90 range). */
.sit-grid__header .review--dark {
  max-width: 80ch;
}
.review__glyph {
  position: absolute;
  left: -4px; top: -36px;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 120px;
  line-height: 1;
  color: currentColor;
  opacity: 0.18;
  user-select: none;
  pointer-events: none;
}
.review__body {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 20px;
  line-height: 1.55;  /* Research: italic on dark needs ≥1.55 (was 1.52). */
  text-wrap: pretty;
  margin: 0 0 18px;
  /* Preserve embedded newlines in reviews (some span paragraphs). */
  white-space: pre-wrap;
}
.review__attrib {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  text-transform: uppercase;
}
.review__who { opacity: 0.85; }
.review__dots {
  display: inline-flex;
  gap: 4px;
  align-items: center;
}
.review__dots span {
  width: 5px; height: 5px; border-radius: 50%;
  background: currentColor;
  opacity: 0.18;
}
.review__dots span.is-on { opacity: 0.7; }
.review__source {
  margin-left: auto;
  opacity: 0.55;  /* Research: 0.35 failed WCAG AA (~4:1) for 10-12px mono caps on dark. */
}

/* Dark variant — inside SitPage sheet. currentColor is already #fafaf7-ish
   (sheet inherits). */
.review--dark .review__body { color: rgba(250,250,247,0.92); }
.review--dark .review__attrib { color: rgba(250,250,247,0.85); }

/* Light variant — on InfoPage (warm paper bg). */
.review--light .review__body { color: var(--fg); }
.review--light .review__attrib { color: var(--fg-muted); }

/* AllReviews — every verified review on InfoPage. Two-column masonry,
   center-symmetric per design refinement 2026-05-01. Title sits center-
   weighted in its breathing room: section top padding ≈ head bottom
   margin, with no hairline between title and the masonry. */
.all-reviews {
  margin: 56px auto 96px;
  padding: clamp(32px, 4vh, 56px) clamp(24px, 6vw, 80px) 96px;
  border-top: 1px solid rgba(185, 197, 164, 0.18);
  max-width: 1280px;
  text-align: center;
}
.all-reviews__head {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 12px;
  padding-bottom: 0;
  margin-bottom: clamp(28px, 4vh, 48px);
  flex-wrap: wrap;
  text-align: center;
}
.all-reviews__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 44px;
  line-height: 1;
  letter-spacing: -0.02em;
  margin: 10px 0 0;
}
.all-reviews__meta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: var(--fg-muted);
}
.all-reviews__grid {
  columns: 2;
  column-gap: 64px;
}
.all-reviews__grid .review {
  margin: 0 0 64px;
  max-width: none;
  break-inside: avoid;
  page-break-inside: avoid;
  /* Reveal — each review fades in and rises 10px as it crosses the
     viewport threshold (IntersectionObserver in AllReviews). Stagger
     is natural: scroll position dictates entry order. */
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 540ms var(--ease-out), transform 540ms var(--ease-out);
}
.all-reviews__grid .review.is-in {
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  .all-reviews__grid .review { opacity: 1; transform: none; transition: none; }
}
/* Research: italic-at-length reduces reading speed ~5% (Arditi & Cho).
   In the 39-review masonry, switch body to ROMAN Fraunces and keep
   italic only on the SitPage singleton. Shrink the big glyph too —
   when every card is already a pull-quote, the 96px glyph is chrome. */
.all-reviews__grid .review__body {
  font-style: normal;
  font-size: 17px;
  line-height: 1.55;
}
.all-reviews__grid .review__glyph {
  font-size: 48px;
  top: -14px;
  opacity: 0.12;
}

@media (max-width: 900px) {
  .all-reviews__grid { columns: 1; }
  .all-reviews__grid .review { margin-bottom: 56px; }
  .all-reviews__title { font-size: 36px; }
}

/* Info-page tweaks for the new layout. */
.info-page__name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 72px;
  line-height: 1;
  letter-spacing: -0.02em;
  margin: 0 0 24px;
}

/* Minimal summary strip at top of the feed — years · sits · reviews · rating.
   Sits just under the Nav, fades as the feed begins scrolling. */
.onesit__summary {
  position: fixed;
  top: 72px; left: 0; right: 0;
  z-index: 5;
  display: flex;
  gap: 18px;
  justify-content: center;
  align-items: center;
  pointer-events: auto;
  font-size: 11px;
  letter-spacing: 0.26em;
  color: rgba(250,250,247,0.75);
  transition: opacity 220ms var(--ease-out);
  text-shadow: 0 1px 10px rgba(0,0,0,0.35);
  user-select: none;
  /* Fades as you scroll — floor at 0.35 so it never fully disappears.
     Driven by --scroll-p set on the .onesit container in JS. */
  opacity: max(0.35, calc(1 - var(--scroll-p, 0) * 1.6));
}
.onesit__summary-sep {
  color: rgba(250,250,247,0.3);
  letter-spacing: 0;
}

@media (max-width: 760px) {
  .onesit__summary {
    top: 54px;
    gap: 10px;
    font-size: 9px;
    letter-spacing: 0.2em;
  }
}

/* ======================================================================
   /travels — sit history + availability.
   Timeline (horizontal bars) + minimalist map + collapsible year sections.
   ====================================================================== */

.travels {
  max-width: 1280px;
  margin: 0 auto;
  padding: 48px 48px 96px;
}

.travels__head {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 40px;
}
.travels__stat {
  font-family: var(--font-display);
  font-weight: 400;
  /* --wght is driven by useVelocityWeight in Travels.jsx — Fraunces
     gets denser as you fling through the page, settles back at 400
     when you stop. Single heading only; no global scroll-type glitter. */
  font-variation-settings: "wght" var(--wght, 400);
  font-size: 48px;
  line-height: 1.02;
  letter-spacing: -0.02em;
  margin: 8px 0 6px;
  text-wrap: balance;
}
.travels__sub {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 16px;
  color: var(--fg-muted);
  max-width: 60ch;
  margin: 0;
}

/* ---- Timeline: full-viewport, 80vh tall, bar expands on hover ---- */
.travels-tl {
  position: relative;
  margin: 24px 0 48px;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  width: 100vw;
  padding: 0 16px;
  user-select: none;
}
.travels-tl__track {
  display: flex;
  align-items: stretch;
  gap: 2px;
  height: 80vh;
  min-height: 520px;
  background: transparent;
  overflow: visible;
}

.travels-tl__year {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  padding: 14px 6px;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  text-transform: uppercase;
  color: var(--fg-muted);
  border-left: 1px solid var(--hairline);
}
.travels-tl__year:first-child { border-left: 0; padding-left: 2px; }

.travels-tl__bar {
  position: relative;
  flex: 1 0 auto;
  min-width: 24px;
  border: 0;
  border-radius: 2px;
  cursor: pointer;
  opacity: 0.82;
  transition:
    opacity 200ms var(--ease-out),
    flex-grow 320ms cubic-bezier(0.2, 0.7, 0.2, 1),
    box-shadow 200ms var(--ease-out);
  padding: 0;
  overflow: hidden;
  color: #0b0b0a;
}
.travels-tl__bar:hover,
.travels-tl__bar.is-active {
  opacity: 1;
  box-shadow: 0 0 0 1px rgba(0,0,0,0.22), 0 16px 36px rgba(0,0,0,0.14);
  z-index: 4;
}
.travels-tl__bar:not(.has-details) { cursor: default; }

/* Spine — small label rotated up the bar (hidden when active) */
.travels-tl__spine {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  padding: 14px 4px;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  pointer-events: none;
  color: rgba(0,0,0,0.74);
  text-shadow: 0 1px 0 rgba(255,255,255,0.25);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  text-transform: uppercase;
  transition: opacity 200ms var(--ease-out);
}
.travels-tl__bar.is-active .travels-tl__spine,
.travels-tl__bar:hover .travels-tl__spine { opacity: 0; }
.travels-tl__spine-loc { white-space: nowrap; }
.travels-tl__spine-dur { opacity: 0.65; }

/* Card — expands into the bar when active */
.travels-tl__card {
  position: absolute;
  inset: 28px 24px 28px 24px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 10px;
  color: #0b0b0a;
  animation: tlCardIn 280ms cubic-bezier(0.2, 0.7, 0.2, 1);
  pointer-events: none;
  text-shadow: 0 1px 0 rgba(255,255,255,0.18);
}
@keyframes tlCardIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.travels-tl__card-kicker {
  font-size: 10px;
  letter-spacing: 0.24em;
  opacity: 0.7;
}
.travels-tl__card-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 56px;
  line-height: 1.04;
  letter-spacing: -0.02em;
  text-wrap: balance;
  margin-top: -2px;
}
.travels-tl__card-meta {
  font-size: 11px;
  letter-spacing: 0.18em;
  opacity: 0.78;
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0 12px;
}
.travels-tl__card-meta .sep { opacity: 0.45; }
.travels-tl__card-pets {
  font-size: 10px;
  letter-spacing: 0.2em;
  opacity: 0.6;
}
.travels-tl__card-blurb {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 20px;
  line-height: 1.45;
  max-width: 52ch;
  margin: 4px 0 0;
  text-wrap: pretty;
}
.travels-tl__card-cta {
  margin-top: auto;
  padding-top: 16px;
  font-size: 10px;
  letter-spacing: 0.28em;
  opacity: 0.82;
}
.travels-tl__bar:not(.has-details) .travels-tl__card-cta { opacity: 0.45; }

.travels-tl__bar--open {
  flex: 1 0 auto;
  min-width: 40px;
  background: transparent;
  border: 1px dashed var(--fg-subtle);
  opacity: 1;
  cursor: default;
}
.travels-tl__bar--open:hover { box-shadow: none; }
.travels-tl__bar--open .travels-tl__spine { color: var(--fg-muted); text-shadow: none; }

.travels-tl__legend {
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 14px;
  font-size: 10px;
  letter-spacing: 0.18em;
  color: var(--fg-muted);
}
.travels-tl__legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.travels-tl__legend-dot {
  width: 10px; height: 4px;
  border-radius: 2px;
  opacity: 0.85;
}
.travels-tl__legend-dot--open {
  background: transparent;
  border: 1px dashed var(--fg-subtle);
}

.travels-tl__tooltip {
  position: absolute;
  left: 50%;
  top: -96px;
  transform: translateX(-50%);
  background: var(--paper-50);
  border: 1px solid var(--hairline);
  padding: 10px 14px;
  border-radius: 4px;
  pointer-events: none;
  white-space: nowrap;
  font-size: 11px;
  letter-spacing: 0.12em;
  box-shadow: 0 8px 24px rgba(0,0,0,0.06);
  animation: tooltipFade 160ms var(--ease-out);
}
.travels-tl__tooltip-loc {
  font-family: var(--font-display);
  font-weight: 400;
  font-style: normal;
  font-size: 16px;
  letter-spacing: 0;
  color: var(--fg);
  text-transform: none;
  margin-bottom: 2px;
}
.travels-tl__tooltip-dates {
  color: var(--fg-muted);
  margin-bottom: 2px;
}
.travels-tl__tooltip-dog {
  color: var(--fg-muted);
  opacity: 0.75;
}

@keyframes tooltipFade {
  from { opacity: 0; transform: translate(-50%, 4px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

/* ---- Map -------------------------------------------------------- */
.travels-map {
  margin: 24px 0 56px;
}
.travels-map__grid {
  display: flex;
  gap: 32px;
  align-items: stretch;
}
.travels-map__panel {
  position: relative;
  flex: 0 0 auto;
}
.travels-map__panel-frame {
  position: relative;
  background: var(--paper-100);
  border: 1px solid var(--hairline);
  border-radius: 4px;
  aspect-ratio: 100 / 60;
  overflow: hidden;
}
.travels-map__svg {
  width: 100%;
  height: 100%;
  display: block;
}
.travels-map__grid-line {
  stroke: var(--fg-subtle);
  stroke-width: 0.2;
  stroke-dasharray: 1 1;
  opacity: 0.35;
}
.travels-map__pin {
  cursor: pointer;
  transition: transform 160ms var(--ease-out);
}
.travels-map__dot {
  transition: r 160ms var(--ease-out);
  stroke: rgba(0,0,0,0.25);
  stroke-width: 0.15;
}
.travels-map__pin.is-active .travels-map__dot {
  stroke: var(--fg);
  stroke-width: 0.4;
}
.travels-map__pulse {
  fill: currentColor;
  opacity: 0.28;
  animation: mapPulse 1400ms ease-in-out infinite;
}
@keyframes mapPulse {
  0%   { opacity: 0.32; transform: scale(0.95); }
  50%  { opacity: 0.15; transform: scale(1.15); }
  100% { opacity: 0.32; transform: scale(0.95); }
}
.travels-map__panel-label {
  margin-top: 10px;
  font-size: 10px;
  letter-spacing: 0.22em;
  color: var(--fg-muted);
}
.travels-map__hover-label {
  position: absolute;
  top: 10px; right: 12px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  background: var(--paper-50);
  padding: 6px 10px;
  border: 1px solid var(--hairline);
  border-radius: 3px;
  font-size: 10px;
  letter-spacing: 0.18em;
  pointer-events: none;
  animation: tooltipFade 160ms var(--ease-out);
}

/* ---- Year sections ---------------------------------------------- */
.travels-year {
  margin-top: 8px;
}
.travels-year__head {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 24px 0 14px;
  background: transparent;
  border: 0;
  border-top: 1px solid var(--hairline);
  cursor: pointer;
  text-align: left;
  color: var(--fg);
  transition: color 120ms var(--ease-out);
}
.travels-year__head:hover { color: var(--fg-muted); }
.travels-year__chevron {
  color: var(--fg-muted);
  width: 14px;
  height: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform 240ms var(--ease-standard), color 180ms var(--ease-standard);
}
.travels-year__head.is-open .travels-year__chevron {
  transform: rotate(90deg);
}

/* Smooth expand/collapse for the year's sit list.
   grid-template-rows: 0fr → 1fr is the idiomatic CSS-only animation
   for unknown content heights. The list stays mounted (accessible via
   keyboard + screen-reader markup); CSS collapses it to zero height
   with overflow:hidden on the child <ol>.
   Supported: Chrome 117+, Safari 17.4+, Firefox 128+ — all current. */
.travels-year__body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 360ms var(--ease-standard);
  /* Clip the ol's default margin too, which otherwise leaks through
     the grid row and gives a collapsed section ~40px of phantom height. */
  overflow: hidden;
}
.travels-year__body.is-open {
  grid-template-rows: 1fr;
}
.travels-year__body > .travels-year__list {
  min-height: 0;
  overflow: hidden;
  margin: 0;
}
@media (prefers-reduced-motion: reduce) {
  .travels-year__body { transition: none; }
}
.travels-year__head:hover .travels-year__chevron {
  color: var(--fg);
}
.travels-year__num {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 30px;
  line-height: 1;
  letter-spacing: -0.01em;
}
.travels-year__count {
  font-size: 10px;
  color: var(--fg-faint);
  letter-spacing: 0.2em;
}
.travels-year__rule {
  flex: 1;
  height: 1px;
  background: var(--hairline);
  margin-left: 12px;
}

.travels-year__list {
  list-style: none;
  margin: 12px 0 32px;
  padding: 0;
  animation: yearOpen 240ms var(--ease-out);
}
@keyframes yearOpen {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

.travels-year__row {
  display: grid;
  grid-template-columns: 14px 120px 1fr 48px 1fr 14px;
  align-items: center;
  gap: 16px;
  padding: 12px 8px;
  border-bottom: 1px solid var(--hairline);
  cursor: pointer;
  transition: background-color 120ms var(--ease-out);
}
.travels-year__row:hover,
.travels-year__row.is-hover {
  background-color: var(--paper-100);
}
.travels-year__row.is-open { cursor: default; }
.travels-year__row.is-open:hover { background-color: transparent; }

.travels-year__bar {
  width: 14px;
  height: 10px;
  border-radius: 1px;
  background: var(--fg-subtle);
}
.travels-year__row.is-open .travels-year__bar {
  background: transparent;
  border: 1px dashed var(--fg-subtle);
  width: 14px; height: 10px;
}

.travels-year__dates {
  font-size: 11px;
  color: var(--fg-muted);
  letter-spacing: 0.16em;
}
.travels-year__loc {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 18px;
  color: var(--fg);
}
.travels-year__days {
  font-size: 10px;
  color: var(--fg-faint);
  letter-spacing: 0.2em;
  text-align: right;
}
.travels-year__tag {
  font-size: 10px;
  color: var(--fg-muted);
  letter-spacing: 0.22em;
  justify-self: end;
}
.travels-year__row.is-open .travels-year__tag {
  color: var(--fg);
}
.travels-year__quote {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 22px;
  line-height: 0;
  color: var(--fg-muted);
  opacity: 0.55;
  transition: opacity 120ms var(--ease-out);
}
.travels-year__row:hover .travels-year__quote {
  opacity: 1;
  color: var(--fg);
}

@media (max-width: 760px) {
  .travels { padding: 32px 20px 64px; }
  .travels__stat { font-size: 32px; }
  .travels-map__grid { flex-direction: column; }
  .travels-map__panel { flex-basis: auto !important; width: 100%; }
  .travels-year__row {
    grid-template-columns: 12px 90px 1fr 36px;
    gap: 10px;
  }
  .travels-year__tag, .travels-year__quote { display: none; }
  .travels-year__loc { font-size: 15px; }
}

/* ---- Map outlines ---- */
.travels-map__state {
  fill: #ece7dc;
  stroke: #c7bfae;
  stroke-width: 0.12;
  stroke-linejoin: round;
  transition: fill 120ms var(--ease-out);
}
.travels-map__neighbor {
  fill: #dcd6c6;
  stroke: #c3bba9;
  stroke-width: 0.18;
  stroke-linejoin: round;
  opacity: 0.9;
}
.travels-map__country {
  fill: #ece7dc;
  stroke: #c7bfae;
  stroke-width: 0.18;
  stroke-linejoin: round;
}
.travels-map__neighbor-group { opacity: 0.85; }

/* ---- Hover preview panel (cursor-follow — microdot-inspired) ---- */
.sit-preview {
  position: fixed;
  top: calc(var(--cursor-y, 50vh) + 20px - (var(--cursor-flip-y, 0) * 480px));
  left: calc(var(--cursor-x, 50vw) + 20px - (var(--cursor-flip, 0) * 380px));
  width: 320px;
  max-height: min(560px, 78vh);
  overflow: hidden;
  background: var(--paper-50);
  border: 1px solid var(--hairline);
  border-radius: 3px;
  box-shadow: 0 24px 56px rgba(0, 0, 0, 0.14), 0 2px 8px rgba(0, 0, 0, 0.06);
  z-index: 20;
  pointer-events: auto;
  cursor: default;
  animation: previewIn 180ms cubic-bezier(0.2, 0.7, 0.2, 1);
  transition: top 120ms var(--ease-out), left 120ms var(--ease-out),
              box-shadow 180ms var(--ease-out), transform 180ms var(--ease-out);
}
.sit-preview.is-clickable { cursor: pointer; }
.sit-preview.is-clickable:hover {
  box-shadow: 0 32px 64px rgba(0, 0, 0, 0.18), 0 4px 12px rgba(0, 0, 0, 0.08);
  transform: translateY(-2px);
}
.sit-preview.is-clickable:hover .sit-preview__cta {
  color: var(--fg);
}
@keyframes previewIn {
  from { opacity: 0; transform: translate(0, 6px); }
  to   { opacity: 1; transform: translate(0, 0); }
}

.sit-preview__media {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: #111;
}
.sit-preview__video,
.sit-preview__plate {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background-size: cover;
  background-position: center;
}
/* Plate always sits behind the video so a stalled/failed video never
   shows as a black box in the Travels preview. */
.sit-preview__plate { z-index: 0; }
.sit-preview__video { z-index: 1; }
.sit-preview__body {
  padding: 20px 22px 20px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.sit-preview__kicker {
  font-size: 10px;
  letter-spacing: 0.22em;
  color: var(--fg-muted);
}
.sit-preview__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 26px;
  line-height: 1.04;
  letter-spacing: -0.01em;
  margin: 2px 0 4px;
  color: var(--fg);
}
.sit-preview__meta {
  font-size: 10px;
  letter-spacing: 0.18em;
  color: var(--fg-muted);
  margin: 0;
}
.sit-preview__meta .sep { margin: 0 8px; opacity: 0.45; }
.sit-preview__pets {
  font-size: 10px;
  letter-spacing: 0.2em;
  color: var(--fg-faint);
  margin: 0 0 8px;
}
.sit-preview__review,
.sit-preview__blurb {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 13px;
  line-height: 1.5;
  color: var(--fg);
  margin: 4px 0 0;
  position: relative;
  padding-left: 14px;
}
.sit-preview__glyph {
  position: absolute;
  left: -4px; top: -8px;
  font-size: 32px;
  font-family: var(--font-display);
  color: var(--fg-muted);
  opacity: 0.35;
  line-height: 1;
}
.sit-preview__cta {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--hairline);
  font-size: 9px;
  letter-spacing: 0.28em;
  color: var(--fg-muted);
}

@media (max-width: 960px) {
  .sit-preview { display: none; }
}

/* ---- Ambient hover on timeline (replaces popup preview) --------- */
/* Whole section responds when a bar is hovered. No card / no popup.
   Other bars dim; active one stays bright; centered typography
   overlays the timeline with the sit's metadata. */

.travels-tl {
  position: relative;
  transition: background-color 360ms var(--ease-out);
}
.travels-tl.is-active {
  background-color: color-mix(in srgb, var(--tl-active, transparent) 6%, transparent);
}

.travels-tl__bar {
  transition:
    opacity 240ms var(--ease-out),
    filter 240ms var(--ease-out),
    flex-grow 320ms cubic-bezier(0.2, 0.7, 0.2, 1),
    box-shadow 220ms var(--ease-out) !important;
}
.travels-tl__bar.is-dim {
  opacity: 0.16;
  filter: saturate(0.4) brightness(0.9);
}
.travels-tl__bar.is-active {
  opacity: 1 !important;
  filter: saturate(1.08) brightness(1.08);
  box-shadow: 0 0 0 1px rgba(0,0,0,0.28), 0 24px 56px rgba(0,0,0,0.22) !important;
  z-index: 4;
}

/* Year labels dim in sympathy with other bars when something is active */
.travels-tl.is-active .travels-tl__year {
  opacity: 0.25;
  transition: opacity 240ms var(--ease-out);
}

/* Ambient overlay — centered typography over the timeline */
.travels-tl__overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 5;
  opacity: 0;
  transition: opacity 280ms var(--ease-out);
}
.travels-tl.is-active .travels-tl__overlay { opacity: 1; }

.travels-tl__overlay-content {
  max-width: 680px;
  padding: 40px 48px;
  text-align: center;
  color: #fafaf7;
  text-shadow:
    0 2px 24px rgba(0, 0, 0, 0.55),
    0 1px 4px rgba(0, 0, 0, 0.45);
  animation: overlayIn 320ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
@keyframes overlayIn {
  from { opacity: 0; transform: translateY(10px) scale(0.985); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.travels-tl__overlay-kicker {
  display: block;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  text-transform: uppercase;
  opacity: 0.85;
  margin-bottom: 14px;
}
.travels-tl__overlay-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(60px, 9vw, 112px);
  line-height: 1;
  letter-spacing: -0.02em;
  margin: 0 0 16px;
  text-wrap: balance;
}
.travels-tl__overlay-meta {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  text-transform: uppercase;
  opacity: 0.82;
  margin: 0 0 28px;
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 12px;
}
.travels-tl__overlay-meta .sep { opacity: 0.45; }
.travels-tl__overlay-quote,
.travels-tl__overlay-blurb {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 22px;
  line-height: 1.5;
  max-width: 56ch;
  margin: 0 auto;
  text-wrap: pretty;
  position: relative;
  color: rgba(255, 255, 255, 0.94);
}
.travels-tl__overlay-glyph {
  font-size: 68px;
  line-height: 0;
  vertical-align: middle;
  opacity: 0.42;
  margin-right: 4px;
}
.travels-tl__overlay-attrib {
  display: block;
  margin-top: 16px;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  opacity: 0.72;
  font-style: normal;
  text-transform: uppercase;
}

/* Hide the no-longer-used popup preview */
.sit-preview { display: none; }

/* ---- Native View Transitions (Chrome 111+, Safari 18+) -----------
   Route changes wrap setState in document.startViewTransition(). These
   keyframes drive the fade+slide between old and new document states. */
::view-transition-old(root) {
  animation: vtOut 200ms cubic-bezier(0.4, 0, 0.2, 1) both;
}
::view-transition-new(root) {
  animation: vtIn 320ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
@keyframes vtOut {
  to { opacity: 0; transform: translateY(-6px); }
}
@keyframes vtIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Distinct curve for transitions into a sit page — feels more cinematic */
html[data-tx="to-sit"] ::view-transition-new(root) {
  animation: vtInSit 360ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
@keyframes vtInSit {
  from { opacity: 0; transform: scale(1.015); filter: blur(6px); }
  to   { opacity: 1; transform: scale(1);     filter: blur(0); }
}

/* ---- Reduced-motion respect -------------------------------------
   Collapse all non-essential motion for users with prefers-reduced-motion. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none !important;
  }
}

/* ---- Night theme scoped to History + About me ------------------- */
/* Overrides palette variables within these articles so everything
   inside reads on dark without touching the feed or sit-page rendering. */

.travels,
.info-page {
  background-color: var(--night-950);
  color: #fafaf7;
  --fg: rgba(250, 250, 247, 0.92);
  --fg-muted: rgba(250, 250, 247, 0.62);
  --fg-faint: rgba(250, 250, 247, 0.38);
  --fg-subtle: rgba(250, 250, 247, 0.22);
  --hairline: rgba(250, 250, 247, 0.12);
  --paper-50: #18171a;   /* "paper" redefined as near-ink so inherited styles don't blow out */
  --paper-100: #1d1c1f;
  --paper-200: #23222a;
  --paper-300: #2a2930;
}

/* Aristide-inspired editorial hero on /about. Massive display identifier
   stacked ("DYLAN / AGEMA") in a muted sage green, mono-caps bio
   underneath. Center-symmetric per design refinement 2026-05-01. */
.info-page--editorial .info-page__hero {
  padding: clamp(80px, 12vh, 160px) clamp(24px, 6vw, 80px) clamp(40px, 8vh, 100px);
  text-align: center;
}
.info-page__hero-id {
  margin: 0 0 clamp(32px, 6vh, 80px);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(64px, 16vw, 220px);
  line-height: 0.86;
  letter-spacing: -0.04em;
  color: #b9c5a4;        /* muted sage, matches aristide's palette key */
  display: flex;
  flex-direction: column;
  align-items: center;   /* center each line horizontally within the flex column */
  gap: 0;
}
.info-page__hero-id-line { display: block; }
.info-page__hero-bio {
  color: rgba(250, 250, 247, 0.72);
  font-size: 13px;
  line-height: 1.55;
  max-width: 56ch;
  margin: 0 auto;        /* center the 56ch block within the centered hero */
}
@media (max-width: 640px) {
  .info-page__hero-id { font-size: clamp(56px, 18vw, 120px); }
  .info-page__hero-bio { font-size: 12px; }
}

/* Biography paragraph — sits between hero and contact, hairlined off
   above. Currently empty (TODO placeholder); structure shipped first
   so the cascade timing is locked when copy lands. */
.info-page__biography {
  padding: clamp(48px, 6vh, 80px) clamp(24px, 6vw, 80px);
  border-top: 1px solid rgba(185, 197, 164, 0.18);
  text-align: center;
}
.info-page__biography p {
  font-family: var(--font-display, Fraunces), Georgia, serif;
  font-size: clamp(16px, 1.4vw, 18px);
  line-height: 1.55;
  color: rgba(250, 250, 247, 0.86);
  max-width: 72ch;
  margin: 0 auto;        /* center the prose block on the page axis */
}

/* InfoPage entrance cascade — see docs/adr/0001-info-page-motion-grammar.md.
   Per-letter type-laying for the hero name, block fade for body sections,
   IntersectionObserver per-element below the fold (AllReviews). Fires
   every visit (no sessionStorage gate). */
.info-page__hero-id-char {
  display: inline-block;
  opacity: 0;
  transform: translateY(8px);
  /* `both`: hold the `from` state during the per-letter delay, then hold
     the `to` state forever after. `backwards` alone (in the originating
     spec) reverts to the static opacity:0 rule once the keyframe ends — a
     letter would flash visible and then disappear. */
  animation: info-hero-letter 300ms cubic-bezier(0.05, 0.7, 0.1, 1) both;
  animation-delay: calc(var(--i) * 22ms);
}
@keyframes info-hero-letter { to { opacity: 1; transform: translateY(0); } }

.info-page__hero-bio,
.info-page__biography,
.info-page__contact {
  animation: info-section-fade 240ms cubic-bezier(0.05, 0.7, 0.1, 1) both;
}
.info-page__hero-bio { animation-delay: 350ms; }
.info-page__biography { animation-delay: 450ms; }
.info-page__contact { animation-delay: 550ms; }
@keyframes info-section-fade {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
}

/* AllReviews header block fade — toggled by IntersectionObserver in
   ReviewQuote.jsx so the heading and the masonry share the same enter
   grammar. Per-element reduce-motion opt-out lives below. */
.all-reviews__head {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 540ms var(--ease-out, cubic-bezier(0.05, 0.7, 0.1, 1)),
              transform 540ms var(--ease-out, cubic-bezier(0.05, 0.7, 0.1, 1));
}
.all-reviews__head.is-in {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .info-page__hero-id-char,
  .info-page__hero-bio,
  .info-page__biography,
  .info-page__contact,
  .all-reviews__head {
    animation: none !important;
    transition: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}

/* Body gets dark bg when either article is mounted so there's no paper peek */
body:has(.travels),
body:has(.info-page) {
  background-color: var(--night-950);
}

/* Nav readable over dark page content */
body:has(.travels) .site-nav,
body:has(.info-page) .site-nav {
  background: linear-gradient(180deg, rgba(10, 10, 9, 0.6), rgba(10, 10, 9, 0));
  border-bottom-color: rgba(250, 250, 247, 0.08);
  color: #fafaf7;
}
body:has(.travels) .site-nav a,
body:has(.travels) .site-nav .wm,
body:has(.info-page) .site-nav a,
body:has(.info-page) .site-nav .wm { color: #fafaf7; }

body:has(.travels) .site-foot,
body:has(.info-page) .site-foot {
  color: rgba(250, 250, 247, 0.4);
}

/* Timeline bars flip from ink-variations to paper-variations on dark.
   Single off-white for all; dim + active states still carry hover. */
.travels .travels-tl__bar:not(.travels-tl__bar--open) {
  background: #c0b9a8 !important;
}
.travels .travels-tl__bar.is-active {
  background: #fafaf7 !important;
  box-shadow: 0 0 0 1px rgba(250, 250, 247, 0.28),
              0 24px 56px rgba(0, 0, 0, 0.6) !important;
}
.travels .travels-tl__bar.is-dim {
  opacity: 0.12;
  filter: saturate(0.4) brightness(0.9);
}
.travels .travels-tl__bar--open {
  border-color: rgba(250, 250, 247, 0.22);
}

/* Ambient overlay typography on dark: white instead of shadow-heavy */
.travels .travels-tl__overlay-content {
  color: rgba(255, 255, 255, 0.96);
  text-shadow:
    0 2px 36px rgba(0, 0, 0, 0.9),
    0 1px 6px rgba(0, 0, 0, 0.7);
}
.travels .travels-tl__overlay-kicker { opacity: 0.72; }
.travels .travels-tl__overlay-meta   { opacity: 0.72; }

/* Year labels on dark */
.travels .travels-tl__year { color: rgba(250, 250, 247, 0.55); }

/* Year-section chrome on dark */
.travels .travels-year__head { color: #fafaf7; }
.travels .travels-year__head:hover { color: rgba(250, 250, 247, 0.65); }
.travels .travels-year__row:hover,
.travels .travels-year__row.is-hover { background-color: rgba(250, 250, 247, 0.04); }
.travels .travels-year__row .travels-year__loc { color: rgba(250, 250, 247, 0.95); }

/* About-me typography on dark */
.info-page .info-page__name { color: #fafaf7; }
.info-page .info-page__lead { color: rgba(250, 250, 247, 0.88); }
.info-page .info-page__dl dt { color: rgba(250, 250, 247, 0.5); }
.info-page .info-page__dl dd { color: rgba(250, 250, 247, 0.92); }
.info-page .link { color: rgba(250, 250, 247, 0.88); border-bottom-color: rgba(250, 250, 247, 0.3); }
.info-page .link:hover { color: #fff; border-bottom-color: #fff; }

/* Review masonry on dark — reuse the dark variant of the quote component */
.info-page .all-reviews__title { color: #fafaf7; }
.info-page .all-reviews__meta { color: rgba(250, 250, 247, 0.58); }
.info-page .all-reviews__head { border-bottom-color: rgba(250, 250, 247, 0.12); }
.info-page .review--light .review__body { color: rgba(250, 250, 247, 0.92); }
.info-page .review--light .review__attrib { color: rgba(250, 250, 247, 0.7); }
.info-page .review--light .review__dots span { background: #fafaf7; opacity: 0.18; }
.info-page .review--light .review__dots span.is-on { opacity: 0.75; }

/* ---- Nav hover underline: grows from the left on hover --------- */
.site-nav__links a {
  position: relative;
  padding-bottom: 4px;
}
.site-nav__links a::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  height: 1px;
  width: 100%;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 260ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.site-nav__links a:hover::after,
.site-nav__links a.active::after {
  transform: scaleX(1);
}
/* Existing .active color override still applies; the underline is in addition. */

/* Wordmark gets a subtle hover for consistency */
.site-nav .wm {
  transition: opacity 180ms var(--ease-out);
}
.site-nav .wm:hover { opacity: 0.7; }

/* ---- Book-a-sit CTA in nav + Bark grouped on the right --------- */
.site-nav__cta {
  display: inline-flex;
  align-items: center;
  gap: 12px;
}

.book-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  text-transform: uppercase;
  color: var(--fg);
  background: var(--paper-50);
  border: 1px solid var(--fg);
  border-radius: 2px;
  text-decoration: none;
  transition:
    background-color 220ms var(--ease-out),
    color 180ms var(--ease-out),
    transform 180ms var(--ease-out),
    scale 220ms var(--ease-out);
  white-space: nowrap;
  /* Magnetic-hover offset — driven by JS in Nav.jsx via rAF lerp.
     Uses the individual translate property so it composes with the
     existing hover `transform: translateY(-1px)` without conflict. */
  translate: var(--mag-x, 0) var(--mag-y, 0);
}
.book-btn:hover {
  background: var(--fg);
  color: var(--paper-50);
  /* Three interaction phases compose without collision via separate
     CSS properties: magnetic pull (`translate` — driven from JS in
     Nav.jsx), lift (`transform: translateY` — existing hover), and
     settle (`scale` — new). Magnetic signals approach; lift + scale
     signal the cursor arriving. */
  transform: translateY(-1px);
  scale: 1.03;
}
@media (prefers-reduced-motion: reduce) {
  .book-btn:hover { scale: 1; }
}
.book-btn span { transition: transform 220ms var(--ease-out); }
.book-btn:hover span { transform: translateX(3px); }

/* Book button stays paper-solid on every route — the one loud commercial
   signal on an otherwise dark canvas. Previously inverted to outline on
   travels/info/sit pages; that diluted the primary CTA. Now consistent. */
.book-btn:focus-visible {
  outline: 2px solid #fafaf7;
  outline-offset: 3px;
}

@media (max-width: 640px) {
  .book-btn span { display: none; }
}

/* ---- About me: verification chips + contact line (research fix) ---- */
.info-page__lead--muted {
  color: rgba(250, 250, 247, 0.62);
  margin-top: 12px;
}

.info-page__contact {
  padding: clamp(40px, 6vh, 80px) clamp(24px, 6vw, 80px) 0;
  border-top: 1px solid rgba(185, 197, 164, 0.18);
  text-align: center;
}
.info-page__contact-line {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px 14px;
  margin: 0;
}
.info-page__contact-email {
  color: #fafaf7;
  font-size: 15px;
  letter-spacing: 0;
  text-transform: none;
  border-bottom: 1px solid rgba(250, 250, 247, 0.4);
  padding-bottom: 2px;
  transition: border-color 180ms var(--ease-out), color 140ms var(--ease-out);
  text-decoration: none;
  font-family: var(--font-display);
}
.info-page__contact-email:hover {
  color: #fff;
  border-bottom-color: #fff;
}
.info-page__contact-sep {
  color: rgba(250, 250, 247, 0.35);
}

/* ---- Graceful video fade-in (plate → video, no pop) ------------ */
.sit-stage__video,
.onesit-frame__media video {
  opacity: 0;
  transition: opacity 400ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.sit-stage__video.is-ready,
.onesit-frame__media video.is-ready {
  opacity: 1;
}

/* ---- Mobile: ≤640px nav compressed so elements don't wrap --------
   Wordmark hidden (brand lives in the browser tab); nav links + book-a-sit
   + bark all shrink; Bark hidden under 480px. */
@media (max-width: 640px) {
  .site-nav {
    padding: 12px 14px;
    gap: 8px;
  }
  .site-nav .wm { display: none; }
  .site-nav__links { gap: 14px; }
  .site-nav__links a {
    font-size: 9px;
    letter-spacing: 0.16em;
  }
  .site-nav__cta { gap: 6px; }
  .book-btn {
    padding: 6px 10px;
    font-size: 9px;
    letter-spacing: 0.16em;
  }
  .book-btn span { display: none; }
  .bark-btn {
    font-size: 9px;
    padding: 4px 6px;
  }
  .onesit__summary {
    top: 52px !important;
    gap: 8px !important;
    font-size: 8px !important;
    letter-spacing: 0.14em !important;
  }
  /* Touch users drag natively — the text cue overlaps the pinned
     trust chip at narrow widths and isn't needed on touch anyway. */
  .onesit-frame__sweep-hint { display: none; }
}

@media (max-width: 480px) {
  .onesit__summary {
    /* On the smallest screens, show only the essential service line */
    display: flex;
  }
  .onesit__summary > *:nth-child(n+6) { display: none; }
}

/* History page on mobile — tall timeline is overwhelming. Reduce and
   let overlay do the work. */
@media (max-width: 640px) {
  .travels { padding: 24px 16px 48px; }
  .travels__stat { font-size: 28px !important; line-height: 1.08 !important; }
  .travels__sub { font-size: 14px; }
  /* 55 bars @ 24px min-width exceed the mobile viewport (~1700px vs 375px).
     Let the timeline scroll horizontally instead of spilling offscreen;
     `overscroll-behavior-x: contain` keeps vertical page scroll intact when
     the user reaches the end of the track. */
  .travels-tl {
    overflow-x: auto;
    overflow-y: visible;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
    -webkit-overflow-scrolling: touch;
  }
  .travels-tl__track {
    height: 48vh !important;
    min-height: 320px !important;
    width: max-content;
  }
  .travels-tl__year { font-size: 18px !important; padding: 8px 4px !important; }
  .travels-tl__overlay-title { font-size: clamp(40px, 11vw, 72px) !important; }
  .travels-tl__overlay-content { padding: 20px 16px !important; }
  .travels-year__row {
    grid-template-columns: 10px 80px 1fr 30px !important;
    gap: 8px !important;
    padding: 10px 4px !important;
  }
  .travels-year__tag, .travels-year__quote { display: none !important; }
  .travels-year__loc { font-size: 14px !important; }
  .travels-year__num { font-size: 24px !important; }
}

/* About me on mobile */
@media (max-width: 640px) {
  .info-page { padding: 24px 16px 48px; }
  .info-page__name { font-size: 48px !important; }
  .info-page__lead { font-size: 19px !important; line-height: 1.35 !important; }
  .info-page__contact-line { font-size: 11px; gap: 6px 10px; }
  .info-page__contact-email { font-size: 14px; }
  .all-reviews { padding: 0 16px; margin: 40px auto 64px; }
  .all-reviews__head { align-items: flex-start; }
  .all-reviews__title { font-size: 32px !important; }
}

/* Extra-narrow: shave every pixel to keep Book-a-sit fully visible */
@media (max-width: 480px) {
  .site-nav {
    padding: 10px 10px !important;
    gap: 4px !important;
  }
  .site-nav__links {
    gap: 10px !important;
    flex-shrink: 1;
    min-width: 0;
  }
  .site-nav__links a {
    font-size: 9px !important;
    letter-spacing: 0.12em !important;
    padding: 4px 0 !important;
  }
  .site-nav__cta {
    flex-shrink: 0;
  }
  .book-btn {
    padding: 6px 8px !important;
    font-size: 9px !important;
    letter-spacing: 0.1em !important;
    white-space: nowrap;
  }
}

/* Below 380px (iPhone SE), shorten "Book a sit" to "Book" */
@media (max-width: 380px) {
  .book-btn-label {
    /* If we add a span wrapper; otherwise rely on narrower letter-spacing */
    display: none;
  }
  .site-nav__links a { font-size: 8.5px !important; }
}

/* =========================================================================
   Dev-mode curation tool (DevArchive.jsx)
   Only rendered when hostname is localhost or ?dev=1. Public visitors see
   none of this. Visual language kept terse and mono to feel internal.
   ========================================================================= */
.dev-archive-btn {
  /* Bottom-left of the stage — top-right conflicts with the sticky nav,
     bottom-right with the dev widget. Bottom-left is clear and doesn't
     cover the centered scroll-to-read hint. */
  position: absolute; bottom: 20px; left: 20px; z-index: 50;
  width: 40px; height: 40px; padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(8px);
  color: rgba(255, 255, 255, 0.9);
  font: 600 20px/1 system-ui, sans-serif;
  cursor: pointer;
  transition: background 160ms ease, color 160ms ease, border-color 160ms ease;
}
.dev-archive-btn:hover { background: rgba(220, 50, 50, 0.7); border-color: rgba(255, 255, 255, 0.7); }
.dev-archive-btn.is-queued { background: rgba(220, 180, 50, 0.7); color: #000; border-color: rgba(255, 255, 255, 0.9); }

/* Toolbar wrapping the × + ★ buttons. Positioned where the old standalone
   × lived (bottom-left of the stage). Buttons sit side by side. */
.dev-btn-toolbar {
  position: absolute; bottom: 20px; left: 20px; z-index: 50;
  display: flex; gap: 10px;
}
.dev-btn-toolbar .dev-archive-btn,
.dev-btn-toolbar .dev-cover-btn {
  position: static;  /* override the absolute on the standalone selector */
}

.dev-cover-btn {
  width: 40px; height: 40px; padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(8px);
  color: rgba(255, 255, 255, 0.9);
  font: 600 18px/1 system-ui, sans-serif;
  cursor: pointer;
  transition: background 160ms ease, color 160ms ease, border-color 160ms ease;
}
.dev-cover-btn:hover { background: rgba(255, 215, 80, 0.5); border-color: rgba(255, 215, 80, 0.9); color: #fff; }
.dev-cover-btn.is-active { background: rgba(255, 215, 80, 0.9); color: #000; border-color: #fff; }

.dev-archive-widget__section {
  padding: 2px 0 6px;
  font-size: 9px; letter-spacing: 0.14em;
  opacity: 0.7;
}

.dev-archive-widget {
  position: fixed; bottom: 64px; right: 14px; z-index: 9999;
  font: 10px/1.2 'JetBrains Mono', ui-monospace, monospace;
  letter-spacing: 0.08em;
}
.dev-archive-widget__toggle {
  padding: 8px 12px;
  border: 1px solid rgba(255, 255, 255, 0.3);
  background: rgba(0, 0, 0, 0.85);
  color: rgba(255, 255, 255, 0.85);
  cursor: pointer;
  text-transform: uppercase;
}
.dev-archive-widget__toggle:hover { background: rgba(20, 20, 20, 0.95); }
.dev-archive-widget__panel {
  margin-top: 8px;
  padding: 12px;
  width: 320px;
  background: rgba(0, 0, 0, 0.9);
  border: 1px solid rgba(255, 255, 255, 0.3);
  color: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(10px);
}
.dev-archive-widget__empty { opacity: 0.55; padding: 8px 0; text-transform: uppercase; }
.dev-archive-widget__list {
  list-style: none; margin: 0 0 10px; padding: 0;
  max-height: 220px; overflow-y: auto;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
.dev-archive-widget__list li {
  display: flex; justify-content: space-between; align-items: center;
  gap: 8px; padding: 6px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.dev-archive-widget__list li:last-child { border-bottom: none; }
.dev-archive-widget__list li span {
  text-transform: none; letter-spacing: 0.04em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1;
}
.dev-archive-widget__undo {
  padding: 2px 6px; background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.3);
  color: rgba(255, 255, 255, 0.75);
  font: inherit; cursor: pointer;
}
.dev-archive-widget__undo:hover { background: rgba(255, 255, 255, 0.1); }
.dev-archive-widget__actions { display: flex; gap: 6px; }
.dev-archive-widget__btn {
  flex: 1; padding: 8px 10px;
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: transparent; color: rgba(255, 255, 255, 0.85);
  font: inherit; letter-spacing: 0.1em; cursor: pointer;
  text-transform: uppercase;
}
.dev-archive-widget__btn:hover:not(:disabled) { background: rgba(255, 255, 255, 0.1); }
.dev-archive-widget__btn:disabled { opacity: 0.35; cursor: default; }
.dev-archive-widget__btn--danger:hover:not(:disabled) { background: rgba(220, 50, 50, 0.5); }
.dev-archive-widget__divider {
  margin: 10px 0 8px;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}
.dev-archive-widget__hint {
  margin-top: 8px; padding: 6px 8px;
  text-align: center; text-transform: none; letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.7);
  background: rgba(255, 255, 255, 0.06);
  word-break: break-all;
}


/* ============================================================
   SIT ACCORDION — vertical photo-strip home feed.
   Inspired by aristidebenoist.com (transposed to vertical).
   Mouse-Y picks the active row; that row expands tall, others
   compress to thin strips. All videos always play in viewport.
   ============================================================ */

.sit-accordion-host {
  position: relative;
  background: #141414;
  color: #fafaf7;
  /* No top padding — the sticky capture wrapper handles vertical
     placement (accordion is centered in a 100vh sticky). Bottom
     padding still separates the host from whatever follows. */
  padding: 0 0 96px;
}

/* Accordion is a centered column of horizontal tiles (wide-short
   bars stacked top-to-bottom). The full set scrolls vertically;
   only one tile is "active" (expanded) at a time, driven by cursor-Y.
   Inspired by aristidebenoist.com's strip accordion (rotated 90°). */
/* Accordion is a centered column where each row self-sizes: width is
   driven by a U-curve on row index, height is driven by cursor proximity.
   Gap between rows is generous so each tile's bleed halo has room to
   taper off before reaching the neighbor — 4px gap caused bleed-on-bleed
   overlap. */
/* Horizontal strip band — aristide-inspired filmstrip. All sits sit in a
   row across the viewport, each a narrow vertical slice of its cover
   media. Cursor-X picks an active strip, which expands wider; others
   compress. The sequence is chronological (left → right) so the band
   IS a timeline on the home. */
/* Aristide-style custom smooth scroll: outer viewport hides overflow,
   inner track translates via transform updated by a rAF lerp loop (see
   SitAccordion.jsx). No native scrollbar, no snap fighting the user —
   just momentum-eased gliding. */
/* Aristide-style sit preview overlay. Opens on top of the full SitPage,
   shows stylized location + dates + review + Explore button. Dismisses
   on Explore. The per-sit background colour comes from --preview-bg
   (derived from the sit's plate). Letters of the location stagger in
   via animation-delay bound to --letter-delay. */
.sit-detail-preview {
  position: absolute;
  inset: 0;
  z-index: 12;  /* above backdrop/cover/grid (all sit under z-index 10) */
  background: var(--preview-bg, #1a1714);
  color: var(--preview-txt, #fafaf7);
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: clamp(24px, 5vh, 72px) clamp(20px, 4vw, 56px);
  transition: opacity 480ms ease-out, transform 520ms cubic-bezier(.22, .61, .36, 1);
  pointer-events: auto;
  overflow: hidden;
}
.sit-detail-preview__cover {
  position: absolute; inset: 0; z-index: 0;
  overflow: hidden;
  opacity: 0;
  transition: opacity 800ms ease-out;
}
.sit-detail-preview.is-ready .sit-detail-preview__cover { opacity: 1; }
.sit-detail-preview__cover img,
.sit-detail-preview__cover video {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 38%;
}
.sit-detail-preview__scrim {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg,
    rgba(10, 9, 8, 0.55) 0%,
    rgba(10, 9, 8, 0.32) 28%,
    rgba(10, 9, 8, 0.32) 72%,
    rgba(10, 9, 8, 0.78) 100%);
  pointer-events: none;
}
.sit-detail-preview__top,
.sit-detail-preview__hero,
.sit-detail-preview__foot { position: relative; z-index: 2; }
.sit-detail-preview:not(.is-ready) {
  opacity: 0;
  transform: translateY(12px);
}
.sit-detail-preview.is-ready {
  opacity: 1;
  transform: translateY(0);
}

/* Top chrome — counter left, "Sits" back-link center */
.sit-detail-preview__chrome {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  min-height: 54px;
}
.sit-detail-preview__counter {
  font-family: var(--font-display, Fraunces), Georgia, serif;
  font-size: clamp(32px, 3vw, 50px);
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.04em;
  color: var(--preview-txt, #fafaf7);
  opacity: 0.85;
  justify-self: start;
}
.sit-detail-preview__back {
  background: none;
  border: 0;
  color: inherit;
  font-size: 11px;
  letter-spacing: 0.22em;
  cursor: pointer;
  padding: 10px 16px;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  opacity: 0.85;
  transition: opacity 180ms ease-out;
}
.sit-detail-preview__back:hover,
.sit-detail-preview__back:focus-visible { opacity: 1; }
.sit-detail-preview__back-total {
  font-size: 10px;
  opacity: 0.6;
}

.sit-detail-preview__hero {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  gap: clamp(0px, 1vh, 8px);
  font-family: var(--font-display, Fraunces), Georgia, serif;
  font-weight: 400;
  line-height: 0.88;
  letter-spacing: -0.02em;
  font-size: clamp(64px, 16vw, 260px);
  white-space: nowrap;
}
.sit-detail-preview__line {
  display: block;
}
.sit-detail-preview__letter {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.3em);
  animation: sit-detail-preview-letter-in 720ms cubic-bezier(.22, .61, .36, 1) forwards;
  animation-delay: var(--letter-delay, 0ms);
}
@keyframes sit-detail-preview-letter-in {
  from { opacity: 0; transform: translateY(0.3em); }
  to   { opacity: 1; transform: translateY(0); }
}

.sit-detail-preview__foot {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: end;
  gap: clamp(16px, 3vw, 48px);
  font-size: 11px;
  letter-spacing: 0.14em;
}

/* Info-left: A/B/C/D letter-marked blocks (aristide pattern) */
.sit-detail-preview__info {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(86px, 1fr));
  gap: 16px 28px;
  margin: 0;
  justify-self: start;
  max-width: 440px;
  font-size: 10px;
  letter-spacing: 0.22em;
}
.sit-detail-preview__info-block {
  display: grid;
  grid-template-rows: auto auto;
  gap: 4px;
  align-content: start;
}
.sit-detail-preview__info-label {
  opacity: 0.55;
  margin: 0;
  font-size: 9px;
}
.sit-detail-preview__info-value {
  opacity: 0.95;
  margin: 0;
  font-size: 10px;
  text-transform: uppercase;
}

/* Center column — rotated vertical EXPLORE (aristide's .e.line-w) */
.sit-detail-preview__explore {
  position: relative;
  background: none;
  border: 0;
  color: inherit;
  padding: 0;
  cursor: pointer;
  justify-self: center;
  align-self: end;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-size: 11px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  opacity: 0.88;
  transition: opacity 180ms ease-out, transform 220ms ease-out;
  min-height: 96px;
}
.sit-detail-preview__explore:hover,
.sit-detail-preview__explore:focus-visible {
  opacity: 1;
  transform: rotate(180deg) translateY(4px);
}
.sit-detail-preview__explore::before {
  content: '';
  width: 1px;
  height: 28px;
  background: currentColor;
  opacity: 0.55;
  transition: height 220ms ease-out;
}
.sit-detail-preview__explore:hover::before { height: 40px; }
.sit-detail-preview__explore-arrow {
  font-size: 14px;
  letter-spacing: 0;
  transform: rotate(180deg);  /* re-upright inside the vertical-rl flow */
}

/* Info-right: short review blurb, italic serif body + mono attrib */
.sit-detail-preview__review {
  justify-self: end;
  text-align: right;
  opacity: 0.82;
  max-width: 380px;
  font-size: 10px;
  letter-spacing: 0.18em;
}
.sit-detail-preview__quote {
  display: inline;
  font-family: var(--font-display, Fraunces), Georgia, serif;
  font-style: italic;
  font-size: 13px;
  letter-spacing: 0;
  line-height: 1.45;
}
.sit-detail-preview__attrib {
  display: block;
  margin-top: 8px;
  opacity: 0.55;
  font-size: 9px;
}

/* Top-center live counter — "NN DAYS SAT" pinned above the accordion
   on the home feed. Fades in with the rest of the corner chrome via
   .intro-fade. Small, quiet — just a running tally. */
.site-nav__center {
  position: fixed;
  top: clamp(18px, 3vh, 36px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 30;
  /* Match the BL corner typography — JetBrains Mono via .mono-caps,
     11px, uppercase letter-spaced. Tabular nums keeps the count from
     reflowing as digits change. */
  color: #fafaf7;
  font-size: 11px;
  letter-spacing: 0.22em;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  white-space: nowrap;
}
@media (max-width: 768px) {
  .site-nav__center { display: none; }
}

/* Site-wide load veil — covers everything during the 'loading' phase so
   the user only sees the loader chrome at top-left. Also absorbs pointer
   events so hovering over where the accordion/timeline WILL be can't
   trigger hit-tests through the opaque sheet. The loader chrome at
   z-index: 40 still receives any events that land on it (not that it
   needs them). Unmounted when phase flips to 'cascading'. */
.accordion-veil {
  position: fixed;
  inset: 0;
  background: #141414;
  z-index: 35;
  pointer-events: auto;
  animation: accordion-veil-in 200ms ease-out both;
}
@keyframes accordion-veil-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Load-in chrome — pinned top-left while cover images decode. The count
   animates 0 → 100 as each image resolves; the hairline bar tracks the
   same ratio. Fades out when the cascade animation starts. */
.accordion-loader {
  position: fixed;
  top: clamp(20px, 3vh, 40px);
  left: clamp(20px, 3vw, 40px);
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 12px;
  pointer-events: none;
  color: #fafaf7;
  animation: accordion-loader-fade 360ms var(--ease-standard, ease-out) both;
}
.accordion-loader__count {
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  letter-spacing: 0.14em;
  opacity: 0.9;
}
.accordion-loader__bar {
  display: block;
  width: 120px;
  height: 1px;
  background: rgba(250, 250, 247, 0.18);
  position: relative;
  overflow: hidden;
}
.accordion-loader__bar-fill {
  position: absolute;
  inset: 0;
  background: #fafaf7;
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform 220ms cubic-bezier(.22, .61, .36, 1);
}
@keyframes accordion-loader-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Scroll-capture wrapper — height set inline by JS (viewportH + horizontal
   scroll budget). Makes the sticky accordion pin to viewport top for the
   duration of the wrapper's scroll range, letting us drive the horizontal
   strip from window.scrollY. */
.sit-accordion-capture {
  position: relative;
  width: 100vw;
}
.sit-accordion-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  overflow: hidden;
}
.sit-accordion-sticky__inner {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: clamp(16px, 3vh, 36px);
  width: 100vw;
}
.sit-accordion {
  position: relative;
  width: 100vw;
  /* Hero band takes most of the viewport so the archive below stays
     beneath the fold on first paint — the user should scroll intentionally
     to discover the archive rather than seeing it peek up under the
     filmstrip. 62vh of a 900 viewport ≈ 560px. */
  height: clamp(420px, 62vh, 700px);
  margin: 0;
  padding: 0;
  overflow: hidden;
  contain: layout paint style;
  /* Edge fades — soft mask on both sides so strips don't appear to
     abruptly begin/end at a hard vertical line. Matches aristide's
     "floating in the viewport" feel. */
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 4%, #000 96%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0%, #000 4%, #000 96%, transparent 100%);
  /* Cursor reads as "grab" on desktop — small affordance that the
     whole band is scrollable, matching aristide's feel. */
  cursor: grab;
}
.sit-accordion:active { cursor: grabbing; }

/* Canvas-rendered hero — fills the container. Block display so it
   respects the container's width; height 100% matches the band. */
.sit-accordion__canvas {
  display: block;
  width: 100%;
  height: 100%;
  user-select: none;
  -webkit-user-drag: none;
}

/* Absolute label overlay — sits over the canvas at the viewport
   center, labeling the currently-hovered sit. Mono-caps, non-
   interactive, fades in/out when hoverSit changes. */
.sit-accordion__overlay-label {
  position: absolute;
  bottom: 28px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 14px;
  padding: 8px 16px;
  color: #fafaf7;
  background: rgba(10, 9, 8, 0.72);
  border: 1px solid rgba(250, 250, 247, 0.12);
  border-radius: 999px;
  pointer-events: none;
  z-index: 5;
  white-space: nowrap;
  font-size: 12px;
}

.sit-accordion__row {
  position: relative;
  /* All tiles are the same width — aristide's strips are fixed and
     uniform; no magnification or per-position variation. The user
     reads chronology via ordering, not tile size. */
  flex: 0 0 clamp(200px, 16vw, 260px);
  height: 100%;
  overflow: hidden;
  cursor: pointer;
  background: #141414;
  /* Squared edges — aristide's strips are sharp rectangles, no radius. */
  border-radius: 0;
  transition: filter var(--dur-long) var(--ease-standard);
  isolation: isolate;
}
/* Compositor hint only during an active interaction window — avoids
   paying for 19 persistent GPU layers at rest. Picks up before the
   transition starts, drops after. */
.sit-accordion:hover .sit-accordion__row,
.sit-accordion__row.is-active {
  will-change: filter, flex-grow;
}

/* Aristide pattern (live-captured 2026-04-22): strips stay equal-width.
   Their WebGL canvas handles the "featured" feel via brightness + color
   bloom on the active strip, not DOM reflow. We adopt the color/brightness
   bloom in CSS and skip the width expansion so layout never shifts. */
.sit-accordion__row.is-active {
  /* flex-grow stays 1 — no expansion. */
  z-index: 1;
}

/* Filmstrip desaturation — idle strips read as dim monochrome; active
   strip reads as full color. The contrast between dim and bloomed is
   now the only signal (previously backed up by width change). Pushing
   the idle filter a touch deeper (brightness 0.55, saturate 0.08) makes
   the active bloom feel more decisive. */
.sit-accordion__row-media {
  transition: filter var(--dur-long) var(--ease-standard);
  filter: saturate(0.08) brightness(0.55);
}
.sit-accordion__row.is-active .sit-accordion__row-media {
  filter: saturate(1) brightness(1.06);
}
/* Subtle inner ring on active — fills the "this one is selected" gap
   left by the removed width expansion. Inset box-shadow is cheap and
   doesn't force a layer. */
.sit-accordion__row.is-active::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgba(250, 250, 247, 0.55);
  pointer-events: none;
  z-index: 3;
}

.sit-accordion__row:focus-visible {
  outline: 2px solid #fafaf7;
  outline-offset: -3px;
}

/* Absolute-fill the row with the media. Slightly oversized (110% width
   via negative inset) so the parallax `translate3d` shift doesn't expose
   the dark bg at the edges when the tile is far from center. */
.sit-accordion__row > .sit-accordion__row-media {
  position: absolute;
  top: 0; bottom: 0;
  left: -60px; right: -60px;
  width: auto;
  height: 100%;
  pointer-events: none;
  -webkit-mask-image: none;
  mask-image: none;
  will-change: transform;
}
.sit-accordion__row-plate {
  position: absolute; inset: 0;
  background-size: cover;
  /* `--focal` is set inline from cover.focal (defaults to 50% 38% in JSX).
     Applies to both the image plate and the video below, so the crop
     window follows the subject (dog/cat) instead of blindly centering. */
  background-position: var(--focal, 50% 38%);
}
.sit-accordion__row-media video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: var(--focal, 50% 38%);
  display: block;
  /* Invisible until onCanPlay fires; plate shows through meanwhile so a
     stalled or failed video never paints a black panel. Mirrors the
     SitPage grid-tile pattern. */
  opacity: 0;
  transition: opacity 320ms ease-out;
}
.sit-accordion__row-media video[data-ready="true"] { opacity: 1; }

.sit-accordion__row-vignette {
  position: absolute; inset: 0;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(0, 0, 0, 0.25) 0%,
    rgba(0, 0, 0, 0) 24%,
    rgba(0, 0, 0, 0) 60%,
    rgba(0, 0, 0, 0.55) 100%
  );
  z-index: 1;
}

.sit-accordion__row-label {
  position: absolute;
  bottom: 20px;
  left: 24px;
  right: 24px;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  z-index: 2;
  color: rgba(250, 250, 247, 0.94);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  text-transform: uppercase;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.55);
  pointer-events: none;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity var(--dur-med) var(--ease-standard),
              transform var(--dur-med) var(--ease-standard);
}
.sit-accordion__row.is-active .sit-accordion__row-label {
  opacity: 1;
  transform: translateY(0);
}

/* Year divider in horizontal strip band — narrow vertical label column
   between year-groups, writing-mode rotated so it reads top-to-bottom. */
.sit-accordion__year {
  flex: 0 0 auto;
  width: 40px;
  height: 100%;
  color: rgba(250, 250, 247, 0.45);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.06em;
  line-height: 16px;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  justify-content: center;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  padding: 0;
}
/* Hide the first year divider — it sits redundantly before the first
   strip of the most recent year. */
.sit-accordion > .sit-accordion__year:first-child { display: none; }

/* Top-of-page summary strip — thin row of trust signals across the top.
   Fixed-position so it sits above the accordion without taking flex height. */
/* Editorial intro strip — sits between the nav and sit 01 as a plain
   white mono-caps block on the page background. No floating / no overlay
   / no gray band. Part of the flow. */
.sit-accordion__summary {
  display: flex;
  justify-content: center;
  gap: 16px;
  padding: 28px 24px 24px;
  color: rgba(250, 250, 247, 0.88);
  white-space: nowrap;
  flex-wrap: wrap;
}
.sit-accordion__summary-sep { color: rgba(250, 250, 247, 0.3); }

/* Tick-map — small dots positioned by geographic longitude, a 1D map of
   where each sit happened (not the chronological order of the strips
   below). Clustered dots = multiple sits near the same longitude
   (most Boulder); a dot far from the rest = an out-of-state sit. */
.sit-accordion__ticks {
  position: relative;
  height: 14px;
  padding: 0;
  margin: 20px clamp(24px, 14vw, 200px) 10px;
}
.sit-accordion__tick {
  position: absolute;
  top: 50%;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: rgba(250, 250, 247, 0.22);
  transform: translate(-50%, -50%);
  transition: width var(--dur-short) var(--ease-standard),
              height var(--dur-short) var(--ease-standard),
              background var(--dur-short) var(--ease-standard);
}
.sit-accordion__tick.is-active {
  width: 7px;
  height: 7px;
  background: rgba(250, 250, 247, 0.92);
}

/* Aristide-informed page indicator — top-center, above the stats strip.
   Matches aristide's 01/30 book-chapter placement. */
.sit-accordion__indicator {
  display: flex;
  width: 100%;
  justify-content: center;
  align-items: baseline;
  gap: 6px;
  color: rgba(250, 250, 247, 0.55);
  pointer-events: none;
  font-variant-numeric: tabular-nums;
  padding: 22px 0 6px;
}
.sit-accordion__indicator-num {
  color: rgba(250, 250, 247, 0.92);
  min-width: 22px;
  text-align: right;
  transition: color var(--dur-short) var(--ease-standard);
}
.sit-accordion__indicator-slash { opacity: 0.35; }
.sit-accordion__indicator-total { opacity: 0.55; }

/* End-of-feed contact block — sits after the last sit row, full-bleed
   background, centered content. The last sit row rolls back up to 100vw
   via the U-curve so the transition into this block feels continuous. */
.accordion-contact {
  margin-top: 12vh;
  padding: 12vh 6vw 10vh;
  text-align: center;
  background: #141414;
  color: #fafaf7;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}
.accordion-contact__name {
  font-family: var(--font-display);
  font-size: clamp(48px, 7vw, 88px);
  font-weight: 400;
  line-height: 0.98;
  letter-spacing: -0.02em;
  margin: 0;
}
.accordion-contact__tagline {
  color: rgba(250, 250, 247, 0.62);
  margin: 0;
}
.accordion-contact__cta {
  display: inline-flex;
  align-items: center;
  gap: 20px;
  margin: 12px 0 4px;
  flex-wrap: wrap;
  justify-content: center;
}
.accordion-contact__email {
  color: #fafaf7;
  font-family: var(--font-display);
  font-size: 18px;
  letter-spacing: 0;
  text-decoration: none;
  border-bottom: 1px solid rgba(250, 250, 247, 0.35);
  padding-bottom: 2px;
  transition: border-color 180ms var(--ease-standard), color 140ms var(--ease-standard);
}
.accordion-contact__email:hover { border-bottom-color: #fafaf7; }
.accordion-contact__links {
  display: inline-flex;
  align-items: center;
  gap: 24px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 4px;
}
.accordion-contact__links a,
.accordion-contact__links button {
  color: rgba(250, 250, 247, 0.72);
  text-decoration: none;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  font: inherit;
  transition: color 140ms var(--ease-standard);
}
.accordion-contact__links a:hover,
.accordion-contact__links button:hover { color: #fafaf7; }

/* Persistent trust chip in bottom-left corner. Routes to /info on click. */
.sit-accordion__trust {
  position: absolute;
  left: 28px;
  bottom: 28px;
  z-index: 30;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(250, 250, 247, 0.18);
  border-radius: 999px;
  color: rgba(250, 250, 247, 0.92);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  cursor: pointer;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: background 200ms ease-out, transform 200ms ease-out;
}
.sit-accordion__trust:hover {
  background: rgba(250, 250, 247, 0.12);
  transform: translateY(-1px);
}
.sit-accordion__trust-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: #f6e95e;
  box-shadow: 0 0 8px rgba(246, 233, 94, 0.6);
}
.sit-accordion__trust-arrow { opacity: 0.7; }

/* ---- Full history timeline — duration-weighted bars for every sit ---- */
/* Sits in three tiers:
   --full:   bar is full-opacity warm ink; click opens overlay (photos)
   --review: bar is mid-opacity; click expands the review inline below
   --none:   bar is low-opacity reference entry; no click target
   Hero strip band above covers 'full' sits with cinematic media. This
   strip is the complete record. */
/* Buffer section — empty vertical space between the center-start
   accordion above and the left-aligned archive below. A thin centered
   rule + the kicker label bridge the two alignments without forcing
   either to change. */
.sit-accordion-host__buffer {
  padding: clamp(80px, 14vh, 180px) 0 clamp(40px, 7vh, 90px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  color: rgba(250, 250, 247, 0.4);
}
.sit-accordion-host__buffer-rule {
  width: 1px;
  height: 56px;
  background: linear-gradient(180deg,
    rgba(250, 250, 247, 0) 0%,
    rgba(250, 250, 247, 0.28) 50%,
    rgba(250, 250, 247, 0) 100%);
}
.sit-accordion-host__buffer-label {
  font-size: 11px;
  letter-spacing: 0.14em;
}

.sit-timeline {
  position: relative;
  max-width: none;
  /* Full-bleed like the accordion above. Horizontal scroll is handled
     by the inner track (transform: translateX via rAF) that syncs to
     the accordion's scroll position. */
  margin: 0;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 4%, #000 96%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0%, #000 4%, #000 96%, transparent 100%);
}
.sit-timeline__track {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 4px;
  /* 3× the old height (was 36px) so the timeline reads as a secondary
     hero element, not an afterthought. */
  height: 108px;
  /* Align with the accordion above — accordion's tile 0 is centered in
     the viewport with its LEFT EDGE at (50vw - 100px) (half of
     CANVAS_STRIP_W = 200). The timeline's first BAR begins at the
     same x so both strips share a common start line. Right padding
     gives a trailing buffer so the last bar doesn't hug the mask edge. */
  padding-left: calc(50vw - 100px);
  padding-right: 50vw;
  will-change: transform;
  /* Anchor for the absolute-positioned first year label below. */
  position: relative;
}

/* First year label — pull it OUT of the flex flow so the first bar
   takes the padding-left anchor and lines up with the first accordion
   tile. The label floats in the padding region to the left of the bar,
   still vertically oriented. Subsequent year labels keep their inline
   flex-item behavior so they sit between year groups naturally. */
.sit-timeline__track > .sit-timeline__year:first-child {
  position: absolute;
  left: calc(50vw - 100px - 22px);
  top: 0;
  bottom: 0;
  padding: 0;
  /* Inherit the vertical-rl + rotate treatment from the base rule. */
}
/* Timeline cascade — bars fly in from the right, mirroring the accordion.
   Each bar's offset scales by its --bar-idx. Bars stay off-screen during
   both 'loading' (images decoding) AND 'chrome' (corners fading in); the
   cascade only runs during 'cascading'. During 'done', default 0 transform. */
.sit-timeline__track--intro-loading .sit-timeline__bar,
.sit-timeline__track--intro-loading .sit-timeline__year,
.sit-timeline__track--intro-chrome .sit-timeline__bar,
.sit-timeline__track--intro-chrome .sit-timeline__year {
  transform: translateX(calc(100vw + var(--bar-idx, 0) * 700px));
  transition: none;
}
.sit-timeline__track--intro-cascading .sit-timeline__bar,
.sit-timeline__track--intro-cascading .sit-timeline__year {
  transform: translateX(0);
  transition: transform 2200ms cubic-bezier(.22, .61, .36, 1);
  transition-delay: calc(var(--bar-idx, 0) * 14ms);
}

/* Site-wide fade-in — any element tagged .intro-fade defaults to opacity
   0 during the loading + chrome phases. As soon as the cascade starts,
   they ease to 1. Corners fade in TOGETHER with the accordion cascade
   so the page reveals as one cohesive motion, not in two separate beats. */
.intro-fade { opacity: 0 !important; transition: opacity 900ms ease-out; }
body[data-intro="cascading"] .intro-fade,
body[data-intro="done"] .intro-fade,
html[data-intro="cascading"] body .intro-fade,
html[data-intro="done"] body .intro-fade { opacity: 1 !important; }

/* Pointer-event lockdown during loading + chrome phases. Tiles + bars
   are completely off-screen during these phases, so no hit-testing
   should fire. During the 'cascading' phase the hit-test math DOES
   account for the live cascadeOffset (see sitIndexAt in SitAccordion),
   so the click/hover area follows the moving tile and we leave events
   enabled there. */
body[data-intro="loading"] .sit-accordion__canvas,
body[data-intro="chrome"] .sit-accordion__canvas,
body[data-intro="loading"] .sit-timeline__bar,
body[data-intro="chrome"] .sit-timeline__bar,
body[data-intro="loading"] .sit-timeline__year,
body[data-intro="chrome"] .sit-timeline__year {
  pointer-events: none !important;
}
.sit-timeline__bar {
  /* Duration-weighted: each bar's width ∝ sit duration (days). The
     multiplier below (× 2) roughly doubles each bar vs. the old track
     width, matching the 2× wider request without flattening short
     sits into a uniform block. Floor of 8px keeps 1-day sits visible
     without overwhelming the proportionality. */
  flex: 0 0 auto;
  width: calc(max(8px, var(--days, 1) * 8px));
  height: 100%;
  border-radius: 6px;
  border: 0;
  padding: 0;
  cursor: pointer;
  transition: background var(--dur-short) var(--ease-standard),
              transform var(--dur-short) var(--ease-standard);
}
.sit-timeline__bar--full {
  background: rgba(250, 250, 247, 0.72);
}
.sit-timeline__bar--review {
  background: rgba(250, 250, 247, 0.32);
}
.sit-timeline__bar--none {
  background: rgba(250, 250, 247, 0.12);
  cursor: default;
}
.sit-timeline__bar--full:hover,
.sit-timeline__bar--full.is-active {
  background: rgba(250, 250, 247, 0.98);
  transform: scaleY(1.12);
}
.sit-timeline__bar--review:hover,
.sit-timeline__bar--review.is-active {
  background: rgba(250, 250, 247, 0.62);
  transform: scaleY(1.08);
}
.sit-timeline__bar--none:hover,
.sit-timeline__bar--none.is-active {
  background: rgba(250, 250, 247, 0.2);
}
.sit-timeline__bar:focus-visible {
  outline: 2px solid #fafaf7;
  outline-offset: 3px;
  border-radius: 6px;
}

/* Inline year label inside the track — translates with the track as
   it scrolls. `flex: 0 0 auto` keeps its natural width; small padding
   gives breathing room before the next bar. Vertical writing-mode
   makes the label read top-to-bottom alongside the bar, saving
   horizontal space and matching aristide's side-label pattern. */
.sit-timeline__year {
  flex: 0 0 auto;
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 10px 0 4px;
  color: rgba(250, 250, 247, 0.5);
  font-size: 11px;
  letter-spacing: 0.08em;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  white-space: nowrap;
}

.sit-timeline__meta {
  margin-top: 8px;
  color: rgba(250, 250, 247, 0.72);
  font-size: 12px;
  height: 18px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: baseline;
  justify-content: center;
}
.sit-timeline__meta-loc { color: #fafaf7; }
.sit-timeline__meta-sep { color: rgba(250, 250, 247, 0.3); }
.sit-timeline__meta-tag {
  padding: 2px 8px;
  border: 1px solid rgba(250, 250, 247, 0.25);
  border-radius: 999px;
  font-size: 10px;
  letter-spacing: 0.08em;
}
.sit-timeline__meta-hint { color: rgba(250, 250, 247, 0.38); }

.sit-timeline__review {
  position: relative;
  margin-top: 18px;
  padding: 20px 44px 20px 28px;
  background: rgba(250, 250, 247, 0.04);
  border: 1px solid rgba(250, 250, 247, 0.1);
  border-radius: 10px;
  max-width: 680px;
  margin-left: auto;
  margin-right: auto;
}
.sit-timeline__review-close {
  position: absolute;
  top: 10px; right: 12px;
  background: transparent;
  border: 0;
  color: rgba(250, 250, 247, 0.55);
  cursor: pointer;
  font-size: 20px;
  line-height: 1;
  padding: 4px 8px;
  border-radius: 4px;
  transition: color 140ms var(--ease-standard), background 140ms var(--ease-standard);
}
.sit-timeline__review-close:hover {
  color: #fafaf7;
  background: rgba(250, 250, 247, 0.06);
}
.sit-timeline__review-glyph {
  font-family: var(--font-display);
  font-size: 32px;
  color: rgba(250, 250, 247, 0.4);
  margin-right: 4px;
}
.sit-timeline__review-quote {
  font-family: var(--font-display);
  font-size: 18px;
  line-height: 1.48;
  color: #fafaf7;
  margin: 4px 0 12px;
  font-style: italic;
  letter-spacing: -0.005em;
}
.sit-timeline__review-attrib {
  color: rgba(250, 250, 247, 0.55);
  margin: 0;
}

@media (max-width: 768px) {
  .sit-timeline { margin: 16px 4vw 0; }
  .sit-timeline__track { height: 28px; }
  .sit-timeline__meta { font-size: 11px; }
}
@media (prefers-reduced-motion: reduce) {
  .sit-timeline__bar { transition: background var(--dur-short) var(--ease-standard) !important; }
  .sit-timeline__bar:hover,
  .sit-timeline__bar.is-active { transform: none !important; }
}

/* Small "where"/"when" axis label next to each axis — mono-caps, muted.
   Positioned absolutely to sit at the leftmost edge of the axis line. */
.sit-accordion__axis-label {
  position: absolute;
  left: clamp(24px, 14vw, 200px);
  transform: translate(-46px, -2px);
  top: 50%;
  color: rgba(250, 250, 247, 0.32);
  font-size: 11px;
  letter-spacing: 0.08em;
  pointer-events: none;
  white-space: nowrap;
}

/* Year spine — below the strip band. Same horizontal range as the band
   (clamp margins), year ticks at the horizontal position of the first
   strip of each year. */
.sit-accordion__spine {
  position: relative;
  height: 34px;
  margin: 14px clamp(24px, 14vw, 200px) 0;
  border-top: 1px solid rgba(250, 250, 247, 0.12);
}
.sit-accordion__spine-tick {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  color: rgba(250, 250, 247, 0.55);
}
.sit-accordion__spine-dot {
  width: 1px;
  height: 8px;
  background: rgba(250, 250, 247, 0.32);
  transition: background var(--dur-short) var(--ease-standard),
              height var(--dur-short) var(--ease-standard);
}
.sit-accordion__spine-year {
  font-size: 11px;
  letter-spacing: 0.06em;
  transition: color var(--dur-short) var(--ease-standard);
}
.sit-accordion__spine-tick.is-active .sit-accordion__spine-dot {
  background: rgba(250, 250, 247, 0.92);
  height: 12px;
}
.sit-accordion__spine-tick.is-active .sit-accordion__spine-year {
  color: rgba(250, 250, 247, 0.92);
}

/* Archive foot — the "classic view" escape hatch back to the Travels
   route for the user who wants the big duration-weighted timeline. */
.home-archive__foot {
  margin-top: 48px;
  padding-top: 28px;
  border-top: 1px solid rgba(250, 250, 247, 0.08);
  text-align: center;
}
.home-archive__classic {
  background: transparent;
  border: 0;
  color: rgba(250, 250, 247, 0.55);
  cursor: pointer;
  padding: 10px 14px;
  /* Inherit the mono-caps block spec from the parent foot instead of
     picking up the UA button default (Arial). Keeps the site's type
     ceiling of ~6 specs per surface. */
  font: inherit;
  letter-spacing: 0.04em;
  text-transform: lowercase;
  transition: color 140ms var(--ease-standard);
}
.home-archive__classic:hover { color: #fafaf7; }
.home-archive__classic:focus-visible {
  outline: 2px solid rgba(250, 250, 247, 0.65);
  outline-offset: 3px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  .home-archive__row,
  .home-archive__chev,
  .home-archive__classic,
  .home-archive__year-head,
  .sit-accordion__spine-dot,
  .sit-accordion__spine-year,
  .sit-accordion__tick {
    transition: none !important;
  }
  .home-archive__row:hover:not(.is-archived) {
    transform: none !important;
  }
}

/* ---- Home archive — history folded into the home below the strips ---- */
.home-archive {
  max-width: 1100px;
  margin: 9vh auto 0;
  padding: 0 clamp(24px, 6vw, 80px);
  color: #fafaf7;
}
.home-archive__head {
  text-align: center;
  margin-bottom: 28px;
}
.home-archive__title {
  color: rgba(250, 250, 247, 0.55);
  font-size: 13px;
  margin: 0;
}
/* Archive toggle — whole archive collapses under this button. Chevron
   rotates down when the archive is open. */
.home-archive__toggle {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  cursor: pointer;
  padding: 6px 10px;
  letter-spacing: 0.14em;
  transition: color 160ms ease-out;
}
.home-archive__toggle:hover,
.home-archive__toggle:focus-visible {
  color: rgba(250, 250, 247, 0.92);
}
.home-archive__toggle-chev {
  display: inline-flex;
  transition: transform 220ms cubic-bezier(.22, .61, .36, 1);
}
.home-archive.is-open .home-archive__toggle-chev {
  transform: rotate(90deg);
}
.home-archive__toggle-count {
  font-size: 10px;
  opacity: 0.5;
  letter-spacing: 0.16em;
}
.home-archive__year {
  border-bottom: 1px solid rgba(250, 250, 247, 0.08);
  padding: 0;
}
.home-archive__year:first-of-type {
  border-top: 1px solid rgba(250, 250, 247, 0.08);
}
.home-archive__year-head {
  display: grid;
  grid-template-columns: 18px auto auto 1fr;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 20px 0;
  background: transparent;
  border: 0;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: color 140ms var(--ease-standard);
}
.home-archive__year-head:hover { color: #fafaf7; }
.home-archive__year-head:focus-visible {
  outline: 2px solid rgba(250, 250, 247, 0.65);
  outline-offset: 4px;
  border-radius: 4px;
}
.home-archive__chev {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  color: rgba(250, 250, 247, 0.55);
  transition: transform 260ms var(--ease-standard);
}
.home-archive__year.is-open .home-archive__chev {
  transform: rotate(90deg);
}
.home-archive__year-num {
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 400;
  letter-spacing: -0.005em;
  font-variant-numeric: tabular-nums;
}
.home-archive__year-count {
  color: rgba(250, 250, 247, 0.52);
}
.home-archive__rule {
  height: 1px;
  background: rgba(250, 250, 247, 0.06);
  align-self: center;
}
.home-archive__list {
  list-style: none;
  padding: 0 0 18px 32px;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.home-archive__row {
  display: grid;
  grid-template-columns: 148px 1fr 48px 1fr;
  align-items: baseline;
  gap: 18px;
  padding: 10px 12px;
  border-radius: 6px;
  transition: background 120ms ease-out, transform 120ms ease-out;
}
.home-archive__row--full,
.home-archive__row--review {
  cursor: pointer;
}
.home-archive__row--full:hover,
.home-archive__row--review:hover {
  background: rgba(250, 250, 247, 0.05);
  transform: translateX(2px);
}
.home-archive__row--none {
  cursor: default;
  opacity: 0.45;
}
.home-archive__row--none:hover { background: transparent; transform: none; }
.home-archive__row.is-expanded {
  background: rgba(250, 250, 247, 0.06);
  transform: none;
}
.home-archive__row-tier {
  justify-self: end;
  color: rgba(250, 250, 247, 0.45);
  font-size: 11px;
  transition: color 140ms var(--ease-standard);
}
.home-archive__row--full .home-archive__row-tier { color: rgba(250, 250, 247, 0.72); }
.home-archive__row--full:hover .home-archive__row-tier,
.home-archive__row--review:hover .home-archive__row-tier { color: #fafaf7; }

/* Sample tags in the archive header — colored swatches matching the
   two tiers so the explanation reads without legend-hunting. */
.home-archive__tier-sample {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 10px;
  letter-spacing: 0.06em;
  vertical-align: baseline;
}
.home-archive__tier-sample--full {
  background: rgba(250, 250, 247, 0.85);
  color: #141414;
}
.home-archive__tier-sample--review {
  background: rgba(250, 250, 247, 0.2);
  color: rgba(250, 250, 247, 0.95);
}

/* Inline review expansion for 'review' tier rows. Sits inside the same
   <ol> so the year list stays cohesive; no separate list container. */
.home-archive__review {
  list-style: none;
  margin: 4px 12px 12px 12px;
  padding: 20px 28px 20px 28px;
  background: rgba(250, 250, 247, 0.04);
  border: 1px solid rgba(250, 250, 247, 0.1);
  border-radius: 10px;
  max-width: 680px;
}
.home-archive__review-glyph {
  font-family: var(--font-display);
  font-size: 28px;
  color: rgba(250, 250, 247, 0.4);
  margin-right: 4px;
  line-height: 1;
}
.home-archive__review-quote {
  font-family: var(--font-display);
  font-size: 17px;
  line-height: 1.48;
  color: #fafaf7;
  margin: 2px 0 10px;
  font-style: italic;
  letter-spacing: -0.005em;
}
.home-archive__review-attrib {
  color: rgba(250, 250, 247, 0.55);
  margin: 0;
}
.home-archive__row:focus-visible {
  outline: 2px solid rgba(250, 250, 247, 0.65);
  outline-offset: 2px;
}
.home-archive__row-date {
  color: rgba(250, 250, 247, 0.6);
  font-variant-numeric: tabular-nums;
}
.home-archive__row-loc {
  color: #fafaf7;
  font-family: var(--font-display);
  font-size: 18px;
  letter-spacing: -0.005em;
}
.home-archive__row-days {
  color: rgba(250, 250, 247, 0.72);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.home-archive__row-dog {
  color: rgba(250, 250, 247, 0.45);
  text-align: right;
}

/* Mobile: flip the strip band from horizontal to vertical stack —
   microdot.vision's "Mobile (390px): collapses to single-column full-
   width vertical stack. No attempt to preserve floating asymmetry."
   Each sit becomes a tappable full-width tile 140px tall; scroll the
   page naturally. The hero strip aesthetic is a desktop primitive;
   stacking is the right touch pattern. */
@media (max-width: 768px) {
  .sit-accordion-host { padding: 60px 0 64px; }
  .sit-accordion[data-mobile] {
    display: flex;
    flex-direction: row;
    height: 65vh;
    min-height: 320px;
    max-height: 520px;
    width: 100%;
    padding: 0;
    gap: 0;
    cursor: default;
    -webkit-mask-image: none;
    mask-image: none;
    contain: none;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
  }
  .sit-accordion[data-mobile]::-webkit-scrollbar { display: none; }
  .sit-accordion[data-mobile] .sit-accordion__canvas { display: none; }
  .sit-accordion__row {
    height: 100%;
    flex: 0 0 85vw;
    border-radius: 0;
    overflow: hidden;
    scroll-snap-align: center;
  }
  .sit-accordion__row.is-active { flex: 0 0 85vw; }
  .sit-accordion__row-label { opacity: 1; transform: none; }
  .sit-accordion__row-media {
    filter: none !important;
    left: 0 !important;
    right: 0 !important;
    width: 100% !important;
  }
  .sit-accordion__year {
    flex: 0 0 auto;
    height: 100%;
    width: 40px;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(250, 250, 247, 0.55);
    scroll-snap-align: none;
  }
  .sit-accordion__summary { display: none; }
  .sit-accordion__axis-label { display: none; }
  .sit-accordion__ticks { display: none; }
  .sit-accordion__indicator { padding: 12px 0 0; }

  .sit-timeline { margin: 18px 4vw 0; }
  .sit-timeline__track { height: 24px; gap: 3px; }
  .sit-timeline__year { font-size: 10px; }
  .sit-timeline__meta { font-size: 11px; }

  .home-archive { padding: 0 6vw; }
  .home-archive__row {
    grid-template-columns: 1fr;
    gap: 4px;
  }
  .home-archive__row-days,
  .home-archive__row-dog,
  .home-archive__row-tier {
    text-align: left;
    justify-self: start;
  }
}


/* ============================================================
   SIT OVERLAY — slide-up modal hosting the floating-tile grid.
   Sits over whichever route is mounted underneath; underlying
   route stays put at its scroll position.
   Inspired by microdot.vision's reel overlay.
   ============================================================ */

/* When the overlay is open, lock body scroll + hide the site nav.
   The overlay handles all interaction; site nav becomes noise. */
/* Body bg is globally dark (ui.css) so there's no paper-50 to flash
   through when the overlay opens. */
body.has-sit-overlay { overflow: hidden; }
/* Each fixed corner element slides to the nearest edge when the overlay
   is open — keeps them out of the overlay's way without a fade through
   partial-opacity state. Top corners slide up, bottom corners slide
   down, so they tuck off-screen in the same direction they already
   point. */
body.has-sit-overlay .site-nav__corner--tl,
body.has-sit-overlay .site-nav__corner--tr {
  transform: translateY(-140%);
}
body.has-sit-overlay .site-nav__corner--bl,
body.has-sit-overlay .site-nav__corner--br {
  transform: translateY(140%);
}
body.has-sit-overlay .site-nav__corner {
  pointer-events: none;
  transition: transform var(--dur-short) var(--ease-standard);
}
body.has-sit-overlay .site-foot {
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-short) var(--ease-standard);
}

.sit-overlay {
  position: fixed; inset: 0;
  z-index: 100;
  background: #141414;
  color: #fafaf7;
  overflow: hidden; /* inner scroll lives on .sit-overlay__scroll */
  transform: translateY(100%);
  transition: transform var(--dur-hero) var(--ease-standard);
  will-change: transform;
  isolation: isolate;
}
/* `is-open` is toggled by JS via two-rAF after mount → visible slideup
   from translateY(100%) → translateY(0). Removed on close → slides down. */
.sit-overlay.is-open { transform: translateY(0); }

/* Backdrop sits behind everything else inside the overlay. Because it's
   outside the inner scroll container, it stays put as the user scrolls. */
.sit-overlay .sit-backdrop { z-index: 0; position: absolute; inset: 0; }
.sit-overlay .sit-backdrop__layer { opacity: 0.55; }
.sit-overlay .sit-backdrop__veil {
  background: radial-gradient(ellipse at 50% 30%,
    rgba(10,9,8,0.55) 0%,
    rgba(10,9,8,0.78) 70%,
    rgba(10,9,8,0.92) 100%);
}

/* Inner scroll container — holds the header + floating grid.
   Hidden during loading/reveal/immersive so the (partially-opaque)
   cover fade-in doesn't show header text underneath. Fades in at squish
   in sync with the cover shrinking down to its tile. */
.sit-overlay__scroll {
  position: absolute; inset: 0;
  z-index: 5;
  overflow-y: auto;
  overflow-x: hidden;
  opacity: 0;
  transition: opacity var(--dur-hero) ease-out;
}
.sit-overlay[data-phase="squish"] .sit-overlay__scroll,
.sit-overlay[data-phase="done"] .sit-overlay__scroll { opacity: 1; }

/* Close X — pinned top-right of the overlay; outside the scroll
   container so it stays put. */
.sit-overlay__close {
  position: absolute;
  top: 28px; right: 32px;
  z-index: 200;
  background: rgba(10,9,8,0.55);
  border: 1px solid rgba(250,250,247,0.18);
  color: rgba(250,250,247,0.85);
  width: 44px; height: 44px;
  border-radius: 999px;
  display: grid; place-items: center;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 22px; line-height: 1;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: background var(--dur-short) var(--ease-standard), color var(--dur-short) var(--ease-standard), transform var(--dur-short) var(--ease-standard);
}
.sit-overlay__close:hover {
  background: rgba(250,250,247,0.12);
  color: #fafaf7;
  transform: scale(1.04);
}
.sit-overlay__close:focus-visible {
  outline: 2px solid #fafaf7;
  outline-offset: 3px;
}

/* Cover layer — full-bleed during reveal + immersive, then dimensions
   are animated directly to the cover tile's measured rect during squish
   (top/left/width/height set inline by JS). Animating dimensions instead
   of transform: scale keeps the image's aspect ratio correct throughout.
   Outside the scroll container so it stays put while measuring. */
.sit-overlay__cover {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  z-index: 50;
  pointer-events: none;
  background-size: cover;
  background-position: center;
  background-color: #0b0907;
  opacity: 0; /* hidden until media is ready */
  /* Squish: hero-scale transition (MD3 emphasized curve). 620ms was
     above NN/G's 500ms "draggy" threshold — dropped to --dur-hero (580ms). */
  transition: top    var(--dur-hero) var(--ease-emphasized),
              left   var(--dur-hero) var(--ease-emphasized),
              width  var(--dur-hero) var(--ease-emphasized),
              height var(--dur-hero) var(--ease-emphasized),
              opacity 800ms ease-out;
  will-change: top, left, width, height, opacity;
}
.sit-overlay[data-phase="reveal"] .sit-overlay__cover,
.sit-overlay[data-phase="immersive"] .sit-overlay__cover,
.sit-overlay[data-phase="squish"] .sit-overlay__cover { opacity: 1; }
.sit-overlay__cover-video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.sit-overlay[data-phase="done"] .sit-overlay__cover { opacity: 0; }

/* ---- Header (above the grid) ---- */
.sit-grid__header {
  position: relative;
  z-index: 5;
  /* Wider max-width so the pull-quote review spans more horizontal
     room and takes less vertical space on the sit overlay. Reading
     measure constraint still enforced on .review body (72ch cap). */
  max-width: 1040px;
  margin: 0 auto;
  padding: 8vh 6vw 4vh;
  text-align: left;
}
.sit-grid__kicker {
  display: block;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  text-transform: uppercase;
  color: rgba(250,250,247,0.55);
  margin-bottom: 14px;
}
.sit-grid__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(40px, 6vw, 72px);
  line-height: 1.02;
  letter-spacing: -0.02em;
  color: #fafaf7;
  margin: 0 0 16px;
  text-wrap: balance;
}
.sit-grid__meta {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  text-transform: uppercase;
  color: rgba(250,250,247,0.65);
  margin: 0 0 24px;
}
.sit-grid__meta .sep { margin: 0 10px; color: rgba(250,250,247,0.35); }
.sit-grid__blurb {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 22px;
  line-height: 1.5;
  color: rgba(250,250,247,0.92);
  max-width: 64ch;
  margin: 0 0 32px;
  text-wrap: pretty;
}

/* ---- Floating grid ---- */
/* Adaptive width: scales up on wider screens so photography gets real
   estate. 1720px ceiling keeps tiles from getting absurdly wide on ultra-
   wides; 96vw below that means the grid breathes to viewport minus a
   thin gutter. Vertical gap bumped to 160px to match microdot's
   breathing-room rhythm — the air between cells is the "fade" effect. */
.sit-grid {
  position: relative;
  z-index: 5;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 160px 16px;
  max-width: min(1720px, 96vw);
  padding: 0 2.5vw 20vh;
  margin: 0 auto;
}
.sit-grid__tile {
  position: relative;
  aspect-ratio: var(--ar, 3/2);
  background-color: #141414;
  /* overflow visible so the filename tag (positioned just above the
     tile) isn't clipped. Image cropping handled by .sit-grid__tile-media. */
  overflow: visible;
}
/* "Film developing" entry effect — a desaturated, bluish-dark wave
   that spreads outward from the photo's center and dissipates as it
   goes. Photo is fully visible underneath the whole time; the wave
   passes over and fades out. Like a fire spreading from a center
   ember and burning off at the edges.
   Toggled via data-developed="true" by IntersectionObserver (≥0.5 in
   view). Cover tile is force-developed during squish/done. */
.sit-grid__tile-media {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  /* Image cropping lives here now that the outer tile is overflow:visible
     (so the caption can spill below). */
  overflow: hidden;
}
/* Develop effect — exactly microdot's approach. A uniform pseudo-overlay
   with `mix-blend-mode: difference`. With grey it inverts/washes out the
   photo (gives the desaturated "negative film" look); transitioning to
   black makes the difference a no-op, restoring the photo. */
.sit-grid__tile-media::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background-color: rgb(128, 128, 128);
  mix-blend-mode: difference;
  transition: background-color 1500ms ease-out;
  pointer-events: none;
}
.sit-grid__tile[data-developed="true"] .sit-grid__tile-media::before {
  background-color: rgb(0, 0, 0);
}
.sit-grid__tile-media img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
}
.sit-grid__tile-media video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 320ms ease-out;
}
.sit-grid__tile-media video[data-ready="true"] { opacity: 1; }
.sit-grid__tile-plate {
  position: absolute; inset: 0;
  background-size: cover;
  background-position: center;
}

/* Source-file reference tag — filename only, sits JUST ABOVE the media's
   top-LEFT corner (microdot feed pattern: text adjacent to the media,
   not overlapping it). No text-shadow needed because it's on the page
   bg, not on the photo. */
.sit-grid__tile-code {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 0;
  z-index: 3;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.94);
  pointer-events: auto;
  user-select: text;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
@media (max-width: 720px) {
  .sit-grid__tile-code { font-size: 11px; bottom: calc(100% + 6px); }
}

/* Cover tile in the grid — invisible until the squish completes. The
   cover-layer overlay sits visually in front of it during squish/immersive. */
.sit-grid__tile--cover { opacity: 0; }
.sit-overlay[data-phase="done"] .sit-grid__tile--cover {
  opacity: 1;
  transition: opacity 280ms ease-out;
}
/* Cover tile force-developed by JS during squish/done so its center-out
   radial reveal completes alongside the cover-layer fade-out. */

/* Other tiles fly in from below during the squish. Initial state = hidden
   below viewport; data-entry="reveal" on the grid root triggers them. */
.sit-grid__tile--regular {
  opacity: 0;
  transform: translateY(60vh);
  transition: opacity 720ms cubic-bezier(0.2, 0.7, 0.2, 1),
              transform 720ms cubic-bezier(0.2, 0.7, 0.2, 1);
  transition-delay: calc(var(--i, 0) * 50ms);
}
.sit-grid[data-entry="reveal"] .sit-grid__tile--regular {
  opacity: 1;
  transform: none;
}

/* Mobile: collapse to single column, kill scattered behavior. */
@media (max-width: 768px) {
  .sit-grid {
    grid-template-columns: 1fr;
    gap: 8vh 0;
    padding: 0 4vw 16vh;
  }
  .sit-grid__tile {
    grid-column: 1 / -1 !important;
  }
  .sit-grid__header {
    padding: 14vh 4vw 6vh;
  }
  .sit-overlay__close {
    top: 16px; right: 16px;
    width: 40px; height: 40px;
  }
}

/* ============================================================
   /labs — public-facing showcase of the scraper + ML pipeline.
   ============================================================ */

.labs {
  max-width: min(1240px, 96vw);
  margin: 0 auto;
  padding: 8vh clamp(24px, 5vw, 80px) 16vh;
  color: #fafaf7;
  background: #141414;
  min-height: 100vh;
}

.labs__lede {
  font-family: var(--font-display);
  font-size: 20px;
  line-height: 1.4;
  color: rgba(250, 250, 247, 0.78);
  max-width: 56ch;
  margin: 0;
}

/* ---- Section 1: data pulse ---- */

.labs-pulse {
  margin-bottom: 96px;
}
.labs-pulse__h {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  color: rgba(250, 250, 247, 0.72);
  border-bottom: 1px solid rgba(250, 250, 247, 0.1);
  padding-bottom: 14px;
  margin: 0 0 28px;
}
.labs-pulse__updated {
  color: rgba(250, 250, 247, 0.42);
  margin: 0 0 36px;
  text-align: right;
}

/* Info pop-up on tool cards — small round (i) button next to each tool
   heading reveals a short popover explaining what the tool does. Keeps
   card default state blank so the data/inputs speak for themselves. */
.labs-info {
  position: relative;
  display: inline-flex;
  align-items: center;
  margin-left: 8px;
}
.labs-info__btn {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1px solid rgba(250, 250, 247, 0.3);
  background: transparent;
  color: rgba(250, 250, 247, 0.7);
  font-family: var(--font-display);
  font-size: 11px;
  line-height: 1;
  font-style: italic;
  padding: 0;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: color var(--dur-short) var(--ease-standard),
              border-color var(--dur-short) var(--ease-standard);
}
.labs-info__btn:hover,
.labs-info__btn:focus-visible {
  color: #fafaf7;
  border-color: rgba(250, 250, 247, 0.8);
  outline: none;
}
.labs-info__pop {
  position: absolute;
  top: calc(100% + 10px);
  left: 0;
  z-index: 5;
  width: clamp(240px, 28vw, 320px);
  padding: 14px 16px;
  background: #141414;
  border: 1px solid rgba(250, 250, 247, 0.2);
  border-radius: 4px;
  font-family: var(--font-display);
  font-size: 15px;
  line-height: 1.45;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: rgba(250, 250, 247, 0.88);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
  /* Fade-in — matches the site's restrained motion language */
  animation: labs-info-in var(--dur-short) var(--ease-standard);
}
@keyframes labs-info-in {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Inventory strip */
.labs-inv {
  list-style: none;
  padding: 0;
  margin: 0 0 64px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px 28px;
}
@media (max-width: 720px) {
  .labs-inv { grid-template-columns: repeat(2, 1fr); }
}
.labs-inv__item {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.labs-inv__n {
  font-family: var(--font-display);
  font-size: clamp(30px, 3.5vw, 44px);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  color: #fafaf7;
  transition: color var(--dur-long) var(--ease-standard);
}
.labs-inv__item[data-loading="true"] .labs-inv__n {
  color: rgba(250, 250, 247, 0.22);
  animation: labs-pulse 1.6s ease-in-out infinite;
}
@keyframes labs-pulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 0.75; }
}
@media (prefers-reduced-motion: reduce) {
  .labs-inv__item[data-loading="true"] .labs-inv__n { animation: none; }
}
.labs-inv__label {
  color: rgba(250, 250, 247, 0.54);
}

/* 30-day training-growth bar chart */
.labs-growth {
  margin: 0 0 64px;
}
.labs-growth__cap {
  color: rgba(250, 250, 247, 0.54);
  margin-bottom: 12px;
}
.labs-growth__chart {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 4px;
  height: 140px;
  border-bottom: 1px solid rgba(250, 250, 247, 0.12);
  padding: 0 2px 2px;
}
.labs-growth__bar {
  flex: 1 1 0;
  min-width: 2px;
  max-width: 14px;
  background: linear-gradient(180deg,
    rgba(250, 250, 247, 0.92) 0%,
    rgba(250, 250, 247, 0.32) 100%);
  border-radius: 1px 1px 0 0;
  transition: opacity var(--dur-short) var(--ease-standard);
}
.labs-growth__bar:hover { opacity: 0.7; }
.labs-growth__bar--skeleton {
  background: rgba(250, 250, 247, 0.14);
  animation: labs-pulse 1.6s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .labs-growth__bar--skeleton { animation: none; opacity: 0.5; }
}
.labs-growth__skeleton {
  color: rgba(250, 250, 247, 0.35);
  align-self: center;
  margin: auto;
}
.labs-growth__axis {
  display: flex;
  justify-content: space-between;
  color: rgba(250, 250, 247, 0.42);
  padding: 8px 2px 0;
}

/* Fun-facts list */
.labs-facts {
  list-style: none;
  padding: 0;
  margin: 0;
}
.labs-facts__item {
  font-family: var(--font-display);
  font-size: 22px;
  line-height: 1.4;
  color: rgba(250, 250, 247, 0.9);
  padding: 16px 0;
  border-bottom: 1px solid rgba(250, 250, 247, 0.08);
  max-width: 72ch;
}
.labs-facts__item:last-child { border-bottom: 0; }

/* ---- Section 2: tools preview ---- */

.labs-tools__h {
  color: rgba(250, 250, 247, 0.72);
  border-bottom: 1px solid rgba(250, 250, 247, 0.1);
  padding-bottom: 14px;
  margin: 0 0 28px;
}

.labs-tools__grid {
  max-width: 640px;
  margin: 0 auto;
}

.labs-tool {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 28px 24px;
  border: 1px solid rgba(250, 250, 247, 0.12);
  border-radius: 4px;
  background: rgba(250, 250, 247, 0.015);
}
.labs-tool__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 2px;
}
.labs-tool__h {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  text-transform: uppercase;
  margin: 0;
  color: #fafaf7;
}
.labs-tool__badge {
  padding: 2px 8px;
  border: 1px solid rgba(250, 250, 247, 0.22);
  border-radius: 999px;
  color: rgba(250, 250, 247, 0.72);
  font-size: 10px;
  letter-spacing: 0.1em;
}
.labs-tool__lede {
  font-family: var(--font-display);
  font-size: 17px;
  line-height: 1.45;
  color: rgba(250, 250, 247, 0.74);
  margin: 0;
  max-width: 50ch;
}

.labs-tool__row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.labs-tool__row--actions {
  justify-content: space-between;
  margin-top: 6px;
}
.labs-tool__label {
  min-width: 72px;
  color: rgba(250, 250, 247, 0.58);
}
.labs-tool__input {
  flex: 1 1 180px;
  min-width: 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid rgba(250, 250, 247, 0.22);
  padding: 8px 2px;
  color: #fafaf7;
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: 0.01em;
}
.labs-tool__input:focus-visible {
  outline: none;
  border-bottom-color: #fafaf7;
}
.labs-tool__input--short { flex: 0 0 80px; }
.labs-tool__input--date { flex: 1 1 140px; min-width: 120px; }

.labs-autocomplete { position: relative; }
.labs-autocomplete__list {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 20;
  margin: 4px 0 0;
  padding: 4px 0;
  list-style: none;
  background: #1a1a18;
  border: 1px solid rgba(250, 250, 247, 0.15);
  border-radius: 4px;
  max-height: 220px;
  overflow-y: auto;
}
.labs-autocomplete__item {
  padding: 6px 12px;
  font-family: var(--font-body);
  font-size: 14px;
  color: rgba(250, 250, 247, 0.8);
  cursor: pointer;
}
.labs-autocomplete__item--hl {
  background: rgba(250, 250, 247, 0.08);
  color: #fafaf7;
}
.labs-tool__range {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex: 1 1 260px;
  min-width: 0;
  flex-wrap: wrap;
}
.labs-tool__to {
  color: rgba(250, 250, 247, 0.38);
}

.labs-tool__cta {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 16px;
  text-transform: uppercase;
  padding: 10px 16px;
  background: var(--paper-50);
  color: var(--fg);
  border: 1px solid var(--paper-50);
  border-radius: 2px;
  cursor: pointer;
  transition: background var(--dur-short) var(--ease-standard),
              color var(--dur-short) var(--ease-standard),
              transform var(--dur-short) var(--ease-standard);
}
.labs-tool__cta:hover:not(:disabled) {
  transform: translateY(-1px);
}
.labs-tool__cta:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.labs-tool__link {
  background: transparent;
  border: 0;
  padding: 0;
  color: rgba(250, 250, 247, 0.58);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.labs-tool__link:hover { color: #fafaf7; }

.labs-tool__msg {
  color: #e8b08c;
  margin: 0;
}
.labs-tool__fine {
  color: rgba(250, 250, 247, 0.38);
  margin: 0;
}
.labs-tool__waitlist {
  font-family: var(--font-display);
  font-size: 15px;
  line-height: 1.5;
  color: rgba(250, 250, 247, 0.82);
  margin: 4px 0 0;
}
.labs-tool__waitlist-link {
  color: #fafaf7;
  border-bottom: 1px solid rgba(250, 250, 247, 0.4);
  text-decoration: none;
}
.labs-tool__waitlist-link:hover { border-bottom-color: #fafaf7; }

/* Sequence Planner — inline results list. Restrained: one row per match,
   city in serif, dates + duration in mono. Fades in so the result appears
   as a soft reveal rather than a hard swap. */
.labs-results {
  margin-top: 8px;
  padding-top: 14px;
  border-top: 1px solid rgba(250, 250, 247, 0.12);
  animation: labs-results-in var(--dur-med) var(--ease-standard);
}
@keyframes labs-results-in {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
}
.labs-results__cap {
  color: rgba(250, 250, 247, 0.52);
  margin: 0 0 10px;
}
.labs-results__list {
  list-style: none;
  padding: 0;
  margin: 0 0 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.labs-results__row {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "city dates"
    "city duration";
  column-gap: 16px;
  row-gap: 2px;
  align-items: baseline;
  padding: 6px 0;
  border-bottom: 1px solid rgba(250, 250, 247, 0.06);
}
.labs-results__row:last-child { border-bottom: 0; }
.labs-results__city {
  grid-area: city;
  font-family: var(--font-display);
  font-size: 17px;
  line-height: 1.2;
  color: #fafaf7;
}
.labs-results__dates {
  grid-area: dates;
  color: rgba(250, 250, 247, 0.78);
  text-align: right;
}
.labs-results__duration {
  grid-area: duration;
  color: rgba(250, 250, 247, 0.52);
  text-align: right;
}
.labs-results__footnote {
  color: rgba(250, 250, 247, 0.38);
  margin: 10px 0 0;
}
.labs-results--empty .mono-caps {
  color: rgba(250, 250, 247, 0.52);
}

/* Sequence Planner — multi-stop chain results.
   Each chain renders as: meta line + indicator chips + vertical timeline.
   Score is hidden — used only for sort. Indicators carry the meaning. */
.labs-chains__list {
  list-style: none;
  padding: 0;
  margin: 0 0 12px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.labs-chain {
  padding: 12px 0 14px;
  border-bottom: 1px solid rgba(250, 250, 247, 0.08);
}
.labs-chain:last-child { border-bottom: 0; padding-bottom: 4px; }
.labs-chain__head {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  align-items: baseline;
  margin: 0 0 8px;
  color: rgba(250, 250, 247, 0.78);
}
.labs-chain__sits-count {
  color: #fafaf7;
}
.labs-chain__coverage {
  color: rgba(250, 250, 247, 0.62);
}
.labs-chain__range {
  color: rgba(250, 250, 247, 0.52);
  margin-left: auto;
}
.labs-chain__chips {
  list-style: none;
  padding: 0;
  margin: 0 0 10px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.labs-chip {
  font-family: var(--font-mono, "JetBrains Mono", monospace);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1;
  padding: 4px 8px;
  border-radius: 3px;
  border: 1px solid transparent;
}
.labs-chip--positive {
  color: rgba(180, 220, 168, 0.95);
  border-color: rgba(180, 220, 168, 0.32);
  background: rgba(180, 220, 168, 0.06);
}
.labs-chip--neutral {
  color: rgba(250, 250, 247, 0.52);
  border-color: rgba(250, 250, 247, 0.16);
  background: transparent;
}
.labs-chip--warning {
  color: rgba(232, 176, 140, 0.95);
  border-color: rgba(232, 176, 140, 0.32);
  background: rgba(232, 176, 140, 0.06);
}
.labs-chain__timeline {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  border-left: 1px dotted rgba(250, 250, 247, 0.18);
  padding-left: 12px;
}
.labs-chain__stop {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  column-gap: 12px;
  row-gap: 2px;
}
.labs-chain__city {
  font-family: var(--font-display);
  font-size: 16px;
  line-height: 1.2;
  color: #fafaf7;
}
.labs-chain__stop-meta {
  color: rgba(250, 250, 247, 0.62);
  text-align: right;
}
.labs-chain__open {
  all: unset;
  cursor: pointer;
  font-size: 11px;
  color: rgba(250, 250, 247, 0.42);
  transition: color 0.15s;
}
.labs-chain__open:hover {
  color: rgba(250, 250, 247, 0.85);
}
.labs-chains__asterisk-note {
  color: rgba(250, 250, 247, 0.38);
}

/* Listing Optimizer live results — score headline + insights list */
.labs-optimizer-results {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.labs-optimizer-results__score {
  display: flex;
  align-items: baseline;
  gap: 12px;
  border-bottom: 1px solid rgba(250, 250, 247, 0.08);
  padding-bottom: 12px;
}
.labs-optimizer-results__n {
  font-family: 'Fraunces', serif;
  font-size: 56px;
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.01em;
  color: rgba(250, 250, 247, 0.92);
}
.labs-optimizer-results__label {
  color: rgba(250, 250, 247, 0.52);
}
.labs-optimizer-results__insights {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.labs-optimizer-results__insight {
  font-family: 'Fraunces', serif;
  font-size: 15px;
  line-height: 1.45;
  color: rgba(250, 250, 247, 0.78);
}

/* Listing Optimizer photo drop zone */
.labs-drop {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 92px;
  border: 1px dashed rgba(250, 250, 247, 0.28);
  border-radius: 4px;
  cursor: pointer;
  transition: border-color var(--dur-short) var(--ease-standard),
              background var(--dur-short) var(--ease-standard);
}
.labs-drop:hover { border-color: rgba(250, 250, 247, 0.55); }
.labs-drop__input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}
.labs-drop__hint {
  color: rgba(250, 250, 247, 0.65);
}
.labs-drop__preview {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.labs-drop__thumb {
  position: relative;
  width: 72px;
  height: 72px;
  border-radius: 3px;
  overflow: hidden;
  background: #181715;
}
.labs-drop__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.labs-drop__x {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: rgba(10, 9, 8, 0.7);
  color: #fafaf7;
  border: 0;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
}
.labs-drop__x:hover { background: rgba(10, 9, 8, 0.9); }

/* ---- Lightbox — fullscreen media viewer over the sit overlay ------
   Layered above SitPage (z-index 100); click backdrop or X to close.
   Prev/Next arrows are hover-revealed at the sides. */
.sit-lightbox {
  position: fixed; inset: 0;
  z-index: 300;
  background: rgba(8, 7, 6, 0.94);
  display: grid;
  place-items: center;
  cursor: zoom-out;
  opacity: 0;
  transition: opacity var(--dur-med) ease-out;
}
.sit-lightbox.is-open { opacity: 1; }
.sit-lightbox__figure {
  margin: 0;
  max-width: 94vw;
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  cursor: default;
}
.sit-lightbox__media {
  display: block;
  max-width: 94vw;
  max-height: 84vh;
  width: auto;
  height: auto;
  object-fit: contain;
  background: #000;
}
.sit-lightbox__code {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.88);
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.sit-lightbox__close {
  position: absolute;
  top: 28px; right: 32px;
  z-index: 2;
  background: rgba(10,9,8,0.55);
  border: 1px solid rgba(250,250,247,0.18);
  color: rgba(250,250,247,0.92);
  width: 44px; height: 44px;
  border-radius: 999px;
  display: grid; place-items: center;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 22px; line-height: 1;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: background var(--dur-short) ease-out, transform var(--dur-short) ease-out;
}
.sit-lightbox__close:hover { background: rgba(250,250,247,0.14); transform: scale(1.04); }
.sit-lightbox__close:focus-visible { outline: 2px solid #fafaf7; outline-offset: 3px; }
.sit-lightbox__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 52px; height: 52px;
  border-radius: 999px;
  background: rgba(10,9,8,0.45);
  border: 1px solid rgba(250,250,247,0.12);
  color: rgba(250,250,247,0.9);
  display: grid; place-items: center;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 26px; line-height: 1;
  opacity: 0;
  transition: opacity var(--dur-short) ease-out, background var(--dur-short) ease-out;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.sit-lightbox:hover .sit-lightbox__nav,
.sit-lightbox__nav:focus-visible { opacity: 1; }
.sit-lightbox__nav:hover { background: rgba(250,250,247,0.14); }
.sit-lightbox__nav--prev { left: 24px; }
.sit-lightbox__nav--next { right: 24px; }
@media (max-width: 720px) {
  .sit-lightbox__close { top: 16px; right: 16px; width: 40px; height: 40px; }
  .sit-lightbox__nav { width: 44px; height: 44px; opacity: 0.7; }
  .sit-lightbox__nav--prev { left: 12px; }
  .sit-lightbox__nav--next { right: 12px; }
}
/* Hover cursor on any clickable tile (SitPage) */
.sit-grid__tile[role="button"] { cursor: zoom-in; }

/* Reduced motion: kill slide-up + squish + fly-in. Just fade. */
@media (prefers-reduced-motion: reduce) {
  .sit-overlay {
    transition: opacity 200ms ease-out;
    transform: none;
    opacity: 0;
  }
  .sit-overlay[data-phase="immersive"],
  .sit-overlay[data-phase="squish"],
  .sit-overlay[data-phase="done"] { opacity: 1; }
  .sit-overlay[data-phase="closing"] { opacity: 0; }
  .sit-overlay__cover { transition: opacity 200ms ease-out; }
  .sit-grid__tile--regular {
    opacity: 1; transform: none; transition: none;
  }
  .sit-grid__tile--cover { opacity: 1; }
}
