/*
   Multi-Hyphenate — the frame.

   Every page is one viewport bounded below by the nav rail, and nothing
   scrolls: information is reached by pressing chips and glyphs, not by
   dragging. This generalizes the geometry the landing already proves
   (see landing.css `.optical-stage`) so all six routes share it.

   The escape hatch is not optional. A hard no-scroll frame fails WCAG 1.4.10
   reflow the moment a reader zooms, lands on a short viewport, or runs a
   larger default font — and the landing's own `min-height: 31rem` already
   clips below ~496px of viewport height. So the content region is `auto`,
   not `hidden`: when the content fits, no scrollbar exists and the frame
   reads exactly as designed; when it genuinely cannot fit, the region
   scrolls instead of swallowing the overflow. Fixed-frame is the intended
   experience. It is never a trap.
*/

body.mh-framed {
  margin: 0;
  overflow: hidden;
  /* chrome.css pads the body for the fixed rail; inside the frame the rail is
     part of the layout, so that padding would double-count. */
  padding-bottom: 0;
}

.mh-frame {
  /* The landing is the rail's ground truth, and it never loads chrome.css — so
     its rail resolves `8.2cqh` against the stage's size container, while these
     pages resolved chrome.css's `:root` clamp instead. Two different formulas,
     so the rail quietly changed height between the landing and everywhere
     else. `.mh-frame` is a size container of the same dimensions as the stage,
     so restating the landing's own expression here makes the two agree
     exactly. The floor is kept: a rail is a touch target before it is a rule. */
  --nav-height: var(--mh-bottom-nav-h);
  --frame-gutter: clamp(1.25rem, 4.4vw, 4rem);
  position: fixed;
  inset: 0;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  width: 100%;
  height: 100svh;
  height: 100dvh;
  overflow: hidden;
  isolation: isolate;
  container-type: size;
  background-color: var(--mh-ink, #062b30);
  background-image: url("../assets/brand/paper-grain.jpg");
  background-position: center;
  background-size: 512px auto;
  background-blend-mode: soft-light;
}

/*
   The WebGL2 ink field. js/ink-field.js appends this canvas to [data-ink-field]
   and adds .is-inked once the first frame is drawn; it bails on reduced motion,
   save-data, a paused toggle, or any WebGL failure, and the frame's own colour
   and grain stay painted underneath. The field is an enhancement, never a
   dependency.

   These rules live here rather than in system.css because the framed pages no
   longer load system.css — without them the canvas mounts as a static grid item
   and takes a row of the layout.
*/
.mh-ink-canvas {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0;
  pointer-events: none;
  transition: opacity 900ms cubic-bezier(0.32, 0.72, 0, 1);
}

[data-ink-field].is-inked .mh-ink-canvas {
  opacity: 1;
}

/* Everything else in the frame rides above the field. */
[data-ink-field] > *:not(.mh-ink-canvas) {
  position: relative;
  z-index: 1;
}

@media (prefers-reduced-motion: reduce) {
  .mh-ink-canvas { display: none; }
}

/* The content region: the frame minus the rail. */
.mh-frame-content {
  position: relative;
  z-index: 2;
  min-height: 0; /* lets the grid row actually shrink, so `auto` can engage */
  padding: clamp(1rem, 3.2svh, 2.6rem) var(--frame-gutter);
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-gutter: stable;
}

.mh-frame-content::-webkit-scrollbar {
  width: 6px;
}

.mh-frame-content::-webkit-scrollbar-thumb {
  border-radius: 3px;
  background: rgb(232 214 191 / 0.24);
}

.mh-frame-content::-webkit-scrollbar-track {
  background: transparent;
}

/* The rail is the absolute lower limit of every page: a laid-out grid row,
   never an absolutely-positioned overlay. Content cannot render beneath it. */
.mh-frame-rail {
  position: relative;
  z-index: 3;
  min-height: var(--nav-height);
  padding-bottom: env(safe-area-inset-bottom);
}

/*
   Short viewports and high zoom: below this height the frame has less room
   than its own chrome needs, so it stops pretending. The page returns to
   normal document flow and scrolls as an ordinary page would.
*/
@media (max-height: 30rem) {
  body.mh-framed {
    overflow: auto;
  }

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

  .mh-frame-content {
    overflow: visible;
  }
}

/* Same release when a coarse pointer meets a very short window — the usual
   signature of a phone in landscape, where a fixed frame leaves nothing
   readable between the rail and the top edge. */
@media (max-height: 26rem) and (pointer: coarse) {
  .mh-frame {
    min-height: 0;
  }
}

/* Motion inside the frame is choreography, not decoration; it obeys the
   site-wide pause toggle as well as the OS setting. */
@media (prefers-reduced-motion: reduce) {
  .mh-frame-content {
    scroll-behavior: auto;
  }
}

/* THE MOTION TOGGLE lives in the top-right corner, the same place the landing
   puts it. base.css positions it bottom-left as a small round glyph pinned to
   the rail — which inside the frame drops it INTO the nav bar. The landing is
   the ground truth for chrome, so the framed routes wear the landing's
   treatment: textual, right-aligned, ruled underneath. */
body.mh-framed .motion-toggle {
  position: fixed;
  top: max(1rem, env(safe-area-inset-top));
  right: var(--frame-gutter, clamp(1.25rem, 4.4vw, 4rem));
  bottom: auto;
  left: auto;
  z-index: 40;
  width: fit-content;
  height: auto;
  min-width: 0;
  min-height: 2.75rem;
  padding: 0.45rem 0 0.35rem;
  color: var(--paper, #f4ecdf);
  background: transparent;
  clip-path: none;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-align: right;
  transform: none;
  border: 0;
  border-bottom: 1px solid rgb(244 236 223 / 0.52);
}

body.mh-framed .motion-toggle::before { content: none; }

body.mh-framed .motion-toggle:hover,
body.mh-framed .motion-toggle:focus-visible {
  color: #fff3e2;
  border-bottom-color: #fff3e2;
}

body.mh-framed .motion-toggle[aria-pressed="true"] {
  color: var(--mh-nav-accent);
  border-bottom-color: var(--mh-nav-accent);
}

/* THE CORNER WORDMARK is a link home on every framed route — the landing IS
   home, so it carries no such link, and this stylesheet never reaches it.
   Hovering lifts the mark into the accent so it reads as clickable rather than
   as decoration. Focus gets the same treatment, so it is not mouse-only. */
.mh-page-mark img,
.film-wordmark img {
  transition: filter 220ms cubic-bezier(0.32, 0.72, 0, 1);
}

.mh-page-mark:hover img,
.mh-page-mark:focus-visible img,
.film-wordmark:hover img,
.film-wordmark:focus-visible img {
  filter:
    drop-shadow(0 0 6px rgb(239 92 50 / 0.6))
    drop-shadow(0 0 20px rgb(239 92 50 / 0.38))
    saturate(1.22) brightness(1.08);
}

/* The ring still belongs to keyboard users; the glow is additional, not a
   replacement for it. */
.mh-page-mark:focus-visible,
.film-wordmark:focus-visible {
  outline: 3px solid var(--mh-nav-accent, #ef5c32);
  outline-offset: 6px;
}

@media (prefers-reduced-motion: reduce) {
  .mh-page-mark img,
  .film-wordmark img { transition: none; }
}

/* THE CORNER WORDMARK SIZE, defined once for every framed route. Works styled
   it as `.film-wordmark` and the other four as `.mh-page-mark`, each with its
   own width — so the logo changed size when you moved between pages. The
   body-scoped selector wins over the per-page stylesheets, which load after
   this one. */
body.mh-framed .mh-page-mark,
body.mh-framed .film-wordmark {
  display: block;
  width: clamp(6.6rem, 9cqw, 9rem);
  line-height: 0;
  /* Works nests the mark in a centred two-row header, so its top drifted with
     the header's height while the other four sit flush to the content padding.
     Top-align it and the mark lands in the same place on every route. */
  align-self: start;
}

body.mh-framed .mh-page-mark img,
body.mh-framed .film-wordmark img {
  width: 100%;
  height: auto;
}

/* =================================================== accessibility polish ==
   Findings from the pre-ship audit, fixed once here rather than four times in
   four page stylesheets — the same split-definition habit that let the rail,
   the toggle and the wordmark drift apart earlier.
   ========================================================================== */

/* CONTRAST. The colophon carried three different alphas across four routes
   (0.42 / 0.45 / 0.5), and the two lowest measured 3.50:1 and 3.83:1 against
   4.5:1. One value, comfortably over the line, everywhere. */
body.mh-framed .film-colophon,
body.mh-framed .mh-colophon-line,
body.mh-framed .mh-coda .mh-colophon-line {
  color: rgb(244 236 224 / 0.62);
}

body.mh-framed .film-colophon a,
body.mh-framed .mh-colophon-line a,
body.mh-framed .mh-coda .mh-colophon-line a {
  color: rgb(244 236 224 / 0.82);
}

/* TAP TARGETS. Several controls render well under the 24x24 WCAG 2.2 floor —
   Contact's "X" link is 9.5px wide, and the Works pager arrows are the only
   route to films 6-30 on touch. Expanding the HIT AREA with a pseudo-element
   rather than the box keeps every layout exactly as designed: nothing moves,
   the finger just gets somewhere to land. */
body.mh-framed .mh-social a,
body.mh-framed .film-colophon a,
body.mh-framed .mh-colophon-line a,
body.mh-framed .fm-step,
body.mh-framed .fm-toggle,
body.mh-framed .film-chips button {
  position: relative;
}

body.mh-framed .mh-social a::after,
body.mh-framed .film-colophon a::after,
body.mh-framed .mh-colophon-line a::after,
body.mh-framed .fm-step::after,
body.mh-framed .fm-toggle::after,
body.mh-framed .film-chips button::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
  /* hit area only: never paints, never intercepts the element's own styling */
  pointer-events: auto;
}

/* The social links sit shoulder to shoulder; without a gap their expanded hit
   areas would overlap and the wrong one would win. */
body.mh-framed .mh-social {
  gap: max(0.9rem, 12px);
}
