/*
   Multi-Hyphenate home title.

   Seven pinned film planes form one responsive tessellation. The world plane
   is a full-stage underlay; the remaining six cuts share a single vertex map
   supplied by optical-home.js. Shared edges therefore meet exactly while the
   underlay catches the subpixel seams a browser can introduce on diagonals.
*/

body.landing-page {
  min-height: 100svh;
  margin: 0;
  overflow: hidden;
  color: #e8d6bf;
  background: #080b0a;
}

.optical-stage {
  --black: #080b0a;
  --cream: #e8d6bf;
  --ember: var(--mh-nav-accent);
  --teal-ink: #4b8d84;
  --nav-height: var(--mh-bottom-nav-h);
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100svh;
  height: 100dvh;
  min-height: 31rem;
  overflow: hidden;
  isolation: isolate;
  container-type: size;
  background-color: var(--black);
  background-image: url("../assets/brand/paper-grain.jpg");
  background-position: center;
  background-size: 512px auto;
  background-blend-mode: soft-light;
}

.optical-stage::before {
  position: absolute;
  inset: 0;
  z-index: 1;
  content: "";
  pointer-events: none;
  background:
    radial-gradient(circle, rgba(232, 214, 191, 0.16) 0 0.42px, transparent 0.7px) 0 0 / 3px 3px,
    url("../assets/brand/paper-grain.jpg") center / 512px auto;
  mix-blend-mode: screen;
  opacity: 0.11;
}

/* Human-framed wraps replace seven independent decoders at the aspect ratios
   for which a bespoke edit exists. Their grades remain separate color maps so
   the teal balance can be tuned without touching either edit. */
.optical-master {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: none;
  overflow: hidden;
  isolation: isolate;
  pointer-events: none;
  background: #1f5655;
}

.optical-master-poster,
.optical-master-video,
.optical-master-grade {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: fill;
}

.optical-master-poster,
.optical-master-video {
  filter: grayscale(1) contrast(1.42) brightness(1.14);
  mix-blend-mode: multiply;
}

/* The poster IS frame one of the clip, so this hand-off has nothing to hide —
   it only has to be soft enough not to register as a cut. Half a second. */
.optical-master-poster {
  z-index: 0;
  opacity: 0.94;
  transition: opacity 220ms linear;
}

.optical-master-video {
  z-index: 1;
  opacity: 0;
  transition: opacity 220ms linear;
}

.optical-master-grade {
  z-index: 2;
  opacity: 0.9;
  mix-blend-mode: color;
}

.optical-master::before,
.optical-master::after {
  position: absolute;
  inset: 0;
  z-index: 3;
  content: "";
  pointer-events: none;
}

.optical-master::before {
  background-image: radial-gradient(circle, rgba(2, 5, 4, 0.82) 0 0.48px, transparent 0.7px);
  background-size: 2.4px 2.4px;
  mix-blend-mode: multiply;
  opacity: 0.46;
}

.optical-master::after {
  z-index: 4;
  background: url("../assets/brand/paper-grain.jpg") center / 512px auto;
  mix-blend-mode: soft-light;
  opacity: 0.48;
}

.optical-master.is-playing .optical-master-video {
  opacity: 0.94;
}

.optical-master.is-playing .optical-master-poster {
  opacity: 0;
}

@media (min-width: 1100px) {
  .optical-master--desktop {
    display: block;
  }

  .optical-stage .optical-plane {
    display: none;
  }
}

@media (max-width: 480px) and (max-aspect-ratio: 4 / 5) {
  .optical-master--mobile {
    display: block;
  }

  .optical-stage .optical-plane {
    display: none;
  }
}

@media (min-width: 481px) and (max-width: 1099px) and (max-aspect-ratio: 4 / 5) {
  .optical-master--tablet {
    display: block;
  }

  .optical-stage .optical-plane {
    display: none;
  }
}

/* Every image is pinned to the complete title card. Only its shared mask moves. */
.optical-plane {
  position: absolute;
  inset: 0;
  overflow: hidden;
  isolation: isolate;
  pointer-events: none;
  background: var(--plane-ink);
  clip-path: var(--plane-cut, inset(0));
  transition: clip-path 520ms cubic-bezier(0.32, 0.72, 0, 1);
  will-change: clip-path;
}

.optical-plane--world {
  --plane-ink: #1f5655;
  z-index: 2;
  clip-path: none;
}

.optical-plane--car {
  --plane-ink: #4d9187;
  --plane-cut: polygon(38% 0%, 100% 0%, 100% 36%, 74% 29%, 49% 38%, 32% 28%);
  z-index: 3;
}

.optical-plane--storm {
  --plane-ink: #2f716e;
  --plane-cut: polygon(0% 31%, 32% 28%, 49% 38%, 45% 59%, 28% 62%, 0% 58%);
  z-index: 4;
}

.optical-plane--industry {
  --plane-ink: #5a9f95;
  --plane-cut: polygon(49% 38%, 74% 29%, 100% 36%, 100% 56%, 74% 65%, 45% 59%);
  z-index: 5;
}

.optical-plane--fire {
  --plane-ink: #397d72;
  --plane-cut: polygon(0% 58%, 28% 62%, 45% 59%, 33% 91.8%, 0% 91.8%);
  z-index: 6;
}

.optical-plane--spark {
  --plane-ink: #72a99d;
  --plane-cut: polygon(45% 59%, 74% 65%, 68% 91.8%, 33% 91.8%);
  z-index: 7;
}

.optical-plane--valiant {
  --plane-ink: #28696a;
  --plane-cut: polygon(74% 65%, 100% 56%, 100% 91.8%, 68% 91.8%);
  z-index: 8;
}

.optical-poster,
.optical-video {
  position: absolute;
  inset: -1.25%;
  width: 102.5%;
  height: 102.5%;
  max-width: none;
  object-fit: cover;
  object-position: var(--shot-x, 50%) var(--shot-y, 50%);
  transform: translate3d(var(--shot-shift-x, 0%), var(--shot-shift-y, 0%), 0) scale(var(--shot-scale, 1));
  transform-origin: center;
}

.optical-poster {
  z-index: 0;
  opacity: 0.98;
  filter: grayscale(1) contrast(1.45) brightness(1.15);
  mix-blend-mode: multiply;
  transition: opacity 360ms linear;
}

.optical-video {
  z-index: 1;
  opacity: 0;
  filter: grayscale(1) contrast(var(--shot-contrast, 1.58)) brightness(var(--shot-brightness, 1.2));
  mix-blend-mode: multiply;
  transition: opacity 360ms linear;
}

.optical-plane.is-playing .optical-video {
  opacity: 0.9;
}

.optical-plane.is-playing .optical-poster {
  opacity: 0;
}

.optical-plane--car .optical-poster {
  filter: grayscale(1) brightness(1.28) contrast(1.04);
}

.optical-plane--storm .optical-poster,
.optical-plane--valiant .optical-poster {
  filter: grayscale(1) brightness(1.1) contrast(1.02);
}

.optical-plane--fire .optical-video {
  filter: grayscale(1) contrast(var(--shot-contrast, 1.34)) brightness(var(--shot-brightness, 1.58));
}

.optical-plane--fire .optical-poster {
  filter: grayscale(1) brightness(1.24) contrast(1.08);
}

.optical-plane::before,
.optical-plane::after {
  position: absolute;
  inset: 0;
  z-index: 2;
  content: "";
  pointer-events: none;
}

.optical-plane::before {
  background-image: radial-gradient(circle, rgba(2, 5, 4, 0.82) 0 0.48px, transparent 0.7px);
  background-size: 2.4px 2.4px;
  mix-blend-mode: multiply;
  opacity: 0.46;
}

.optical-plane::after {
  background: url("../assets/brand/paper-grain.jpg") center / 512px auto;
  mix-blend-mode: soft-light;
  opacity: 0.48;
}

/* No-JS framing defaults. The shot-aware JS replaces these variables at each
   editorial cut while the tessellation itself remains fixed. */
.optical-plane--world {
  --shot-x: 52%;
  --shot-y: 48%;
  --shot-scale: 1.02;
  --shot-shift-x: -2.04%;
  --shot-shift-y: 0.09%;
}

.optical-plane--car {
  --shot-x: 55%;
  --shot-y: 40%;
  --shot-scale: 1.03;
  --shot-shift-x: 16.31%;
  --shot-shift-y: -20.92%;
}

.optical-plane--storm {
  --shot-x: 43%;
  --shot-y: 40%;
  --shot-scale: 1.07;
  --shot-shift-x: -17.88%;
  --shot-shift-y: 5.82%;
}

.optical-plane--industry {
  --shot-x: 58%;
  --shot-y: 49%;
  --shot-scale: 1.04;
  --shot-shift-x: 16.07%;
  --shot-shift-y: -3.84%;
}

.optical-plane--fire {
  --shot-x: 50%;
  --shot-y: 46%;
  --shot-scale: 0.88;
  --shot-shift-x: -28.29%;
  --shot-shift-y: 26.93%;
}

.optical-plane--spark {
  --shot-x: 52%;
  --shot-y: 39%;
  --shot-scale: 0.58;
  --shot-shift-x: 3.72%;
  --shot-shift-y: 30.77%;
}

.optical-plane--valiant {
  --shot-x: 34%;
  --shot-y: 40%;
  --shot-scale: 0.78;
  --shot-shift-x: 45.65%;
  --shot-shift-y: 30.24%;
}

.optical-title {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: flex;
  box-sizing: border-box;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* The nav rail owns the bottom of the frame; centring against the full
     viewport would read low, so the title centres in the area above the rail. */
  padding: 0 0 var(--nav-height, 4.75rem);
  pointer-events: none;
}

.optical-stage .motion-toggle {
  position: absolute;
  top: max(1rem, env(safe-area-inset-top));
  right: 4.1cqw;
  bottom: auto;
  left: auto;
  z-index: 30;
  /* The rule IS the underline of the label, so the box has to hug the text —
     a fixed min-width left it running 38px past the end of the word. Height
     still carries the touch target; width no longer has to. */
  width: fit-content;
  height: auto;
  min-width: 0;
  min-height: 2.75rem;
  padding: 0.45rem 0 0.35rem;
  color: var(--cream);
  background: transparent;
  background-blend-mode: normal;
  clip-path: none;
  font-size: 0.68rem;
  text-align: right;
  transform: none;
  border-bottom: 1px solid rgba(232, 214, 191, 0.52);
  pointer-events: auto;
}

.optical-stage .motion-toggle::before {
  content: none;
}

.optical-stage .motion-toggle:hover,
.optical-stage .motion-toggle:focus-visible {
  color: #fff3e2;
  border-bottom-color: #fff3e2;
}

.optical-stage .motion-toggle[aria-pressed="true"] {
  color: var(--ember);
  border-bottom-color: var(--ember);
}

.optical-wordmark {
  position: static;
  width: min(38.2cqw, 57cqh);
  margin: 0;
  font-size: 0;
  line-height: 0;
}

.optical-wordmark .optical-mark {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0.35cqh 0.55cqh 0 rgba(1, 3, 2, 0.52));
}

/* The hand-writing reveal. Sixteen per-letter strokes fire in writing order
   (delay/duration ride in as --dl/--dd from the markup), then the swash. At
   rest every mask element is fully present, so no-JS and reduced motion see
   the finished mark and never the animation. */
/* The reveal is a POSITION sweep, not a path traversal.
   Every path-based attempt could show a detached fragment, because revealing
   along a traversal means the pen jumps wherever the skeleton is broken. Here
   the revealed region is a half-plane advancing along each line's own measured
   baseline slant, so what is visible is always one connected sweep and a
   fragment is geometrically impossible. Each line writes in turn, left to
   right, with a soft leading edge so the ink arrives under a nib rather than
   behind a hard wipe. */
/* ---- the draw-on ----
   The still IS the animation's final frame, at identical dimensions, stacked in
   the same box. There is nothing to align: the swap is the same pixels. */
.optical-mark {
  position: relative;
  display: block;
  width: 100%;
}

.optical-mark-base,
.optical-draw-vid {
  display: block;
  width: 100%;
  height: auto;
  max-width: none;
}

.optical-draw-vid {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
}

/* The mark is decoration: it writes itself over a page that is already alive. */
.optical-stage.is-intro .optical-mark-base { opacity: 0; }
.optical-stage.is-intro .optical-draw-vid { opacity: 1; }

/* The keyed canvas stands in for the video: same box, same artwork, but with
   real alpha recovered from the black-backed frames (js/wordmark-draw.js).
   The <video> itself is never shown -- it is only a texture source. */
.optical-draw-canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: auto;
  max-width: none;
  opacity: 0;
  pointer-events: none;
}

.optical-stage.is-keyed .optical-draw-vid { opacity: 0 !important; }
.optical-stage.is-intro.is-keyed .optical-draw-canvas { opacity: 1; }

.optical-stage.is-intro .optical-mark-base {
  animation: mh-draw-floor 200ms linear 4980ms both;
}

@keyframes mh-draw-floor {
  from { opacity: 0; }
  to { opacity: 1; }
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ------------------------------------------------------------- the intro */
/* First paint of the session: true black, nothing but the mark writing on.
   The planes, masters and nav are held dark, then actualize one at a time
   (delays assigned inline by optical-home.js). */
.optical-stage.is-intro {
  background: var(--black, #0b0f0d);
}

.optical-stage.is-intro::before {
  opacity: 0;
}

/* The nav and the controls are there from the first frame: the visitor can
   leave immediately, and the mark writing itself is decoration over a page
   that is already working. Only the film planes wait, and only briefly. */
.optical-stage.is-intro .optical-plane,
.optical-stage.is-intro .optical-master {
  opacity: 0;
}

/* Same dissolve as the curtains, so the two viewport paths read identically —
   see .optical-curtain for why this curve is not the site's standard ease. */
.optical-stage.is-intro .optical-plane.is-actual {
  opacity: 1;
  transition: opacity 1100ms cubic-bezier(0.45, 0.05, 0.55, 0.95);
}

/* Master-viewport actualization: the PLAYING master is painted in full and hidden
   behind opaque, shard-shaped CURTAINS that optical-home.js fades out one beat at
   a time. The master carrying .is-reveal is visible from the first frame; what
   the visitor sees is the curtains. Planes (non-master viewports) pop with their
   videos already running.

   This replaced an SVG mask reference, which Safari would not animate — it held
   the card black for the whole run and then committed every shard in a single
   frame. A clip-path polygon is the same primitive the tessellation and the nav
   chevrons already use, and it is honoured everywhere. */
.optical-stage.is-intro .optical-master.is-reveal {
  opacity: 1;
}

.optical-curtain-layer {
  position: absolute;
  inset: 0;
  /* above the master's halftone (3) and its grain (4) — a curtain hides the
     shard's full treatment, not just its footage */
  z-index: 9;
  pointer-events: none;
}

.optical-curtain {
  position: absolute;
  inset: 0;
  /* Under .is-intro the stage drops its grain for flat --black and holds its
     halftone at zero, so a flat fill is an exact match for the ground the
     curtains stand in for. */
  background: var(--black, #080b0a);
  opacity: 1;
  /* A DISSOLVE, NOT AN ENTRANCE — which is why this is the one thing on the
     site that does not use --mh-ease. That curve is a hard ease-out: on a
     620ms dissolve it was 72% open inside the first 155ms, so a beat that
     measured 620ms read as a snap barely longer than a cut. An optical
     dissolve holds its middle, so this is a gentle sigmoid, nearly linear
     through the crossover, and long enough to be read as a dissolve at all. */
  transition: opacity 1100ms cubic-bezier(0.45, 0.05, 0.55, 0.95);
  will-change: opacity;
}

.optical-curtain.is-open {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .optical-curtain { transition: none; }
}

.optical-stage.is-intro .optical-nav.is-actual {
  opacity: 1;
}


.optical-nav {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 20;
  display: grid;
  grid-template-columns: 30.2% 38.4% 31.4%;
  height: var(--nav-height);
  min-height: var(--mh-bottom-nav-h);
  padding-bottom: env(safe-area-inset-bottom);
  background:
    url("../assets/brand/paper-grain.jpg") center / 512px auto,
    var(--black);
  background-blend-mode: soft-light;
  border-top: 4px solid var(--ember);
}

.optical-nav::before,
.optical-nav::after {
  position: absolute;
  top: -4px;
  bottom: 0;
  width: 2.15cqw;
  min-width: 1.15rem;
  max-width: 2.4rem;
  content: "";
  background: var(--ember);
  clip-path: polygon(38% 0, 100% 0, 61% 100%, 0 100%);
  pointer-events: none;
}

.optical-nav::before {
  left: 29.2%;
}

.optical-nav::after {
  left: 67.7%;
}

.optical-nav a {
  display: grid;
  place-items: center;
  min-width: 0;
  color: var(--cream);
  font-family: var(--font-display, "Arial Narrow", sans-serif);
  font-size: var(--mh-nav-size);
  font-stretch: var(--mh-nav-stretch);
  font-weight: var(--mh-nav-weight);
  font-variation-settings: "wdth" 66;
  line-height: 1;
  letter-spacing: var(--mh-nav-tracking);
  -webkit-text-stroke-width: 0;
  -webkit-text-stroke-color: currentColor;
  text-decoration: none;
  text-transform: uppercase;
  transition:
    color 160ms linear,
    background-color 160ms linear,
    font-weight 220ms var(--mh-nav-ease),
    -webkit-text-stroke-width 220ms var(--mh-nav-ease);
}

.optical-nav a:nth-child(1) {
  text-indent: -1.2cqw;
}

.optical-nav a:nth-child(2) {
  text-indent: -2.7cqw;
}

.optical-nav a:nth-child(3) {
  text-indent: 0.7cqw;
}

.optical-nav a:hover,
.optical-nav a:focus-visible {
  color: #fff3e2;
  background-color: rgba(239, 92, 50, 0.13);
  font-weight: var(--mh-nav-hover-weight);
  -webkit-text-stroke-width: 0.012em;
}

.optical-nav a:focus-visible {
  outline: 3px solid var(--cream);
  outline-offset: -0.55rem;
}

@media (max-aspect-ratio: 4 / 5) {
  .optical-stage {
    --nav-height: var(--mh-bottom-nav-h);
    background-size: 512px auto;
  }

  .optical-plane--car {
    --plane-cut: polygon(52% 0%, 100% 0%, 100% 38%, 82% 29%, 61% 34%, 35% 26%);
  }

  .optical-plane--storm {
    --plane-cut: polygon(0% 28%, 35% 26%, 61% 34%, 50% 56%, 27% 60%, 0% 55%);
  }

  .optical-plane--industry {
    --plane-cut: polygon(61% 34%, 82% 29%, 100% 38%, 100% 52%, 77% 62%, 50% 56%);
  }

  .optical-plane--fire {
    --plane-cut: polygon(0% 55%, 27% 60%, 50% 56%, 35% 89.6%, 0% 89.6%);
  }

  .optical-plane--spark {
    --plane-cut: polygon(50% 56%, 77% 62%, 70% 89.6%, 35% 89.6%);
  }

  .optical-plane--valiant {
    --plane-cut: polygon(77% 62%, 100% 52%, 100% 89.6%, 70% 89.6%);
  }

  .optical-plane--world {
    --shot-x: 54%;
    --shot-y: 44%;
    --shot-scale: 1;
    --shot-shift-x: -4%;
    --shot-shift-y: 6%;
  }

  .optical-plane--car {
    --shot-x: 43%;
    --shot-y: 36%;
    --shot-scale: 1;
    --shot-shift-x: 33.34%;
    --shot-shift-y: -16.24%;
  }

  .optical-plane--storm {
    --shot-x: 45%;
    --shot-y: 40%;
    --shot-scale: 1.02;
    --shot-shift-x: -17.34%;
    --shot-shift-y: 3.37%;
  }

  .optical-plane--industry {
    --shot-x: 56%;
    --shot-y: 46%;
    --shot-scale: 1.02;
    --shot-shift-x: 20.22%;
    --shot-shift-y: -1.77%;
  }

  .optical-plane--fire {
    --shot-x: 47%;
    --shot-y: 45%;
    --shot-scale: 0.78;
    --shot-shift-x: -24%;
    --shot-shift-y: 26.34%;
  }

  .optical-plane--spark {
    --shot-x: 30%;
    --shot-y: 38%;
    --shot-scale: 1;
    --shot-shift-x: 28.78%;
    --shot-shift-y: 35.41%;
  }

  .optical-plane--valiant {
    --shot-x: 34%;
    --shot-y: 38%;
    --shot-scale: 0.7;
    --shot-shift-x: 45.35%;
    --shot-shift-y: 29.86%;
  }

  .optical-title {
    padding: 0 0 var(--nav-height, 4.75rem);
  }

  .optical-stage .motion-toggle {
    top: max(0.8rem, env(safe-area-inset-top));
    right: 5.5cqw;
  }

  .optical-wordmark {
    position: static;
    width: min(86cqw, 48cqh);
  }

  .optical-nav {
    grid-template-columns: repeat(3, 1fr);
    min-height: var(--mh-bottom-nav-h);
  }

  .optical-nav::before {
    left: 31.8%;
  }

  .optical-nav::after {
    left: 65.1%;
  }

  .optical-nav a,
  .optical-nav a:nth-child(1),
  .optical-nav a:nth-child(2),
  .optical-nav a:nth-child(3) {
    font-size: var(--mh-nav-size);
    letter-spacing: var(--mh-nav-tracking);
    text-indent: 0;
    transform: none;
  }
}

@media (max-height: 560px) and (min-aspect-ratio: 4 / 5) {
  .optical-nav a {
    font-size: 1.1rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .optical-master-poster,
  .optical-master-video,
  .optical-plane,
  .optical-poster,
  .optical-video,
  .optical-nav a {
    transition: none;
  }

  .optical-stage.is-intro .optical-draw-path {
    animation: none;
  }
}

@media (forced-colors: active) {
  .optical-master,
  .optical-plane {
    display: none;
  }

  .optical-stage,
  .optical-nav {
    color: CanvasText;
    background: Canvas;
  }

  .optical-nav a {
    color: CanvasText;
  }

  .optical-stage .motion-toggle {
    color: CanvasText;
    border-color: CanvasText;
  }

  .optical-nav::before,
  .optical-nav::after {
    background: Highlight;
  }
}

/* ------------------------------------------------------- the escape hatch */

/* The framed routes release to normal flow below 30rem of height (frame.css).
   The landing never got the same treatment, and its `min-height: 31rem` plus
   `overflow: hidden` meant that under ~496px of viewport the nav rail was laid
   out below the fold with no way to scroll to it: at 390x400 the home page had
   NO reachable navigation at all, and 320x256 is exactly the WCAG 1.4.10
   reflow case (1280x1024 at 400% zoom). The title card is the design; being
   stranded on it is not. */
@media (max-height: 30rem) {
  body.landing-page {
    overflow: auto;
  }

  .optical-stage {
    position: static;
    height: auto;
    min-height: 100svh;
    container-type: normal;
  }

  /* Every plane on the stage is absolutely positioned, so once the stage goes
     static the rail is its only in-flow child and floats to the TOP. Pin it to
     the viewport instead — which is where it sits at every other size anyway. */
  .optical-nav {
    position: fixed;
    inset: auto 0 0 0;
  }
}
