/* ===== Tokens ===== */
:root {
  --bg: #0b0b0d;
  --surface: #16161a;
  --text: #ededef;
  --muted: #8b8b93;
  --silver-1: #c8ccd4;
  --silver-2: #e8eaed;
  --border-glass: rgba(255, 255, 255, 0.12);
  --border-glass-strong: rgba(255, 255, 255, 0.2);

  --font-display: 'Manrope', sans-serif;
  --font-body: 'Manrope', sans-serif;
  --font-mono: 'JetBrains Mono', monospace;

  --radius-panel: 4px;
  --radius-pill: 999px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  line-height: 1.55;
  overflow-x: hidden;
}
/* Belt-and-suspenders: while the phone-mockup feed is active, the page
   itself can't scroll at all (script.js toggles this on body), so a wheel
   or touch event that somehow reaches outside the phone still can't drag
   the whole page back up into the SAGA intro. */
body.feed-locked {
  overflow: hidden;
  height: 100dvh;
}

a { color: inherit; text-decoration: none; }
button { font-family: inherit; }
img { max-width: 100%; display: block; }

section { position: relative; padding: 7rem 6vw; }

/* ===== Grain (fixed, non-scrolling) ===== */
.grain {
  position: fixed;
  inset: 0;
  z-index: 999;
  pointer-events: none;
  opacity: 0.04;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ===== Glass utility ===== */
.glass {
  background: linear-gradient(135deg, rgba(255,255,255,0.06), rgba(255,255,255,0.02)), rgba(22,22,26,0.55);
  backdrop-filter: blur(22px) saturate(160%);
  -webkit-backdrop-filter: blur(22px) saturate(160%);
  border: 1px solid var(--border-glass);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}
@media (prefers-reduced-transparency: reduce) {
  .glass {
    background: var(--surface);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

/* ===== Header ===== */
.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 72px;
  padding: 0 6vw;
  background: transparent;
  transition: opacity 0.5s ease;
}
body.intro-active .site-header {
  opacity: 0;
  pointer-events: none;
}
.logo {
  /* Exact same font as the intro's "SAGA" (see script.js FONT). */
  font-family: Arial, sans-serif;
  font-weight: 700;
  font-size: 1.1rem;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.logo span { color: var(--muted); }

/* Icon-only social row, replacing the old text nav entirely. */
.social-nav {
  display: flex;
  align-items: center;
  gap: 1.1rem;
}
.social-nav a {
  display: flex;
  color: var(--text);
  opacity: 0.75;
  transition: opacity 0.2s ease;
}
.social-nav a:hover { opacity: 1; }
.social-nav i { font-size: 19px; }
/* jsDelivr serves these brand logos as solid black; invert so they read as
   light against the dark header. */
.brand-icon { filter: invert(1); }

/* ===== Fixed background video ===== */
/* #bgVideo (local btss.mp4) plays from load. The moment a menu item is
   clicked, script.js hides this and reveals #bgVideoWrap (Vimeo) instead. */
.bg-video {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: -1;
}

/* Vimeo Player, only shown after the first menu click. Vimeo's native
   controls stay off (controls:false) in favor of the tiny custom bar
   below. Iframes don't support object-fit the way a <video> does, so this
   is the standard "oversize a 16:9 iframe and clip it" technique for
   full-bleed cover. */
.bg-video-wrap {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  background: var(--bg);
}
.bg-video-wrap[hidden] { display: none; }
.bg-video-wrap iframe {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100vw;
  height: 56.25vw; /* 16 / 9 */
  min-height: 100vh;
  min-width: 177.78vh; /* 16 / 9 */
  transform: translate(-50%, -50%);
  border: 0;
  pointer-events: none;
}

/* Phone mockup for vertical (9:16) content - CSS-only frame, centered on
   screen, dark bezel + notch. .phone-screen is forced to an exact 9:16 box
   (not the phone body's real ~9:19.5 ratio), so a 9:16 export fills it at
   100%/100% with zero cropping and zero letterboxing - "completo a lo
   ancho". */
.phone-mockup {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.phone-mockup > * { pointer-events: auto; }
.phone-mockup[hidden] { display: none; }
.phone-frame {
  position: relative;
  width: min(320px, 78vh, 62vw);
  aspect-ratio: 9 / 19.5;
  background: #050506;
  border-radius: 2.6rem;
  border: 2px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 80px rgba(0,0,0,0.55), inset 0 0 0 6px #0b0b0d;
  overflow: hidden;
  transition: width 0.3s ease, border-radius 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
}
@media (max-width: 760px) {
  /* Desktop's 320px/62vw cap keeps the mockup small and object-like on a
     big screen - on a phone that same cap leaves a lot of dead black
     space on either side. Let it grow close to full width instead, so the
     video itself reads as the main thing on screen. */
  .phone-frame { width: min(94vw, 80vh); }
}
.phone-notch {
  position: absolute;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
  width: 34%;
  height: 18px;
  background: #050506;
  border-radius: 999px;
  z-index: 2;
  transition: opacity 0.2s ease;
}
.phone-screen {
  /* width + aspect-ratio (not left/right insets) is the reliable
     combination for getting a real, non-zero computed height here -
     left/right-derived width combined with aspect-ratio was leaving this
     box (and everything inside it) at ~0 height in some cases, so the
     feed was "scrolling" inside an invisible box. */
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: calc(100% - 12px);
  aspect-ratio: 9 / 16;
  border-radius: 2.2rem;
  overflow: hidden;
  background: #000;
}

/* TikTok-style feed: one full-screen slide per clip, native scroll +
   snap to move between them (script.js: setupVerticalFeed watches which
   slide is in view to play/pause and update the dots). */
.vertical-feed {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
  scrollbar-width: none;
}
.vertical-feed::-webkit-scrollbar { display: none; }
.vertical-slide {
  position: relative;
  width: 100%;
  height: 100%;
  scroll-snap-align: start;
  background: #050506;
  overflow: hidden;
}
.vertical-slide-player {
  position: absolute;
  inset: 0;
}
.vertical-slide-player iframe,
.vertical-slide-player video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border: 0;
  pointer-events: none;
}
.vertical-tag {
  position: absolute;
  top: 1rem;
  left: 1rem;
  z-index: 2;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  padding: 0.35rem 0.8rem;
  border-radius: var(--radius-pill);
  background: rgba(11,11,13,0.55);
  color: var(--silver-2);
}
.vertical-slide-info {
  position: absolute;
  left: 1rem;
  right: 1rem;
  bottom: 1.1rem;
  z-index: 2;
  text-shadow: 0 2px 10px rgba(0,0,0,0.7);
}
.vertical-slide-info h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  margin-bottom: 0.3rem;
}
.vertical-slide-info p {
  font-size: 0.8rem;
  color: var(--silver-2);
  line-height: 1.4;
}

.vertical-dots {
  position: absolute;
  right: 0.6rem;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.vertical-dots .dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: rgba(255,255,255,0.35);
  transition: background 0.2s ease, height 0.2s ease;
}
.vertical-dots .dot.active {
  height: 16px;
  border-radius: 3px;
  background: var(--silver-2);
}

/* Explicit prev/next: native scroll-snap swipe still works too, but
   hovering a small inset box to scroll it isn't obvious on desktop. */
.vertical-nav-btn {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1px solid var(--border-glass-strong);
  background: rgba(11,11,13,0.5);
  color: var(--silver-2);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color 0.2s ease, opacity 0.2s ease;
}
.vertical-nav-btn:hover { border-color: var(--silver-1); }
.vertical-nav-btn i { font-size: 15px; }
.vertical-nav-up { top: 0.6rem; }
.vertical-nav-down { bottom: 0.6rem; }
.vertical-nav-btn[disabled] { opacity: 0.25; pointer-events: none; }

/* "Ver en horizontal": drops the phone bezel/notch and lets the vertical
   video grow taller (still pillarboxed, since the footage is vertical) -
   the closest honest equivalent of "viewing it landscape" for
   portrait-shaped footage, without distorting or literally rotating it. */
.phone-mockup.expanded .phone-frame {
  width: min(66vh, 92vw);
  border-radius: 0;
  border-color: transparent;
  box-shadow: none;
}
.phone-mockup.expanded .phone-notch { opacity: 0; }
.phone-mockup.expanded .phone-screen {
  width: 100%;
  border-radius: 0;
}

.phone-expand-btn {
  position: absolute;
  top: 1.4rem;
  right: 1.4rem;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--border-glass-strong);
  background: rgba(11,11,13,0.4);
  color: var(--silver-2);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 3;
}
.phone-expand-btn:hover { border-color: var(--silver-1); }
.phone-expand-btn i { font-size: 16px; }
@media (max-width: 760px) {
  /* On mobile, the phone bezel's own top-right corner sits too close to
     the header (and used to actually overlap it, back when this button
     was a sibling of .phone-frame instead of a child - position:absolute
     was resolving against the full-viewport .phone-mockup wrapper, not
     the phone itself). Anchor to the viewport instead and stack it right
     below the hamburger menu button, same size/style, so the two read as
     a pair. */
  .phone-expand-btn {
    position: fixed;
    top: 134px;
    right: 6vw;
    z-index: 40;
  }
}

/* Mobile-only "ver en horizontal" for the full-bleed video (not the phone
   mockup, which has its own expand button). Hidden on desktop entirely -
   the full-bleed video already reads fine at 16:9 there. */
.bg-rotate-btn { display: none; }
.bg-rotate-btn[hidden] { display: none; }
@media (max-width: 760px) {
  .bg-rotate-btn {
    position: fixed;
    top: 88px;
    right: 6vw;
    z-index: 30;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    border: 1px solid var(--border-glass-strong);
    background: rgba(11,11,13,0.4);
    color: var(--text);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
  }
  .bg-rotate-btn[hidden] { display: none; }
  .bg-rotate-btn i { font-size: 18px; }

  /* Rotates the currently-visible full-bleed layer (local <video> or the
     Vimeo wrap) 90deg. Swapping width/height to 100vh/100vw BEFORE the
     rotation is what makes it land back at exactly the viewport's own
     footprint once rotated, instead of overflowing or leaving gaps. */
  body.bg-rotated .bg-video,
  body.bg-rotated .bg-video-wrap {
    top: 50%;
    left: 50%;
    right: auto;
    bottom: auto;
    width: 100vh;
    height: 100vw;
    transform: translate(-50%, -50%) rotate(90deg);
    transform-origin: center center;
  }
  /* Whole video visible, letterboxed if needed - not cropped. A real
     <video> just needs object-fit:contain; an iframe has no such thing, so
     it's sized by hand: pick whichever of "fit by width" / "fit by height"
     is the smaller result, which is exactly what min() does here. The two
     expressions stay proportional to each other (each is the other's
     dimension run through the 16:9 ratio), so the video's aspect ratio
     never gets distorted. */
  body.bg-rotated .bg-video {
    object-fit: contain;
  }
  body.bg-rotated .bg-video-wrap iframe {
    width: min(100vh, 177.78vw);
    height: min(100vw, 56.25vh);
    min-height: 0;
    min-width: 0;
  }
}

/* Minimal controls for the Vimeo videos: play/mute toggles and a thin seek
   bar, centered at the bottom of the screen. Hidden until the first menu
   click. */
.video-controls {
  position: fixed;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 1rem;
  width: min(420px, 70vw);
}
.video-controls[hidden] { display: none; }
.play-btn-ctrl,
.mute-btn {
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--border-glass-strong);
  background: rgba(11,11,13,0.4);
  color: var(--silver-2);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color 0.2s ease;
}
.play-btn-ctrl:hover,
.mute-btn:hover { border-color: var(--silver-1); }
.play-btn-ctrl i,
.mute-btn i { font-size: 16px; }
.seek-bar {
  /* The visible track is a thin 2px line (::before below), but the
     clickable/draggable area is this whole element - 2px was also the hit
     target before, which is why it was so hard to grab. */
  position: relative;
  flex: 1;
  height: 24px;
  display: flex;
  align-items: center;
  cursor: pointer;
  touch-action: none;
}
.seek-bar::before {
  content: "";
  display: block;
  width: 100%;
  height: 2px;
  background: rgba(255,255,255,0.22);
  border-radius: 2px;
}
.seek-fill {
  position: absolute;
  top: 50%;
  left: 0;
  height: 2px;
  transform: translateY(-50%);
  width: 0%;
  background: var(--silver-2);
  border-radius: 2px;
}
.seek-fill::after {
  content: "";
  position: absolute;
  right: -4px;
  top: 50%;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--silver-2);
  transform: translateY(-50%);
}

/* Prev/next between multiple videos within one category - hidden by
   default, only shown (script.js) when the active category has more than
   one data-vimeo-ids entry. Same visual language as the other circular
   controls, centered on the left/right edges like a carousel. */
.bg-carousel-btn {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  z-index: 45;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 1px solid var(--border-glass-strong);
  background: rgba(11,11,13,0.4);
  color: var(--silver-2);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color 0.2s ease, opacity 0.2s ease;
}
.bg-carousel-btn:hover { border-color: var(--silver-1); }
.bg-carousel-btn i { font-size: 20px; }
.bg-carousel-btn[hidden] { display: none; }
.bg-carousel-btn[disabled] { opacity: 0.25; pointer-events: none; }
.bg-carousel-prev { left: 3vw; }
.bg-carousel-next { right: 3vw; }
@media (max-width: 760px) {
  .bg-carousel-btn { width: 36px; height: 36px; }
  .bg-carousel-btn i { font-size: 17px; }
  .bg-carousel-prev { left: 3vw; }
  .bg-carousel-next { right: 3vw; }
}

/* ===== Apertura: el mismo video visto a través de "SAGA" ===== */
/* Full-viewport white gate, shown once before the hero. The canvas paints
   a solid white sheet with a goo-fused hole cut through it
   (destination-out) shaped like the word SAGA - #bgVideo shows through
   that hole, nothing more. The hole behaves like a fluid: it reacts to the
   cursor (repulsion field), wanders on its own, and periodically loosens
   enough to stop reading as "SAGA" before reforming. Scrolling pins this
   section and scales the canvas up so the hole grows past the edges of the
   screen - by the end, there is no more white left, only the video, which
   simply continues as the hero background (same element, never restarted).
   This is the deliberate, one-time white/dark theme switch allowed for an
   intro gate. */
.intro-gate {
  /* No background color here on purpose: the white comes only from the
     canvas's own fill, painted fresh every frame. A background here would
     sit between the canvas and #bgVideo, so punching a hole in the canvas
     would just reveal this white instead of the video underneath. */
  background: transparent;
  min-height: 100dvh;
  padding: 0;
  overflow: hidden;
}
.intro-pin {
  position: relative;
  height: 100dvh;
  width: 100%;
  transform-origin: center;
  will-change: transform;
}
.intro-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* ===== Hero (the only other screen on the page) ===== */
.hero {
  min-height: 100dvh;
  padding: 0;
  position: relative;
}

/* The real nav: dim by default, brightens on hover/active. Each item
   swaps the background video (script.js: setupNavVideoSwitch). */
.hero-menu {
  position: absolute;
  right: 6vw;
  top: 20%;
  bottom: 20%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-end;
  list-style: none;
  z-index: 3;
}
.hero-menu a {
  font-family: var(--font-mono);
  font-size: 0.9rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: rgba(237,237,239,0.32);
  transition: color 0.25s ease;
}
.hero-menu a:hover,
.hero-menu a.active-video {
  color: rgba(237,237,239,0.95);
}
@media (max-width: 860px) {
  .hero-menu { right: 6vw; top: 16%; bottom: auto; gap: 1.6rem; }
}

/* Menu becomes a dropdown ONLY on narrow (mobile) screens while the phone
   mockup is active (script.js toggles .collapsed on #heroMenu and un-hides
   #menuToggle) - on wider screens ("en horizontal") the menu always stays
   the visible dim list, phone mockup or not, so this entire block is
   scoped to the mobile breakpoint. */
.menu-toggle { display: none; }
@media (max-width: 760px) {
  .menu-toggle {
    /* fixed, not absolute: .hero-menu's containing block is the .hero
       section, whose own on-screen position depends on scroll (and gets
       frozen wherever it happened to be by body.feed-locked's
       overflow:hidden the moment you enter phone mode) - anchoring to the
       viewport instead sidesteps that entirely, always top-of-screen. */
    position: fixed;
    top: 88px; /* just under the 72px header, clear of the social icons */
    right: 6vw;
    z-index: 45;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    border: 1px solid var(--border-glass-strong);
    background: rgba(11,11,13,0.4);
    color: var(--text);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
  }
  .menu-toggle[hidden] { display: none; }
  .menu-toggle i { font-size: 18px; }

  /* Sits below BOTH the hamburger (88-126px) and the phone's expand
     button (134-172px, styles further down), not on top of them - it used
     to open right over the hamburger and swallow the next tap, so there
     was no way to close it again. */
  .hero-menu.collapsed {
    position: fixed;
    right: 6vw;
    top: 190px;
    bottom: auto;
    gap: 0;
    opacity: 0;
    pointer-events: none;
    transform: translateY(-8px);
    transition: opacity 0.2s ease, transform 0.2s ease;
    z-index: 40;
  }
  .hero-menu.collapsed a {
    display: block;
    padding: 0.55rem 0;
  }
  .hero-menu.collapsed.open {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
  }
}

.hero-content {
  position: absolute;
  z-index: 2;
  left: 0;
  bottom: 5rem;
  width: 50%;
  padding: 0 6vw;
}
@media (max-width: 860px) {
  .hero-content { width: 100%; padding: 0 6vw; }
}
.hero-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.3rem, 2vw, 1.7rem);
  line-height: 1.25;
  letter-spacing: -0.01em;
  text-shadow: 0 2px 16px rgba(0,0,0,0.55);
}
.hero-subtitle {
  margin-top: 1.4rem;
  color: var(--silver-2);
  font-size: 1.02rem;
  max-width: 46ch;
  text-shadow: 0 2px 12px rgba(0,0,0,0.6);
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.001ms !important; animation-duration: 0.001ms !important; }
}
