/* ==========================================================================
   JUDAN — holding page
   ========================================================================== */

:root{
  /* ---- Brand ----------------------------------------------------------- */
  --brand:            #4D6A92;   /* primary — rgb(77,106,146) */
  --brand-deep:       #11202D;   /* deepest navy in the blue-hour reference */
  --brand-mid:        #16334B;
  --brand-steel:      #2B4C66;
  --brand-light:      #9CB8DC;   /* lightened brand — accent TEXT only.
                                    --brand itself sits at 1.9:1 on the graded
                                    video and fails contrast as type. */
  --white:            #ffffff;

  /* ---- Blue-hour grade (tunable) --------------------------------------- */
  /* 1. duotone tint applied with mix-blend-mode:color */
  --grade-tint:       #4D6A92;
  --grade-tint-alpha: 0.92;

  /* 2. dusk multiply gradient — sky deepest, ground lifts */
  --grade-sky:        #223C58;
  --grade-band:       #587FA1;
  --grade-ground:     #86A2C2;

  /* 3. warm horizon glow */
  --grade-glow:       rgba(201, 169, 160, 0.20);

  /* 4. flat shade under the text */
  --grade-shade:      0.28;

  /* ---- Layout ---------------------------------------------------------- */
  --gap:              22px;
  --slide-h:          140px;
  --slide-h-sm:       100px;
}

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

html,
body{ height:100%; }

body{
  font-family:'Montserrat', 'Segoe UI', system-ui, -apple-system, sans-serif;
  color:var(--white);
  background:var(--brand-deep);
  overflow:hidden;
  position:relative;
}

/* ==========================================================================
   Background stage
   --------------------------------------------------------------------------
   The footage now comes from a Vimeo background player rather than a
   same-origin <video>, but the treatment is unchanged: it is graded to blue
   hour entirely with blend layers on top, and no CSS filter is applied to the
   player itself. The blend stack is identical to v2, so the look is identical.

   The one structural difference an iframe forces: a cross-origin frame cannot
   be object-fit:cover'd, so the frame is sized to a 16:9 box that is always at
   least as large as the viewport in both axes and centred — the CSS
   equivalent of cover for a fixed-ratio embed. .stage clips the overflow.
   ========================================================================== */

.stage{
  position:fixed;
  inset:0;
  z-index:-1;
  overflow:hidden;
  background:var(--brand-deep);
  isolation:isolate;          /* contain the blend stack */
  pointer-events:none;
}

/* Still frame beneath the player: covers the load gap, and is the entire
   background when motion is not wanted. */
.stage__poster{
  position:absolute;
  inset:0;
  background:url('../auh-poster.jpg') center / cover no-repeat, var(--brand-deep);
}

/* Centred without a transform. WebKit composites an iframe on its own layer
   and a transform on that layer is a long-standing source of blank or
   mispainted frames in Safari; all four insets at 0 plus margin:auto centres
   the box on both axes even when it is larger than its container, which is
   exactly what translate(-50%,-50%) was doing. .stage clips the overflow. */
.stage__video{
  position:absolute;
  top:0;
  right:0;
  bottom:0;
  left:0;
  margin:auto;
  display:block;

  /* 16:9 cover: whichever of the two pairs is larger wins. */
  width:100vw;
  height:56.25vw;             /* 100 / (16/9) */
  min-width:177.78vh;         /* 100 * (16/9) */
  min-height:100vh;

  border:0;
  pointer-events:none;

  /* Fade in once the player has painted, so the poster never cuts to black. */
  opacity:0;
  transition:opacity 900ms ease;
}

/* main.js adds this on the frame's load event, on the first message from the
   player origin, or on a timer — whichever lands first, so the frame can
   never sit at opacity 0 with the video playing invisibly behind it. */
.stage__video.is-ready{ opacity:1; }

/* No script at all: reveal the frame rather than leaving it invisible. */
html:not(.js) .stage__video{ opacity:1; }

.grade{
  position:absolute;
  inset:0;
  pointer-events:none;
}

/* 1. Duotone — recolours the frame to the brand hue, keeping luminance. */
.grade--duotone{
  background:var(--grade-tint);
  opacity:var(--grade-tint-alpha);
  mix-blend-mode:color;
}

/* 2. Dusk — multiplies a vertical gradient so the sky drops to deep navy
      while the ground stays readable, matching the reference photograph. */
.grade--dusk{
  background:linear-gradient(
    180deg,
    var(--grade-sky)    0%,
    var(--grade-sky)    18%,
    var(--grade-band)   58%,
    var(--grade-ground) 100%
  );
  mix-blend-mode:multiply;
}

/* 3. Horizon — the faint warm band low in the reference frame. */
.grade--horizon{
  background:radial-gradient(
    120% 55% at 22% 88%,
    var(--grade-glow) 0%,
    transparent 60%
  );
  mix-blend-mode:screen;
}

/* 4. Shade — flat floor so white type always clears contrast. */
.grade--shade{
  background:var(--brand-deep);
  opacity:var(--grade-shade);
}

/* Fallback: without blend-mode support the duotone/dusk/horizon layers would
   paint as flat blocks, so hide them and lean on a plain navy wash. */
@supports not (mix-blend-mode: color){
  .grade--duotone,
  .grade--dusk,
  .grade--horizon{ display:none; }
  .grade--shade{
    background:linear-gradient(180deg, var(--brand-deep), var(--brand-steel));
    opacity:.82;
  }
}

/* ==========================================================================
   Content
   ========================================================================== */

.container{
  width:90%;
  max-width:1000px;
  height:100vh;
  height:100dvh;              /* stops the shift under mobile browser chrome */
  margin:0 auto;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:var(--gap);
  text-align:center;
}

.logo img{
  height:60px;
  width:auto;
}

/* Height is a floor, not a fixed value — main.js grows it to fit the tallest
   headline so a slow-loading or fallback font can never clip a line. That
   height is appended to the END of this stylesheet as a real rule rather than
   written as an inline style: style-src has no 'unsafe-inline', and WebKit
   enforces that against style writes from script where Blink does not. */
.viewport{
  min-height:var(--slide-h);
  width:100%;
  max-width:900px;
  overflow:hidden;
}

.track{ will-change:transform; }

.slide{
  height:var(--slide-h);
  display:flex;
  align-items:center;
  justify-content:center;
}

/* Reduced-motion presentation: the three headlines cross-fade in place rather
   than freezing on the first. Opacity carries no vestibular risk, so the page
   still reads through all three lines. main.js drives the fades. */
.viewport.is-fade .track{
  position:relative;
  height:100%;
}

.viewport.is-fade .slide{
  position:absolute;
  top:0;
  right:0;
  bottom:0;
  left:0;
  opacity:0;
}

.viewport.is-fade .slide:first-child{ opacity:1; }

/* The loop duplicate is only meaningful for the sliding track. */
.viewport.is-fade .slide[aria-hidden="true"]{ display:none; }

/* Measuring pass: release every fixed height and every absolute position so
   each headline reports its natural height, whatever font finally loaded.
   This block MUST stay below the .is-fade block — the two have identical
   specificity, so source order is what lets measurement win while a
   cross-fade is running. */
.viewport.is-measuring,
.viewport.is-measuring .track{
  height:auto;
}

.viewport.is-measuring .slide{
  position:static;
  height:auto;
  display:flex;
  opacity:1;
}

/* Sized so every headline sets in at most two lines from ~360px up: the 52px
   ceiling leaves ~7% of the 900px measure spare on the longest line, which is
   the margin that keeps it at two lines across rendering engines. */
h1{
  font-size:clamp(21px, 4.2vw, 52px);
  font-weight:600;
  line-height:1.2;
  letter-spacing:1px;
}

.accent{ color:var(--brand-light); }

/* Descriptor line: a full sentence, so it reads in sentence case at a wider
   measure rather than as a spaced-out uppercase strapline. */
.subtext{
  font-size:17px;
  letter-spacing:.4px;
  opacity:.85;
  line-height:1.6;
  max-width:620px;
  margin-left:auto;
  margin-right:auto;
}

.footer-line{
  position:fixed;
  bottom:20px;
  left:50%;
  transform:translateX(-50%);
  font-size:12px;
  letter-spacing:2px;
  text-transform:uppercase;
  opacity:.6;
  pointer-events:none;
  /* left:50% caps the shrink-to-fit width at half the viewport, so on a phone
     the line breaks in two without this. */
  white-space:nowrap;
}

@media (max-width:600px){
  .viewport{ min-height:var(--slide-h-sm); }
  .slide{ height:var(--slide-h-sm); }

  /* A little more measure and no tracking: both buy the phone breakpoint the
     room it needs to hold the headlines to two lines. */
  .container{ width:94%; }
  h1{ letter-spacing:0; }

  .logo img{ height:50px; }

  .subtext{ font-size:15px; }
}

/* ==========================================================================
   Reduced motion
   --------------------------------------------------------------------------
   With script running, main.js handles this: the headlines cross-fade instead
   of sliding. The footage still plays — it is the same Vimeo embed loaded on
   page load in every state — so this no longer hides .stage__video.

   The rules below are only the no-script floor: one headline, no carousel.
   ========================================================================== */

@media (prefers-reduced-motion: reduce){
  html:not(.js) .viewport{ height:auto; }
  html:not(.js) .slide{ display:none; }
  html:not(.js) .slide:first-child{ display:flex; }
}
