/* ===========================================================================
   GIFLIF Journey — scroll-scrubbed cinematic stage.

   One continuous video, one sticky stage. The artwork and its typography are
   final and baked into the film, so nothing here paints over the picture: the
   only chrome is a hairline progress rule at the very bottom edge and two small
   pill controls in a corner, both clear of the closing CTA in the final frame.
   ======================================================================== */

:root {
  --jr-indigo: #14213A;
  --jr-gold: #E0A64B;
  --jr-cream: #EFE0C0;
}

/* The scroll track. Its height IS the journey length (set from the config in
   JS, derived from viewport height). Nothing in the ancestor chain may set
   overflow:hidden — sticky dies silently if it does. */
.jr-track { position: relative; width: 100%; background: var(--jr-indigo); }

.jr-stage {
  /* The stage is draggable, so tell the browser we handle the gesture — without
     this, a one-finger drag on a touchscreen is claimed by native scrolling
     before pointermove ever sees it. `pan-y` keeps ordinary vertical flicks
     native and hands us the sideways ones. */
  touch-action: pan-y;
  cursor: grab;
  position: sticky; top: 0;
  height: 100svh; width: 100%;
  overflow: hidden;
  background: var(--jr-indigo);
  display: grid; place-items: center;
}

/* Video and the approved still use IDENTICAL fit rules, so lifting the still
   cannot shift the composition by a pixel. */
.jr-video,
.jr-still {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  /* CONTAIN, always. Karan: "the entire thing that you want to show shows in
     that one thing." The film carries baked-in typography, sponsor identities
     and a final CTA — cover would crop some of that off on almost every window
     that is not exactly 16:9. Letterboxed against the world's own indigo keeps
     every frame whole. */
  object-fit: contain;
  object-position: 50% 50%;
  display: block;
  background: var(--jr-indigo);
}

.jr-video { z-index: 1; }

/* The still sits ABOVE the video and is lifted only once a real decoded frame
   exists beneath it. That is what removes the black flash on first paint. */
.jr-still {
  z-index: 2; opacity: 1;
  transition: opacity .3s linear;
  pointer-events: none;
}
.jr-still.is-hidden { opacity: 0; }

/* --- progress ----------------------------------------------------------- */
.jr-hud {
  position: absolute; left: 0; right: 0; bottom: 0;
  z-index: 5; pointer-events: none;
}
.jr-bar { height: 2px; width: 100%; background: rgba(239, 224, 192, .12); }
.jr-bar-fill {
  height: 100%; width: 100%;
  transform: scaleX(0); transform-origin: 0 50%;
  background: var(--jr-gold);
  will-change: transform;
}

/* --- controls ----------------------------------------------------------- */
/* BOTTOM-LEFT. Top-right collided with the site nav (HOME / OUR IPS / WORK /
   HELLO) which this page renders above the stage — the controls landed
   underneath it and were unreadable. Bottom-left is clear of the nav, clear of
   the centred CTA baked into the final frame, and clear of the progress rule
   which sits flush to the bottom edge. */
.jr-controls {
  position: absolute; left: 1rem; bottom: 1.25rem; z-index: 7;
  display: flex; gap: .5rem;
  padding-bottom: env(safe-area-inset-bottom);
}
/* Karan asked for these to be clearly visible, not a whisper over the artwork:
   solid ground, brighter type, real tap size. Still small enough that they
   never compete with the illustration. */
.jr-btn {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: .68rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--jr-cream); text-decoration: none;
  background: rgba(11, 18, 32, .82);
  border: 1px solid rgba(239, 224, 192, .38);
  border-radius: 999px; padding: .6rem 1.05rem;
  cursor: pointer; backdrop-filter: blur(6px);
  box-shadow: 0 2px 14px rgba(0, 0, 0, .45);
  transition: color .2s ease, border-color .2s ease, background .2s ease;
  min-height: 44px; display: inline-flex; align-items: center;
}
.jr-btn:hover, .jr-btn:focus-visible { color: var(--jr-cream); border-color: var(--jr-gold); }
.jr-btn:focus-visible { outline: 2px solid var(--jr-gold); outline-offset: 3px; }
.jr-btn[aria-pressed="true"] {
  color: #14213A; background: var(--jr-gold); border-color: var(--jr-gold);
}

/* --- entry gate ---------------------------------------------------------
   No button. Karan: show the gesture instead of asking for a click. A big
   two-finger swipe, drifting upward, over a soft scrim of the first frame. Any
   real scroll dismisses it, so the prompt and the action are the same motion. */
.jr-gate {
  position: absolute; inset: 0; z-index: 8;
  display: grid; place-items: center;
  background: radial-gradient(ellipse at 50% 45%, rgba(20, 33, 58, .62) 0%, rgba(11, 18, 32, .90) 72%);
  transition: opacity .8s ease;
}
.jr-gate.is-gone { opacity: 0; pointer-events: none; }
.jr-gate-inner { text-align: center; padding: 0 1.5rem; color: var(--jr-cream); }

.jr-gate-eyebrow {
  margin: 0 0 1.8rem;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: .64rem; letter-spacing: .38em; text-transform: uppercase;
  color: rgba(224, 166, 75, .9);
}

/* Phase 1 — the loading bar. Real buffered progress, in the brand's own gold.
   No spinner: a spinner says "something is happening", a bar says "how much
   longer", which is the only question anyone actually has. */
.jr-load {
  display: flex; flex-direction: column; align-items: center; gap: 1rem;
  transition: opacity .35s ease;
}
.jr-load-bar {
  width: min(280px, 62vw); height: 2px;
  background: rgba(239, 224, 192, .16);
  border-radius: 2px; overflow: hidden;
}
.jr-load-fill {
  height: 100%; width: 100%;
  transform: scaleX(.02); transform-origin: 0 50%;
  background: var(--jr-gold);
  /* NO transition. The value is driven per-frame from rAF; a CSS transition on
     top of that restarts every frame and produces lag and stutter instead of
     smoothing. Smoothing is done in JS, where the easing is aware of dt. */
  will-change: transform;
}
/* A slow sheen travelling along the bar, so it still reads as "working" even in
   the moments when the network genuinely has nothing to report. */
.jr-load-bar { position: relative; }
.jr-load-bar::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent,
              rgba(255, 240, 214, .55), transparent);
  transform: translateX(-100%);
  animation: jrSheen 1.5s ease-in-out infinite;
}
@keyframes jrSheen {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}
.jr-gate.is-ready .jr-load-bar::after { animation: none; opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .jr-load-bar::after { animation: none; opacity: 0; }
}
.jr-load-label {
  margin: 0;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: .58rem; letter-spacing: .28em; text-transform: uppercase;
  color: rgba(239, 224, 192, .55);
}
/* Once ready the bar steps aside entirely rather than lingering under the
   gesture — two things competing for the same moment reads as clutter. */
.jr-gate.is-ready .jr-load {
  opacity: 0; height: 0; overflow: hidden; margin: 0;
  pointer-events: none;
}

/* Phase 2 — the gesture. Hidden until the journey can genuinely move; showing
   someone how to scroll into a picture that cannot yet respond is worse than
   showing nothing. */
.jr-gate-ready {
  opacity: 0; max-height: 0; overflow: hidden;
  transform: translateY(10px);
  transition: opacity .55s ease, transform .55s ease;
}
.jr-gate.is-ready .jr-gate-ready {
  opacity: 1; max-height: 320px; transform: translateY(0);
}
.jr-gate-gesture {
  color: var(--jr-cream);
  filter: drop-shadow(0 4px 18px rgba(0, 0, 0, .75));
}

/* Hand travels up and resets, the way a real two-finger swipe does. */
.jr-g-hand { animation: jrGHand 2.8s cubic-bezier(.34, 0, .2, 1) infinite; }
@keyframes jrGHand {
  0%, 10%   { transform: translateY(14px); opacity: .5; }
  40%, 56%  { transform: translateY(-14px); opacity: 1; }
  86%, 100% { transform: translateY(14px); opacity: .5; }
}
/* Arrow leads the hand by half a beat. */
.jr-g-arrow { animation: jrGArrow 2.8s cubic-bezier(.34, 0, .2, 1) infinite; }
@keyframes jrGArrow {
  0%, 8%    { opacity: 0; transform: translateY(16px); }
  34%       { opacity: 1; transform: translateY(-4px); }
  62%, 100% { opacity: 0; transform: translateY(-20px); }
}

.jr-gate-label {
  margin: 1.2rem 0 0;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: clamp(1.25rem, 3vw, 1.9rem);
  color: var(--jr-cream);
}
.jr-gate-sub {
  margin: .7rem 0 0; min-height: 1em;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: .58rem; letter-spacing: .28em; text-transform: uppercase;
  color: rgba(239, 224, 192, .5);
}

@media (prefers-reduced-motion: reduce) {
  .jr-g-hand, .jr-g-arrow { animation: none; }
}

/* --- letterbox where cropping would eat the artwork's own type ----------- */
/* The film carries baked-in typography and sponsor identities. Cropping 16:9
   into a portrait or squat window cuts them off, so outside a near-16:9 window
   the whole frame is shown against the world's own indigo instead. */
/* (contain is now the default at every size — see .jr-video above) */

/* --- reduced motion ------------------------------------------------------ */
/* The same approved artwork, stepped through at the visitor's own pace. */
.jr-reduced { display: grid; gap: 2px; background: var(--jr-indigo); }
.jr-reduced img { width: 100%; height: auto; display: block; }

/* --- scroll hint --------------------------------------------------------
   Karan: "people otherwise won't understand." Two fingers on a trackpad
   drifting up, shown on the frame the visitor lands on. It appears only after
   the gate is dismissed (never stacked over it), and the first real scroll
   retires it for good — a hint that keeps nagging is just clutter. */
.jr-hint {
  position: absolute; left: 50%; bottom: 6.2rem;
  transform: translateX(-50%);
  z-index: 6; opacity: 0; pointer-events: none;
  display: flex; flex-direction: column; align-items: center; gap: .55rem;
  color: rgba(239, 224, 192, .9);
  text-shadow: 0 2px 10px rgba(0, 0, 0, .8);
  transition: opacity .7s ease;
}
.jr-hint.is-live { opacity: 1; }
.jr-hint.is-gone { opacity: 0; }
/* (the in-stage variant is retained for the post-entry hint; the landing
   screen uses .jr-gate-hint above) */
.jr-hint span {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: .58rem; letter-spacing: .28em; text-transform: uppercase;
}
.jr-hint svg { filter: drop-shadow(0 2px 8px rgba(0, 0, 0, .7)); }

/* The hand drifts up and settles, the way a real two-finger swipe does. */
.jr-hint-hand { animation: jrSwipe 2.6s cubic-bezier(.4, 0, .2, 1) infinite; }
@keyframes jrSwipe {
  0%, 12%   { transform: translateY(6px);  opacity: .45; }
  38%, 58%  { transform: translateY(-6px); opacity: 1; }
  85%, 100% { transform: translateY(6px);  opacity: .45; }
}
/* The arrow leads it, half a beat ahead. */
.jr-hint-arrow { animation: jrSwipeArrow 2.6s cubic-bezier(.4, 0, .2, 1) infinite; }
@keyframes jrSwipeArrow {
  0%, 10%  { opacity: 0; transform: translateY(6px); }
  35%      { opacity: .95; transform: translateY(-4px); }
  60%, 100%{ opacity: 0; transform: translateY(-10px); }
}

@media (prefers-reduced-motion: reduce) {
  .jr-hint-hand, .jr-hint-arrow { animation: none; }
}
@media (max-width: 820px) { .jr-hint { bottom: 5.5rem; } }

/* Feedback that the picture itself is grabbable. */
.jr-stage:active { cursor: grabbing; }
.jr-video, .jr-still { user-select: none; -webkit-user-drag: none; pointer-events: none; }

/* --- the route into the business site -----------------------------------
   Karan: "go to main site should bling on top centre; event consultancy button
   on top right isn't right."

   Top centre, fixed, and gently pulsing. On a full-bleed cinematic landing page
   a quiet corner link is simply not seen — the artwork takes all the attention,
   which is the point of the artwork. This is the one element allowed to move
   and glow so the way onward is never in question. Everything else on the page
   stays deliberately still. */
.jr-gotosite {
  position: fixed;
  top: 3.1rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 120;                     /* above the topbar (100) and the gate (8) */
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .68rem 1.35rem;
  border-radius: 999px;
  background: var(--jr-gold);
  color: #14213A;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: .68rem; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase;
  text-decoration: none; white-space: nowrap;
  border: 1px solid rgba(255, 236, 200, .85);
  animation: jrGlow 2.4s ease-in-out infinite;
  transition: transform .2s ease, background .2s ease;
}
.jr-gotosite:hover {
  background: #F2CB80;
  transform: translateX(-50%) translateY(-2px);
  animation-play-state: paused;      /* stop pulsing once it has been found */
}
.jr-gotosite:focus-visible {
  outline: 2px solid var(--jr-cream); outline-offset: 4px;
  animation-play-state: paused;
}
.jr-gotosite-arrow { transition: transform .2s ease; }
.jr-gotosite:hover .jr-gotosite-arrow { transform: translateX(3px); }

/* The "bling": a breathing halo rather than a blink. A hard flash on a slow
   cinematic page reads as an error; a slow pulse reads as an invitation. */
@keyframes jrGlow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(224, 166, 75, .55),
                         0 2px 14px rgba(0, 0, 0, .45); }
  50%      { box-shadow: 0 0 0 10px rgba(224, 166, 75, 0),
                         0 2px 22px rgba(224, 166, 75, .5); }
}

@media (prefers-reduced-motion: reduce) {
  .jr-gotosite { animation: none; box-shadow: 0 2px 18px rgba(224, 166, 75, .45); }
}

/* On a phone the topbar nav sits close; drop it clear and shrink slightly. */
@media (max-width: 620px) {
  .jr-gotosite {
    top: auto; bottom: 4.6rem;
    font-size: .6rem; padding: .58rem 1.05rem; letter-spacing: .12em;
  }
}
