/* ──────────────────────────────────────────────────────────────────────────────────────────
   DESIGN TOKENS
   Frequently used colours, easing curves, and reusable values live here as CSS variables.
   The entire page can be rethemed by editing this block.
────────────────────────────────────────────────────────────────────────────────────────── */
:root {
  /* ── Core palette ── dynamically morphed by JS (updateAccent in slider.js) on every slide change GSAP tweens --accent and --accent2.
     The browser (<meta name="theme-color">) also updates in lockstep with --accent. The static values here are the initial fallback.
    -------------------------------------------------------------------------------------------------------------------------------------
    • accent, accent2 → fallback colors if JS not running yet (see Per-slide accent colour morphing in JS for details);
    • text, dark      → off-white & jet-black for text and background;
    • easing          → timing function for custom speeds (snappy deceleration curve);
  */
  --accent: #ffffff; --accent2: #f5f5f5;
  --text:   #f5f5f5; --dark:    #0a0a0a;
  --easing: cubic-bezier(0.7, 0, 0.3, 1);

  /* ── Accent shade scale ── */
  --accent-5:  color-mix(in srgb, var(--accent) 05%, transparent); /* watermark, subtle bg    */
  --accent-10: color-mix(in srgb, var(--accent) 10%, transparent); /* hover bg, fine borders  */
  --accent-15: color-mix(in srgb, var(--accent) 15%, transparent); /* dividers, separators    */
  --accent-20: color-mix(in srgb, var(--accent) 20%, transparent); /* dim ring, dim label     */
  --accent-25: color-mix(in srgb, var(--accent) 25%, transparent); /* key borders, ring idle  */
  --accent-35: color-mix(in srgb, var(--accent) 35%, transparent); /* ring shadow, tick marks */
  --accent-50: color-mix(in srgb, var(--accent) 50%, transparent); /* cursor ring, label play */
  --accent-75: color-mix(in srgb, var(--accent) 75%, transparent); /* ring active stroke      */

  /* ── Text shade scale ── */
  --text-20: color-mix(in srgb, var(--text) 20%, transparent); /* footer text, hints       */
  --text-30: color-mix(in srgb, var(--text) 30%, transparent); /* inactive dots            */
  --text-50: color-mix(in srgb, var(--text) 50%, transparent); /* scroll hint, dimmed text */

  /* ── Dark shade scale ── */
  --dark-30: color-mix(in srgb, var(--dark) 30%, transparent); /* slide overlay light */
  --dark-70: color-mix(in srgb, var(--dark) 70%, transparent); /* slide overlay dark  */
  --dark-90: color-mix(in srgb, var(--dark) 90%, transparent); /* toast message box   */

  /* ── Breakpoint token ──
     Single source of truth for the mobile/desktop split. CSS custom properties cannot be used inside @media queries,
     so the @media below hard-codes the same value — but JS reads THIS property at runtime via getComputedStyle so it never needs its own copy. */
  --mobile-breakpoint: 768; /* unitless — px unit added in JS; @media adds it directly so —
  ───────────────────────────────────────────────────────────────────────────────────────────
    ⚠ Warning — If you change this value, update the @media (max-width: …) rule to match.
  ──────────────────────────────────────────────────────────────────────────────────────── */
}

/* ──────────────────────────────────────────────────────────────────────────────────────────────
   Z-INDEX STACKING ORDER
   ──────────────────────────────────────────────────────────────────────────────────────────────
   Single source of truth for every stacking layer in this file.
   Before adding a new fixed/absolute element, choose a value from the gaps listed below
   and register it here — never pick an arbitrary number without updating this table.
   ──────────────────────────────────────────────────────────────────────────────────────────────

   CURSOR (always on top — must never be obscured by any UI element)
   ┌─────────────────────────────┬───────┐
   │ .cursor                     │  9999 │
   │ .cursor-follower            │  9998 │
   │ .click-ripple               │  9997 │
   └─────────────────────────────┴───────┘

   FULL-SCREEN COVERS (block all interaction beneath them)
   ┌─────────────────────────────┬───────┐
   │ .loader                     │  1000 │  initial load cover; removed once ready
   │ .orientation-overlay        │   900 │  landscape-on-mobile prompt
   └─────────────────────────────┴───────┘

   NAVIGATION & MENUS
   ┌─────────────────────────────┬───────┬──────────────────────────────────────────────────────┐
   │ .hamburger                  │   500 │  must sit above .mobile-menu so × stays tappable     │
   │ .transition-toast           │   500 │  shares level with .hamburger; safe because          │
   │                             │       │  pointer-events: none — never blocks the button      │
   │ .update-toast               │   500 │  shares level; pointer-events: all (has Reload btn)  │
   │                             │       │  positioned lower so it never overlaps               │
   │                             │       │  with .transition-toast                              │
   │ .nav                        │   450 │  below hamburger/toast; above content & HUD          │
   │ .mobile-menu                │   400 │  below .hamburger so the close button renders on top │
   └─────────────────────────────┴───────┴──────────────────────────────────────────────────────┘

   PERSISTENT CONTROLS (always-visible UI elements overlaid on top of slides)
   ┌─────────────────────────────┬───────┐
   │ .controls-popup             │   300 │  keyboard cheatsheet
   │ .transition-overlay         │   200 │  curtain-wipe strips between slides
   │ .controls                   │   100 │  dot nav
   │ .arrows                     │   100 │  prev / next buttons
   │ .slide-counter              │   100 │  "01 — 05" label
   │ .scroll-hint                │   100 │  animated chevrons
   │ .progress-line              │   100 │  bottom progress bar
   └─────────────────────────────┴───────┘

   SLIDE INTERNALS (z-index is local to each .slide stacking context)
   ┌─────────────────────────────┬───────┐
   │ .slide-bg::before (grain)   │     2 │
   │ .slide-bg::after (gradient) │     1 │
   └─────────────────────────────┴───────┘

   VANTA BACKGROUND
   ┌─────────────────────────────┬───────┐
   │ #vanta-bg                   │     0 │  3D animated fallback; behind .slider (z:1)
   │ .slider                     │     1 │  explicit; keeps slider above #vanta-bg
   └─────────────────────────────┴───────┘

   ── SAFE INSERTION ZONES ──────────────────────────────────────────────────────────────────────
    9997 – 9999   reserved for cursor layers
     901 – 9996   modals / critical alerts above the orientation overlay
     501 –  899   currently unused — above menus
     451 –  499   currently unused — between nav and hamburger
     401 –  449   currently unused — between mobile-menu and nav
     301 –  399   currently unused — between controls-popup and mobile-menu
     201 –  299   currently unused — between transition-overlay and controls-popup
     101 –  199   currently unused — between HUD and transition-overlay
   ─────────────────────────────────────────────────────────────────────────────────────────── */

/* Reset: strip browser defaults, hide scrollbars globally */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; scrollbar-width: none; -ms-overflow-style: none; } *::-webkit-scrollbar { display: none; }

html, body {
  text-rendering: optimizeLegibility; font-family: 'DM Mono', monospace;
  /* ───────────────────────────────────────────────────────────────────────────────────────────
     Vanta.js animated background renders on #vanta-bg (z-index: -1) behind this layer.
     Solid dark fallback keeps content readable if Vanta fails to initialise (e.g. no WebGL).
  ─────────────────────────────────────────────────────────────────────────────────────────── */
  background: var(--dark);       /* dark background as fallback, matches .t-strip color */
  cursor: none;                  /* native cursor hidden — replaced by .cursor and .cursor-follower */
  overflow: hidden;              /* full-screen slider; scrolling is handled via JS and touch events */
  height: 100vh; height: 100dvh; /* 100dvh accounts for mobile browser chrome */
  width: 100vw;
}
a { text-decoration: none !important; } /* removing underline from all links */

/* ── Vanta animated background canvas ── Fixed fullscreen layer behind all content.
   pointer-events: none ensures it never intercepts mouse or touch events meant for the UI. */
#vanta-bg {
  position: fixed;
  inset: 0;             /* top/right/bottom/left: 0 — covers the full viewport */
  z-index: 0;           /* sits behind .slider (z-index: 1) but above html/body */
  pointer-events: none; /* never blocks mouse/touch events */
  width: 100vw;
  height: 100vh;
}

/* ─────────────────────────────────────────────────────────────────────────────────
   CUSTOM CURSOR
   Two-layer system: a small filled dot (.cursor) that tracks instantly,
   and a larger ring (.cursor-follower) that lags behind via rAF lerp in JS.
   Both are invisible (opacity: 0) until the mouse first moves (.visible class).
───────────────────────────────────────────────────────────────────────────────── */
.cursor {
  position: fixed; width: 10px; height: 10px;
  background: var(--accent); border-radius: 50%;
  pointer-events: none; z-index: 9999;
  transform: translate(-50%,-50%);
  opacity: 0;
  transition: width 0.3s var(--easing), height 0.3s var(--easing), background 0.3s, opacity 0.5s ease;
  mix-blend-mode: difference; /* inverts colours beneath the dot */
}
.cursor-follower {
  position: fixed; width: 40px; height: 40px;
  border: 1px solid var(--accent-50); border-radius: 50%;
  pointer-events: none; z-index: 9998;
  transform: translate(-50%,-50%);
  opacity: 0;
  transition: width 0.1s var(--easing), height 0.1s var(--easing), opacity 0.5s ease;
}

/* Shown once the mouse has entered the viewport */
.cursor.visible { opacity: 1; }
.cursor-follower.visible { opacity: 1; }

/* Hovering a link or button: dot shrinks, ring expands */
.cursor.active { width: 6px; height: 6px; }
.cursor-follower.active { width: 60px; height: 60px; border-color: var(--accent2); }

/* Hide cursor near screen edges to avoid clipping artefacts */
.cursor.edge-hidden,
.cursor-follower.edge-hidden { opacity: 0 !important; }

/* Individual ripple rings spawned on click (managed as a DOM pool in JS) */
.click-ripple {
  position: fixed;
  pointer-events: none;
  z-index: 9997;
  border-radius: 50%;
  width: 0; height: 0;
}

/* Touch devices: remove custom cursor entirely and restore the native pointer */
@media (hover: none) and (pointer: coarse) {
  .cursor, .cursor-follower, .click-ripple { display: none !important; }
  body { cursor: auto; }
}

/* ────────────────────────────────────────────────────────────────────────────────
   LOADER
   Full-screen cover shown while the first slide image and fonts are loading.
   Fades out and is removed from the accessibility tree once the app is ready.
──────────────────────────────────────────────────────────────────────────────── */
.loader {
  position: fixed; inset: 0; z-index: 1000;
  background: var(--dark);
  display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 20px;
}
.loader-bar-wrap {
  width: 70%; max-width: 500px; height: 1px;
  background: var(--text-20); overflow: hidden; position: relative;
}
/* Shimmer sweep that runs over the fill bar */
.loader-bar-wrap::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent 0%, var(--text-50) 50%, transparent 100%);
  transform: translateX(-100%);
  animation: loaderShimmer 1.6s ease-in-out infinite;
}
@keyframes loaderShimmer {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(200%); }
}
.loader-bar { height: 100%; width: 0%; background: linear-gradient(90deg, var(--accent) 0%, var(--text) 100%); } /* width animated by JS */
.loader-num { font-size: 11px; letter-spacing: 0.25em; color: var(--text-50); }
.loader-label { font-family: 'Bebas Neue', sans-serif; font-size: clamp(32px,5vw,60px); letter-spacing: 0.15em; color: var(--accent); }

/* ─────────────────────────────────────────────────────────────────────────────
   SLIDER
   Full-screen fixed container. Each .slide is stacked absolutely on top of
   each other; only the .active one has pointer-events and is visible.
───────────────────────────────────────────────────────────────────────────── */
.slider { position: fixed; inset: 0; z-index: 1; overflow: hidden; touch-action: pan-y; }
.slide {
  position: absolute; inset: 0;
  display: flex; align-items: center; overflow: hidden;
  pointer-events: none; visibility: hidden; /* inactive slides are fully inert */
}
.slide.active { pointer-events: all; visibility: visible; }

/* ────────────────────────────────────────────────────────────────────────────────
   SLIDE BACKGROUND
   The background image sits in a slightly oversized container (inset: -5%) so
   GSAP can scale/translate it for parallax without exposing blank edges.
   Two pseudo-elements layer over the image:
     ::after — a directional dark gradient to ensure text contrast on the left
     ::before — a subtle dot-grid grain texture for visual depth
──────────────────────────────────────────────────────────────────────────────── */
.slide-bg { position: absolute; inset: -5%; overflow: hidden; }
.slide-bg-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
  display: block;
}
.slide-bg::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(110deg, var(--dark-70) 30%, var(--dark-30) 100%);
}
.slide-bg::before {
  content: ''; position: absolute; inset: 0; opacity: 0.035; z-index: 2;
  /* Fine 3×3 noise grain — subtler and more cinematic than the 4×4 dot grid */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='3' height='3'%3E%3Ccircle cx='0.75' cy='0.75' r='0.6' fill='white'/%3E%3Ccircle cx='2.25' cy='2.25' r='0.45' fill='white' opacity='0.5'/%3E%3C/svg%3E");
  background-repeat: repeat; background-size: 3px 3px;
}

/* ── Slide text content wrapper ── */
.slide-content { position: relative; z-index: 10; padding: 0 8vw; max-width: 900px; }

/* ────────────────────────────────────────────────────────────────────────────────
   SLIDE TAG  (e.g. "Architecture / 2026")
   The short category label above the headline. The ::before pseudo is the
   decorative dash. The blinking cursor animation is driven by the .typing class.
──────────────────────────────────────────────────────────────────────────────── */
.slide-tag {
  font-size: 10px; letter-spacing: 0.35em; text-transform: uppercase;
  color: var(--accent); display: flex; align-items: center; gap: 16px;
  margin-bottom: 35px; transition: color 0.8s ease;
}
.slide-tag span { display: block; }

/* Blinking underscore cursor appended during the typewriter animation */
.slide-tag span::after {
  content: '_';
  display: inline;
  margin-left: 1px;
  opacity: 0;
}
.slide-tag span.typing::after { opacity: 1; animation: blink 0.6s step-end infinite; }
@keyframes blink {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0; }
}

/* Short horizontal rule before the tag text — animated: expands + shimmer on slide-enter */
.slide-tag::before {
  content: '';
  display: block;
  width: 40px; height: 1px;
  background: linear-gradient(90deg, var(--accent2), var(--accent));
  flex-shrink: 0;
  transition: background-color 0.8s ease, width 0.6s var(--easing), opacity 0.6s ease;
  position: relative;
  overflow: hidden;
}

/* Shimmer sweep over the tag line — plays once per slide transition */
.slide-tag::before {
  /* layered: base color + shimmer via mask animation */
  background-image: linear-gradient(
    90deg,
    var(--accent2) 0%,
    var(--accent)  60%,
    var(--accent2) 100%
  );
  background-size: 200% 100%;
  animation: tagLineShimmer 3s ease infinite;
}

@keyframes tagLineShimmer {
  0%   { background-position: 100% 0; opacity: 0.7; }
  40%  { background-position: -20% 0; opacity: 1;   }
  100% { background-position: -20% 0; opacity: 0.7; }
}

/* Expand-in on .active slide for the tag line */
.slide.active .slide-tag::before {
  width: 40px;
  animation: tagLineExpand 0.7s var(--easing) forwards, tagLineShimmer 3s ease 0.7s infinite;
}

@keyframes tagLineExpand {
  from { width: 0px; opacity: 0; }
  to   { width: 40px; opacity: 1; }
}

/* Headline lines clip-reveal upward — overflow: hidden on the wrapper is key */
.slide-headline-wrap { overflow: hidden; }
.slide-headline {
  font-family: 'Bebas Neue', sans-serif; font-size: clamp(50px, 10vw, 100px);
  line-height: 0.9; letter-spacing: 0.02em; color: var(--text);
  display: block;
}
.slide-sub {
  font-family: 'Cormorant Garamond', serif; font-style: italic;
  font-size: clamp(18.5px, 3vw, 22px); color: var(--text-50);
  margin-top: 24px; line-height: 1.6; max-width: 480px;
}
.slide-sub span { display: block; overflow: hidden; padding-bottom: 0.15em; }
/* CTA row — primary button + secondary text link */
.slide-cta { margin-top: 48px; display: flex; align-items: center; gap: 32px; overflow: hidden; }

/* Primary CTA button — accent fill with hover wipe effect */
.cta-btn {
  display: inline-flex; align-items: center; gap: 12px;
  font-size: 11px; letter-spacing: 0.25em; text-transform: uppercase;
  color: var(--dark); background: var(--accent);
  padding: 14px 28px;
  position: relative; overflow: hidden;
  transition: color 0.3s, background-color 0.8s ease, box-shadow 0.4s ease;
  box-shadow: 0 0 0 0 var(--accent-25);
}
.cta-btn:hover {
  box-shadow: 0 0 400px 4px var(--accent-50), 0 4px 300px -4px var(--accent-75);
}
.cta-btn::before {
  content: ''; position: absolute; inset: 0; background: var(--accent2);
  transform: translateX(-101%); transition: transform 0.4s var(--easing); /* slides in from left */
}
.cta-btn:hover::before { transform: translateX(0); }
.cta-btn span { position: relative; z-index: 1; } /* sits above the ::before overlay */

/* Secondary link with diagonal arrow suffix + premium underline sweep */
.cta-link {
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-50);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  position: relative;
  padding-bottom: 2px;
  /* Premium underline sweep (replaces pseudo underline) */
  background-image: linear-gradient(90deg, var(--accent), var(--accent2));
  background-repeat: no-repeat;
  background-position: 0% 100%;
  background-size: 0% 1px;
  transition: color 0.4s var(--easing), letter-spacing 0.4s var(--easing), background-size 0.45s var(--easing);
}
/* Hover state */
.cta-link:hover {
  color: var(--text);
  letter-spacing: 0.25em;
  background-size: 100% 1px;
}
/* Arrow (preferred: separate span) */
.cta-link .cta-arrow {
  display: inline-block;
  font-size: 14px;
  opacity: 0.6;
  transition: transform 0.35s var(--easing), opacity 0.35s ease;
}
.cta-link:hover .cta-arrow {
  transform: translate(3px, -3px);
  opacity: 1;
}
/* Fallback arrow (no span) */
.cta-link:not(:has(.cta-arrow))::after {
  content: '↗';
  font-size: 14px;
  opacity: 0.6;
  transition: transform 0.35s var(--easing), opacity 0.35s ease, color 0.4s ease;
}
.cta-link:not(:has(.cta-arrow)):hover::after {
  transform: translate(3px, -3px);
  opacity: 1;
  color: var(--accent);
}

/* Slide number / countdown ring — bottom-right of each slide */
.slide-num {
  position: absolute; right: 8vw; bottom: 15vh;
  z-index: 1; pointer-events: none; user-select: none;
  display: flex; align-items: center; justify-content: center;
}

/* ─────────────────────────────────────────────────────────────────────────────
   COUNTDOWN RING
   SVG ring injected by JS into each .countdown-ring. The progress arc
   (ring-progress) has its strokeDashoffset driven by requestAnimationFrame
   to visualise time remaining until the next autoplay advance.
   .is-playing brightens the stroke and glow when autoplay is active.
───────────────────────────────────────────────────────────────────────────── */
.countdown-ring {
  position: relative;
  width: clamp(120px, 18vw, 180px);
  height: clamp(120px, 18vw, 180px);
  display: flex; align-items: center; justify-content: center;
}
.countdown-ring svg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  transform: rotate(-90deg); /* start arc at 12 o'clock */
  overflow: visible;
}
.ring-track {
  fill: none;
  stroke: var(--accent-20); /* faint background circle */
  stroke-width: 1;
}
.ring-progress {
  fill: none;
  stroke: var(--accent-25); /* dimmed when paused */
  stroke-width: 1.5;
  stroke-linecap: round;
  transition: stroke 0.5s ease, filter 0.5s ease;
  filter: drop-shadow(0 0 2px var(--accent-15));
}
.ring-progress.is-playing {
  stroke: var(--accent-75); /* brighter when counting down */
  filter: drop-shadow(0 0 6px var(--accent-50)) drop-shadow(0 0 12px var(--accent-25));
}
.ring-tick {
  fill: none;
  stroke: var(--accent-35); /* small tick marks at N/E/S/W */
  stroke-width: 1.5;
  stroke-linecap: round;
}
/* Slide number label centred inside the ring */
.countdown-label {
  position: relative; z-index: 1;
  font-family: 'Bebas Neue', sans-serif;
  font-size: clamp(50px, 8vw, 80px);
  line-height: 1;
  padding-top: 5px;
  color: var(--accent-20); /* dim when paused */
  letter-spacing: -0.02em;
  transition: color 0.5s ease;
}
.countdown-ring.is-playing .countdown-label {
  color: var(--accent-50); /* brighten during autoplay */
  text-shadow: 0 0 40px var(--accent-20);
}

/* ── Navigation bar (fixed, top of viewport) ── */
.nav {
  position: fixed; top: 0; left: 0; right: 0; padding: 32px 8vw;
  display: flex; align-items: center; justify-content: space-between; z-index: 450;
}
.nav-logo { font-family: 'Bebas Neue', sans-serif; font-size: 25px; letter-spacing: 0.2em; color: var(--accent); transition: color 0.6s ease; }
.nav-links { display: flex; gap: 40px; list-style: none; }
.nav-links a { font-size: 10px; letter-spacing: 0.25em; text-transform: uppercase; color: var(--text-50); transition: color 0.3s; }
.nav-links a:hover { color: var(--text); }

/* ─────────────────────────────────────────────────────────────────────────────
   DOT NAVIGATION (right-centre of viewport)
   One small dot per slide. The active dot scales up and gains a ring border.
   The ::before pseudo acts as an expanded hit area for easier clicking.
───────────────────────────────────────────────────────────────────────────── */
.controls {
  position: fixed; right: 5vw; top: 50%; transform: translateY(-50%);
  z-index: 100; display: flex; flex-direction: column; gap: 12px; align-items: center;
}
.dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--text-30); cursor: pointer;
  border: none; padding: 0;
  transition: background 0.6s ease, transform 0.3s; position: relative;
}
.dot::before {
  content: ''; position: absolute; inset: -6px; border-radius: 50%;
  border: 1px solid transparent; transition: border-color 0.6s ease, inset 0.3s; /* ring tightens on active */
}
.dot.active {
  background: var(--accent);
  transform: scale(1.3);
  box-shadow: 0 0 8px 2px var(--accent-35);
}
.dot.active::before { inset: -5px; border-color: var(--accent); }

/* ── Focus styles — show outline only for keyboard navigation, not mouse clicks ── */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.dot:focus-visible {
  outline-offset: 5px;
}

.arrow-btn:focus-visible,
.autoplay-btn:focus-visible {
  outline-offset: -2px;
}

/* ─────────────────────────────────────────────────────────────────────────────
   ARROW BUTTONS  (prev / next, bottom-right)
   A horizontal fill wipe on hover is achieved with a ::before pseudo that
   scaleX from 0 → 1 on the left axis.
───────────────────────────────────────────────────────────────────────────── */
.arrows {
  position: fixed; bottom: 8vh; right: 8vw;
  display: flex; gap: 12px; z-index: 100;
}
.arrow-btn {
  width: 52px; height: 52px;
  border: 1px solid var(--text-20); background: transparent; color: var(--text);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: color 0.3s, border-color 0.3s, transform 0.2s;
  position: relative; overflow: hidden;
}
.arrow-btn::before {
  content: ''; position: absolute; inset: 0; background: var(--accent);
  transform: scaleX(0); transform-origin: left; transition: transform 0.35s var(--easing);
}
.arrow-btn:hover::before { transform: scaleX(1); }
.arrow-btn:hover { color: var(--dark); border-color: var(--accent); }
.arrow-btn svg { position: relative; z-index: 1; } /* keep icon above fill overlay */
.arrow-btn:active { transform: scale(0.95); }

/* ── Autoplay toggle button — sits between prev/next arrows ── */
.autoplay-btn {
  width: 52px; height: 52px;
  border: 1px solid var(--text-20); background: transparent; color: var(--text-50);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: color 0.3s ease, border-color 0.4s ease, background 0.3s ease, box-shadow 0.4s ease;
  overflow: hidden; flex-shrink: 0;
  position: relative;
}
/* Shimmer diagonal sweep on hover */
.autoplay-btn::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(115deg, transparent 30%, var(--accent-15) 50%, transparent 70%);
  transform: translateX(-150%);
  transition: transform 0.55s var(--easing);
}
.autoplay-btn:hover::before { transform: translateX(150%); }
.autoplay-btn:hover {
  background: var(--accent-10);
  border-color: var(--accent-25);
  color: var(--text);
  box-shadow: inset 0 0 20px var(--accent-5), 0 0 16px var(--accent-10);
}
.autoplay-btn:active { opacity: 0.8; transform: scale(0.95); }
/* Playing state: glowing accent border + subtle pulse ring */
.autoplay-btn.is-playing {
  border-color: var(--accent-75);
  color: var(--accent);
  box-shadow: 0 0 14px 2px var(--accent-25), inset 0 0 12px var(--accent-10);
  animation: autoplayPulse 2.5s ease-in-out infinite;
}
@keyframes autoplayPulse {
  0%, 100% { box-shadow: 0 0 10px 1px var(--accent-25), inset 0 0 10px var(--accent-10); }
  50%       { box-shadow: 0 0 22px 4px var(--accent-35), inset 0 0 18px var(--accent-15); }
}

/* Toggle play/pause icons — only one is shown at a time */
.icon-pause { display: none; }
.autoplay-btn.is-playing .icon-play  { display: none; }
.autoplay-btn.is-playing .icon-pause { display: block; }

/* ───────────────────────────────────────────────────────────────────────────────────
   HAMBURGER (mobile only — hidden on desktop via media query below)
   Three lines animate into an X via GSAP transforms in openMenu() / closeMenu().
─────────────────────────────────────────────────────────────────────────────────── */
.hamburger {
  display: none;
  width: 44px; height: 44px; cursor: pointer;
  background: transparent; border: none;
  position: relative; z-index: 500;
  flex-shrink: 0;
}
.ham-line {
  display: block; width: 24px; height: 1.5px;
  background: var(--text);
  position: absolute;
  left: 50%; transform: translateX(-50%);
}
.ham-line:nth-child(1) { top: 14px; }
.ham-line:nth-child(2) { top: 21px; }
.ham-line:nth-child(3) { top: 28px; }

/* ──────────────────────────────────────────────────────────────────────────────────────
   MOBILE MENU OVERLAY
   Full-screen overlay that covers the slider. Hidden by default (pointer-events:
   none, visibility: hidden). The dark background (.mobile-menu-bg) scaleY-animates
   from the top; nav links (.mob-link) translate up from below their clip container.
────────────────────────────────────────────────────────────────────────────────────── */
.mobile-menu {
  position: fixed; inset: 0; z-index: 400;
  display: flex; flex-direction: column; justify-content: center; align-items: center;
  pointer-events: none; visibility: hidden;
}
/* Applied by JS when the menu opens — overrides the hidden defaults above */
.mobile-menu.is-open {
  visibility: visible;
  pointer-events: auto;
}
.mobile-menu-bg {
  position: absolute; inset: 0; background: var(--dark);
  transform: scaleY(0); transform-origin: top; /* GSAP animates scaleY 0→1 on open */
}
.mobile-menu-links {
  position: relative; z-index: 1;
  list-style: none; display: flex; flex-direction: column;
  align-items: center; gap: 4px; text-align: center;
}
.mobile-menu-links li { overflow: hidden; } /* clips the translateY entrance of each link */
.mobile-menu-links a {
  font-family: 'Bebas Neue', sans-serif;
  font-size: clamp(44px, 13vw, 80px);
  letter-spacing: 0.06em;
  color: var(--text);
  line-height: 1.1;
  transform: translateY(110%); /* starts off-screen below clip boundary */
  display: block; transition: color 0.3s;
}
.mobile-menu-links a:hover { color: var(--accent); }
.mobile-menu-footer {
  position: absolute; bottom: 48px; left: 0; right: 0;
  display: flex; justify-content: space-between; align-items: flex-end;
  padding: 0 8vw; opacity: 0; /* fades in after links animate */
}
.mobile-menu-footer-label { font-size: 9px; letter-spacing: 0.35em; text-transform: uppercase; color: var(--text-50); }
.mobile-menu-footer-num {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 22vw; line-height: 1; color: var(--accent-5); /* giant watermark text */
  letter-spacing: -0.02em; user-select: none;
}

/* Thin bar at the very bottom — scaleX from 0→1 as slides advance */
.progress-line {
  position: fixed; bottom: 0; left: 0; width: 100%; height: 2px;
  background: linear-gradient(90deg,
    transparent 0%,
    var(--accent-25) 8%,
    var(--accent-75) 35%,
    var(--accent) 50%,
    var(--accent-75) 65%,
    var(--accent-25) 92%,
    transparent 100%
  );
  background-size: 200% 100%;
  box-shadow:
    0 0 6px 1px var(--accent-50),
    0 0 18px 2px var(--accent-25),
    0 -1px 40px 0 var(--accent-15);
  z-index: 100;
  transform-origin: left; transform: scaleX(0);
  animation: progressShimmer 2.5s ease-in-out infinite, progressGlow 4s ease-in-out infinite;
  transition: height 0.3s ease, box-shadow 0.5s ease;
}

@keyframes progressShimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

@keyframes progressGlow {
  0%, 100% {
    box-shadow:
      0 0 6px 1px var(--accent-50),
      0 0 18px 2px var(--accent-25),
      0 -1px 40px 0 var(--accent-15);
  }
  50% {
    box-shadow:
      0 0 10px 2px var(--accent-75),
      0 0 30px 4px var(--accent-35),
      0 -2px 60px 0 var(--accent-20);
  }
}

/* Slide counter — bottom-left (e.g. "01 — 05"); decorative, hidden from screen readers */
.slide-counter {
  position: fixed; bottom: 8vh; left: 8vw;
  z-index: 100; font-size: 11px; letter-spacing: 0.2em; color: var(--text-50);
}
.counter-current {
  font-size: 24px; font-family: 'Bebas Neue', sans-serif;
  color: var(--accent); display: inline; letter-spacing: 0.1em;
}

/* ── Scroll hint — centre-bottom, three animated chevrons pointing down ── */
.scroll-hint {
  position: fixed; bottom: 8vh; left: 50%; transform: translateX(-50%);
  z-index: 100; display: flex; flex-direction: column; align-items: center; gap: 12px;
}
.scroll-hint-text {
  font-size: 10px; letter-spacing: 1.5em; text-transform: uppercase;
  color: var(--text-50);
  margin-left: 14.5px; /* compensates for letter-spacing on last char */
}
.scroll-hint-chevrons {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}
/* Each chevron pulses opacity in sequence, creating a cascading downward flow */
.chevron {
  width: 14px;
  height: 8px;
  opacity: 0;
  animation: chevronFlow 2.2s var(--easing) infinite;
}
.chevron:nth-child(1) { animation-delay: 0s; }
.chevron:nth-child(2) { animation-delay: 0.2s; }
.chevron:nth-child(3) { animation-delay: 0.4s; }
@keyframes chevronFlow {
  0%   { opacity: 0; }
  20%  { opacity: 0.25; }
  50%  { opacity: 1; }
  80%  { opacity: 0.25; }
  100% { opacity: 0; }
}

/* ─────────────────────────────────────────────────────────────────────────────
   TRANSITION OVERLAY
   Five vertical strips that scaleY to cover the screen, then un-cover to
   reveal the incoming slide — creating the curtain-wipe between slides.
───────────────────────────────────────────────────────────────────────────── */
.transition-overlay { position: fixed; inset: 0; z-index: 200; pointer-events: none; display: flex; }
.t-strip { flex: 1; background: var(--dark); transform: scaleY(0); transform-origin: bottom; }

/* ──────────────────────────────────────────────────────────────────────────────────
   CONTROLS POPUP  (keyboard shortcut reference)
   Appears automatically ~3.5s after page load for pointer users.
   Uses clip-path animation for the reveal (clipped from bottom → fully visible).
   The backdrop-filter frosted-glass effect requires the CSS prefix for Safari.
────────────────────────────────────────────────────────────────────────────────── */
.controls-popup {
  position: fixed; bottom: 50px; left: 50%; transform: translateX(-50%);
  z-index: 300;
  width: 470px;
  background: var(--dark-90);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px); /* Safari */
  border: 1px solid var(--accent-10);
  padding: 28px 32px 24px;
  opacity: 0;
  pointer-events: none;
  clip-path: inset(0% 0% 100% 0%); /* initially fully clipped (invisible) */
}
.controls-popup.visible { pointer-events: all; }
.popup-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 20px;
}
.popup-title {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 13px; letter-spacing: 0.3em; color: var(--accent);
}
.popup-close {
  background: none; border: none; cursor: pointer;
  color: var(--text-50); padding: 4px;
  transition: color 0.25s, transform 0.25s;
  display: flex; align-items: center; justify-content: center;
}
.popup-close:hover { color: var(--text); transform: rotate(90deg); }
.popup-close svg { display: block; }
.popup-divider { height: 1px; background: var(--accent-10); margin-bottom: 18px; }
.popup-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 24px; }
.popup-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.popup-key { display: inline-flex; align-items: center; gap: 4px; flex-shrink: 0; }
.key {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 26px; height: 22px; padding: 0 6px;
  border: 1px solid var(--accent-25);
  background: var(--accent-5);
  font-family: 'DM Mono', monospace;
  font-size: 9px; letter-spacing: 0.05em;
  color: var(--accent); border-radius: 3px; white-space: nowrap;
}
.popup-desc {
  font-size: 9px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--text-50); text-align: right;
}
.popup-footer {
  margin-top: 18px; padding-top: 14px;
  border-top: 1px solid var(--accent-10);
  font-size: 8px; letter-spacing: 0.25em; text-transform: uppercase;
  color: var(--text-20); text-align: center;
}
.popup-footer span {
  color: var(--accent);
}

/* ── Transition toast ── */
.transition-toast {
  position: fixed; top: 88px; right: 8vw;
  z-index: 500;
  background: var(--dark-90);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border: 1px solid var(--accent-10);
  padding: 14px 20px;
  display: flex; align-items: center; gap: 12px;
  pointer-events: none;
  opacity: 0;
  clip-path: inset(0% 0% 100% 0%);
}
.transition-toast-icon {
  flex-shrink: 0;
  color: var(--accent2);
  display: flex; align-items: center;
}
.transition-toast-body {
  display: flex; flex-direction: column; gap: 3px;
}
.transition-toast-title {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 12px; letter-spacing: 0.3em;
  color: var(--accent);
}
.transition-toast-msg {
  font-size: 8.5px; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--text-50);
}

/* ── Update-available toast ──
   Appears when a new Service Worker is waiting (see slider.js SW registration block).
   Positioned below the transition-toast (top: 88px → 160px) so they never overlap.
   Pointer-events: all (unlike transition-toast) because it contains a Reload button. */
.update-toast {
  position: fixed; top: 70px; left: 50%; transform: translateX(-50%);
  z-index: 500;
  background: var(--dark-90);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border: 1px solid var(--accent-10);
  padding: 14px 16px 14px 20px;
  display: flex; align-items: center; gap: 12px;
  pointer-events: all;
  opacity: 0;
  clip-path: inset(0% 0% 100% 0%);
}
.update-toast-icon {
  flex-shrink: 0;
  color: var(--accent2);
  display: flex; align-items: center;
}
.update-toast-body {
  display: flex; flex-direction: column; gap: 3px;
  flex: 1;
}
.update-toast-title {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 12px; letter-spacing: 0.3em;
  color: var(--accent);
}
.update-toast-msg {
  font-size: 8.5px; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--text-50);
}
.update-toast-btn {
  flex-shrink: 0;
  background: none;
  border: 1px solid var(--accent-25);
  color: var(--accent);
  font-family: 'Bebas Neue', sans-serif;
  font-size: 11px; letter-spacing: 0.25em;
  padding: 5px 12px;
  cursor: pointer;
  transition: background 0.2s, color 0.2s, border-color 0.2s;
}
.update-toast-btn:hover {
  background: var(--accent);
  color: var(--dark);
  border-color: var(--accent);
}
.update-toast-btn:active { transform: scale(0.95); }

/* ── Orientation overlay ──
   Matches the frosted-glass visual language of .controls-popup and .transition-toast.
   Hidden by default; the @media rule below activates it on coarse-pointer landscape devices only. ── */
.orientation-overlay {
  display: none;
  position: fixed; inset: 0; z-index: 900;
  background: var(--dark);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  flex-direction: column; align-items: center; justify-content: center; gap: 28px;
  pointer-events: all;
}
.orientation-overlay-icon {
  color: var(--accent2);
  animation: rotateHint 2.5s var(--easing) infinite;
}
@keyframes rotateHint {
  0%, 60%  { transform: rotate(90deg);  opacity: 1;   }
  80%      { transform: rotate(0deg);   opacity: 0.6; }
  100%     { transform: rotate(0deg);   opacity: 1;   }
}
.orientation-overlay-divider {
  width: 370px; height: 1px; background: var(--accent-15);
}
.orientation-overlay-title {
  font-family: 'Bebas Neue', sans-serif;
  font-size: clamp(22px, 5vw, 32px); letter-spacing: 0.3em;
  color: var(--accent); text-align: center;
}
.orientation-overlay-msg {
  font-size: 9px; letter-spacing: 0.3em; text-transform: uppercase;
  color: var(--text-50); text-align: center;
}
.orientation-overlay-hint {
  font-size: 8px; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--text-20); text-align: center;
  margin-top: -12px; /* tighten gap between the two message lines */
}
.orientation-overlay-hint strong { color: var(--accent); }

@media screen and (max-width: 1024px) and (pointer: coarse) and (orientation: landscape) {
  .orientation-overlay { display: flex; }
}

/* ── Responsive — mobile breakpoint (≤768px) ── sync value with --mobile-breakpoint in :root */
@media (max-width: 768px) {
  .nav-links { display: none; }
  .hamburger { display: flex; }
  .slide-content { padding: 0 5vw; transform: translateY(-50px); }
  .slide-tag { margin-bottom: 30px; }
  .slide-sub { max-width: 80vw; margin-top: 14px; line-height: 1.4; }
  .slide-cta { margin-top: 24px; }
  .controls { right: 20px; }
  .arrows { right: 6vw; }
  .slide-num { font-size: unset; }
  .scroll-hint { display: none; }
  .progress-line { height: 2px; }
  /* scaling down message boxes */
  .controls-popup { width: min(380px, 90vw); min-width: 270px; padding: 18px 20px 16px; bottom: 36px; }
  .popup-header { margin-bottom: 14px; }
  .popup-divider { margin-bottom: 12px; }
  .popup-grid { gap: 8px 16px; }
  .popup-title { font-size: 11px; letter-spacing: 0.22em; }
  .popup-desc { font-size: 8px; letter-spacing: 0.12em; }
  .key { min-width: 22px; height: 19px; font-size: 8px; padding: 0 4px; }
  .popup-footer { margin-top: 12px; padding-top: 10px; font-size: 7px; letter-spacing: 0.18em; }
  .transition-toast { right: 6vw; top: 74px; padding: 12px 16px; }
  .update-toast { left: auto; right: -70px; top: 80px; padding: 12px 14px 12px 16px; gap: 10px; }
  .update-toast-title { font-size: 11px; letter-spacing: 0.22em; }
  .update-toast-msg   { font-size: 8px;  letter-spacing: 0.12em; }
  .update-toast-btn   { font-size: 10px; letter-spacing: 0.2em; padding: 4px 10px; }
}

/* ────────────────────────────────────────────────────────────────────────────────
   REDUCED MOTION
   Collapses all transitions/animations to near-zero for users who prefer it.
   Also hides the SVG countdown ring (purely decorative, animation-heavy).
──────────────────────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
  .ring-progress { display: none; }
  .ring-track    { display: none; }
  .ring-tick     { display: none; }
}