/* ==========================================================================
   SVEF — motion  ·  THRESHOLD

   Loaded last, so a single-class rule here refines the component rule of
   the same name rather than colliding with it. Everything in this file is
   additive: delete it and the site still works, without the choreography.

   The system has ONE device — the aperture, a letterbox mask that draws
   back to admit you — and every other movement is that device applied
   somewhere new: the page opens through it, photographs below the fold
   reveal through it, each headline line rises from behind it, and the
   slideshow frames each successive room tighter inside it.

   One idea used consistently reads as choreography. Five different ideas
   read as a demo reel.
   ========================================================================== */

/* ------------------------------------------------------------- the intro
   .intro is server-rendered on <html> so the hero never paints in its
   resting state and then jumps back to animate. main.js swaps it for
   .is-open once the first photograph has decoded — see the note on the
   overture in main.js for why that wait is capped by a timer. */

html.intro .site-header { opacity: 0; }
html.is-open .site-header { opacity: 1; }

/* The header's entrance is timed to the home page's overture, where it
   should arrive AFTER the headline has set itself — about 2.2s in. Every
   other page has no overture to wait for, so that delay was simply 2.2
   seconds of missing header on every navigation. The wait belongs to the
   page that earns it, which is the only one carrying .has-hero. */
.site-header {
  transition: opacity 500ms var(--ease-curtain) 120ms,
              padding var(--dur-base) var(--ease-glide),
              background var(--dur-base) var(--ease-glide);
}
body.has-hero .site-header {
  transition-property: opacity, padding, background;
  transition-duration: var(--dur-slow), var(--dur-base), var(--dur-base);
  transition-timing-function: var(--ease-curtain), var(--ease-glide), var(--ease-glide);
  transition-delay: 2200ms, 0ms, 0ms;
}

/* ------------------------------------------------------- the logo entrance
   The lockup is a single image now, so there is nothing left to draw stroke
   by stroke. It arrives with the header instead: a fade and a short lift,
   which is the same gesture the rest of the header chrome makes. */

.site-header .logo {
  opacity: 0;
  translate: 0 6px;
  transition: opacity var(--dur-slow) var(--ease-curtain),
              translate var(--dur-slow) var(--ease-curtain);
}
html.is-open .site-header .logo { opacity: 1; translate: none; }

/* Same reasoning as the header itself: the lockup arrives in step with the
   overture on the home page, and simply appears everywhere else. */
.site-header .logo { transition-delay: 120ms; }
body.has-hero .site-header .logo { transition-delay: 2150ms; }

/* The footer lockup is not an entrance. It simply sits. */
.site-footer .logo { opacity: 1; translate: none; }

/* --------------------------------------------------------- stagger delays
   reveal.js sets --delay from data-reveal-delay so a row of cards arrives
   in sequence rather than all at once. */

[data-reveal] { transition-delay: var(--delay, 0ms); }

/* =================================================== NO MOTION LAYER =====
   Every reveal in this design begins at opacity 0, a clip-path closed to a
   hairline, or a scaleX of 0. That is safe only for as long as something
   is guaranteed to open them again. If the script never runs — blocked,
   a parse error, an ancient browser — an ungated page would render as an
   empty black column with no way back.

   main.js sets .js on <html> as its first act. Everything below is the
   answer to that class being absent. It must stay in sync with every
   opening state declared in base.css and components.css. */

html:not(.js) .hero-stage { clip-path: none !important; }
html:not(.js) .hero-title .ln i { transform: none !important; }
html:not(.js) .site-header { opacity: 1 !important; }
html:not(.js) .hero-eyebrow .line,
html:not(.js) .hero-foot::before,
html:not(.js) .seam::before,
html:not(.js) .step::before,
html:not(.js) .pillar::before { transform: scaleX(1) !important; }

html:not(.js) .hero-eyebrow .eyebrow,
html:not(.js) .hero-foot > *,
html:not(.js) .seat,
html:not(.js) .creed-list li,
html:not(.js) .statement-text em,
html:not(.js) [data-reveal] {
  opacity: 1 !important;
  transform: none !important;
  clip-path: none !important;
}

html:not(.js) .logo { opacity: 1 !important; translate: none !important; }
html:not(.js) .figure-mask { clip-path: none !important; }

/* Without script the slideshow never advances, so the stack must resolve
   to exactly one visible frame rather than five stacked photographs. */
html:not(.js) .hero-stage-slide { opacity: 0 !important; }
html:not(.js) .hero-stage-slide.is-current { opacity: 1 !important; }
html:not(.js) .hero-stage-slide img { transform: none !important; }

/* ==================================================== REDUCED MOTION =====
   Motion is a courtesy, not a requirement. When it is declined, remove it
   wholesale rather than merely shortening it. tokens.css already collapses
   the durations; what is left here are the states that would otherwise
   strand content off-screen or reveal all five photographs at once. */

@media (prefers-reduced-motion: reduce) {
  .hero-stage { clip-path: none !important; }
  .hero-title .ln i { transform: none !important; }
  .site-header { opacity: 1 !important; }

  .hero-eyebrow .line,
  .hero-foot::before,
  .seam::before,
  .step::before,
  .pillar::before { transform: scaleX(1) !important; }

  .hero-eyebrow .eyebrow,
  .hero-foot > *,
  .seat,
  .creed-list li,
  .statement-text em,
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }

  .logo { opacity: 1 !important; translate: none !important; }
  .figure-mask { clip-path: none !important; }

  .hero-stage-slide { transition: none !important; }
  .hero-stage-slide:not(.is-current) { opacity: 0 !important; }
  .hero-stage-slide.is-current { opacity: 1 !important; }
  .hero-stage-slide img { transform: none !important; }

  /* The hover wipe holds its end state rather than travelling to it. */
  .btn::before,
  .nav-link::after,
  .link-arrow::after,
  .link-sweep::after { transition: none !important; }
}

/* ==================================================== THE PAGE HERO ======
   Interior pages get the same arrival as the home page, one step shorter:
   the photograph settles out of a slight over-scale while the kicker,
   title and standfirst rise in sequence. No aperture on the stage here —
   that gesture belongs to the front door, and spending it on every page
   would make it ordinary. */

.page-hero-media img {
  transform: scale(1.05);
  transition: transform 2600ms var(--ease-curtain);
}
html.is-open .page-hero-media img { transform: scale(1); }

.page-hero-sub,
.page-hero-title,
.page-hero-text,
.page-hero-inner .btn-group {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--dur-reveal) var(--ease-curtain),
              transform var(--dur-reveal) var(--ease-curtain);
}
html.is-open .page-hero-sub,
html.is-open .page-hero-title,
html.is-open .page-hero-text,
html.is-open .page-hero-inner .btn-group { opacity: 1; transform: none; }

html.is-open .page-hero-sub              { transition-delay: 140ms; }
html.is-open .page-hero-title            { transition-delay: 240ms; }
html.is-open .page-hero-text             { transition-delay: 380ms; }
html.is-open .page-hero-inner .btn-group { transition-delay: 500ms; }

/* Same obligation as everything else that opens from nothing: if the
   script never runs, or motion is declined, it must already be there. */
html:not(.js) .page-hero-media img,
html:not(.js) .page-hero-sub,
html:not(.js) .page-hero-title,
html:not(.js) .page-hero-text,
html:not(.js) .page-hero-inner .btn-group {
  opacity: 1 !important;
  transform: none !important;
}

@media (prefers-reduced-motion: reduce) {
  .page-hero-media img,
  .page-hero-sub,
  .page-hero-title,
  .page-hero-text,
  .page-hero-inner .btn-group {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* The timeline's focus state is decoration on top of a list that already
   reads correctly, so when motion is declined it simply does not run —
   timeline.js returns early. Nothing needs putting back here beyond the
   connector, which is handled with the other draws above. */
@media (prefers-reduced-motion: reduce) {
  .step-badge,
  .step-number { transform: none !important; }
}
