/* H5, the mosaic.
   After aralesk.es. The viewport is a grid of production stills. On load every
   tile turns over, and the far side of all of them together is one clapperboard:
   each back face holds the same drawing, sized to the whole grid and shifted by
   the tile's own column and row, so the board is cut by the grid rather than
   drawn into it. Scroll turns the grid back into pieces.
   Each still is drawn here, so the whole wall costs no requests. */

.hero-mosaic {
  position: relative;
  min-height: 100svh;
  overflow: clip;
  isolation: isolate;
  display: grid;
  background: var(--bg-deep);

  --cols: 6;
  --rows: 4;
}

/* ---- the wall ---- */

.hm__grid {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: grid;
  grid-template-columns: repeat(var(--cols), 1fr);
  grid-template-rows: repeat(var(--rows), 1fr);
  gap: 2px;
  perspective: 1400px;
  background: var(--ink);
}

.hm__tile {
  position: relative;
  transform-style: preserve-3d;
  will-change: transform;
}

.hm__face,
.hm__back {
  position: absolute;
  inset: 0;
  overflow: hidden;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
.hm__back { transform: rotateY(180deg); background: var(--bg-deep); }

.hm__face svg { width: 100%; height: 100%; }

/* The back faces share one drawing: full grid size, shifted into place.
   base.css caps every svg at max-width 100%, which would pin the drawing to one
   tile and defeat the whole trick, so this one opts out. */
.hm__board {
  position: absolute;
  max-width: none;
  width: calc(var(--cols) * 100%);
  height: calc(var(--rows) * 100%);
  left: calc(var(--c) * -100%);
  top: calc(var(--r) * -100%);
}

/* ---- the drawn stills ---- */

.hm-ink    { fill: var(--ink); }
.hm-deep   { fill: var(--bg-deep); }
.hm-paper  { fill: var(--paper); }
.hm-teal   { fill: var(--teal); }
.hm-tealD  { fill: var(--teal-deep); }
.hm-tint   { fill: var(--teal-tint); }
.hm-signal { fill: var(--signal); }
.hm-line   { stroke: var(--teal-tint); fill: none; stroke-width: 2; }
.hm-rule   { fill: var(--ink); opacity: 0.32; }
.hm-soft   { fill: var(--paper); opacity: 0.2; }

/* the story wall (clap mode): words a crew would read off a screen or a sheet */
.hm-mono   { font-family: var(--mono); font-weight: 500; }
.hm-disp   { font-family: var(--display); font-weight: 900; }
.hm-ar     { font-family: var(--display); font-weight: 700; }
.hm-tealT  { fill: var(--teal); }
.hm-stroke-p { fill: none; stroke: var(--paper); stroke-width: 1; }
.hm-stroke-i { fill: none; stroke: var(--ink); stroke-width: 1; }
.hm-stroke-t { fill: none; stroke: var(--teal); stroke-linecap: round; stroke-linejoin: round; }

/* ---- the board the tiles become ---- */

.hm__board .b-body  { fill: var(--teal); }
.hm__board .b-edge  { fill: var(--teal-deep); }
.hm__board .b-label { fill: var(--paper); opacity: 0.55; }
.hm__board .b-value { fill: var(--paper); }
.hm__board .b-rule  { stroke: var(--paper); stroke-opacity: 0.3; stroke-width: 2; }
.hm__board .b-stripe-a { fill: var(--paper); }
.hm__board .b-stripe-b { fill: var(--ink); }

/* ---- the words, which never depend on the picture behind them ---- */

.hm__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* Enough to hold the type against a paper tile, not so much that the board
     the wall just became stops being visible. */
  background:
    radial-gradient(ellipse 70% 56% at 50% 50%, color-mix(in srgb, var(--ink) 26%, transparent) 0%, transparent 74%),
    linear-gradient(to bottom, color-mix(in srgb, var(--ink) 52%, transparent) 0%, transparent 30%, color-mix(in srgb, var(--ink) 78%, transparent) 100%);
}

.hm__plate {
  position: relative;
  z-index: 2;
  align-self: center;
  justify-self: center;
  width: min(100% - var(--gut) * 2, 820px);
  padding-block: clamp(1.5rem, 4svh, 2.75rem);
  text-align: center;
}

.hm__title {
  font-size: clamp(2rem, 5.6vw, 4.5rem);
  color: var(--paper);
  text-shadow: 0 2px 30px color-mix(in srgb, var(--ink) 55%, transparent);
}

.hm__ar {
  margin-top: clamp(0.5rem, 1.6vh, 0.9rem);
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.1rem, 2.3vw, 1.8rem);
  line-height: 1.5;
  color: var(--teal-pale);
}

.hm__lede {
  margin: clamp(0.9rem, 2.4vh, 1.5rem) auto 0;
  max-width: 56ch;
  font-size: var(--t-base);
  line-height: 1.6;
  color: color-mix(in srgb, var(--paper) 78%, transparent);
}

.hm__ctas {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem;
  margin-top: clamp(1.2rem, 3vh, 2rem);
}
.hm__ctas .btn { --btn-bg: var(--paper); --btn-fg: var(--ink); }
.hm__ctas .btn--ghost {
  --btn-bg: transparent;
  --btn-fg: color-mix(in srgb, var(--paper) 74%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--paper) 26%, transparent);
}
.hm__ctas .btn--ghost:hover { --btn-fg: var(--paper); }

@media (max-width: 1100px) { .hero-mosaic { --cols: 4; --rows: 5; } }
@media (max-width: 640px)  { .hero-mosaic { --cols: 3; --rows: 6; } }

/* Reduced motion, and the moment before GSAP has run: the wall is already the
   board and the words are already there. Nothing to wait for. */
.hero-mosaic.is-still .hm__tile { transform: rotateY(180deg); }

/* ---- data-clap="scroll" --------------------------------------------------
   The wall's top bar gets a stick that shuts as you scroll out of the hero,
   and the impact takes a single frame of white. Only this mode draws them. */
.hm__stick {
  position: absolute;
  z-index: 3;
  transform-origin: 0 100%;
  border-radius: 3px;
  background-color: var(--ink);
  background-image: repeating-linear-gradient(
    45deg,
    var(--paper) 0 var(--stripe-w, 14px),
    var(--ink) var(--stripe-w, 14px) calc(var(--stripe-w, 14px) * 2)
  );
  box-shadow: 0 10px 26px -10px rgba(0, 0, 0, .8);
  will-change: transform;
  pointer-events: none;
}
.hm__flash {
  position: absolute;
  inset: 0;
  z-index: 4;
  background: var(--paper);
  opacity: 0;
  mix-blend-mode: screen;
  pointer-events: none;
}
/* No JS and no motion: the board is simply shut, which is the finished state. */
.hero-mosaic.is-still .hm__stick { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .hm__stick { transform: none !important; }
  .hm__flash { display: none; }
}

/* ---- the printed plate (clap mode) ----------------------------------------
   Every back face carries the whole plate at the grid's own size, shifted by
   its column and row like the board, so the words are cut by the same gaps.
   It is sized in pixels from the grid (--gw, --gh) so it wraps exactly like
   the live plate, whose links sit on top of the printed ones. */
.hm__print {
  position: absolute;
  z-index: 1;
  left: calc(var(--c) * -100%);
  top: calc(var(--r) * -100%);
  width: var(--gw, calc(var(--cols) * 100%));
  height: var(--gh, calc(var(--rows) * 100%));
  display: grid;
  pointer-events: none;
}
.hm__plate--print .hm__title,
.hm__plate--print .hm__ar,
.hm__plate--print .hm__lede { display: block; }
.hm__plate--print .hm__title {
  font-family: var(--display);
  font-weight: 900;
  line-height: 0.96;
  letter-spacing: -0.03em;
  text-wrap: balance;
  /* Printed onto the board: a hairline of light on the top edge, a hard
     shadow under it, and a soft one where the board meets the room. */
  text-shadow:
    0 -1px 0 color-mix(in srgb, var(--paper) 24%, transparent),
    0 3px 0 color-mix(in srgb, var(--ink) 38%, transparent),
    0 16px 30px color-mix(in srgb, var(--ink) 45%, transparent);
}
.hm__plate--print .hm__lede { text-wrap: pretty; text-shadow: 0 1px 0 color-mix(in srgb, var(--ink) 40%, transparent); }
.hm__plate--print .hm__ar { text-shadow: 0 2px 0 color-mix(in srgb, var(--ink) 35%, transparent); }
/* The printed links only hold their place; the live ones are the real thing. */
.hm__plate--print .hm__ctas { visibility: hidden; }

/* The live plate keeps its words for screen readers and search, and shows
   only its links. The veil is not needed: nothing busy sits behind the words
   any more, only the board. */
.has-print .hm__plate--live :is(.hm__title, .hm__ar, .hm__lede) { opacity: 0; }
.has-print .hm__veil { display: none; }

/* ---- texture and depth (clap mode) -----------------------------------------
   Each tile is a physical block: a hairline of light on its top left edge,
   shade on the bottom right, a little falloff into the corners, and a fine
   grain over the lot so the flat colour reads as a printed surface. The grain
   is a mask, so its colour still comes from the tokens. */
.hero-mosaic[data-clap='scroll'] :is(.hm__face, .hm__back)::before,
.hero-mosaic[data-clap='scroll'] :is(.hm__face, .hm__back)::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.hero-mosaic[data-clap='scroll'] :is(.hm__face, .hm__back)::before {
  z-index: 3;
  box-shadow:
    inset 1px 1px 0 color-mix(in srgb, var(--paper) 18%, transparent),
    inset -1px -1px 0 color-mix(in srgb, var(--ink) 60%, transparent),
    inset 0 0 18px color-mix(in srgb, var(--ink) 24%, transparent);
}
.hero-mosaic[data-clap='scroll'] :is(.hm__face, .hm__back)::after {
  z-index: 4;
  background: var(--paper);
  opacity: 0.1;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.7 0 0 0 -.6'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.7 0 0 0 -.6'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  -webkit-mask-size: 180px;
          mask-size: 180px;
}
/* The bar's own shadow on the body, so the stripes sit proud of the board. */
.hm__board .b-shade { fill: var(--ink); opacity: 0.35; }
/* Set by settle() so no seam runs through a line of the printed words. */
.has-print .hm__plate { top: var(--plate-dy, 0px); }
/* On the board side the seams cut through type, so the bevel is only a
   hairline: enough to read as separate blocks, not enough to bite letters. */
.hero-mosaic[data-clap='scroll'] .hm__back::before {
  box-shadow:
    inset 1px 1px 0 color-mix(in srgb, var(--paper) 12%, transparent),
    inset -1px -1px 0 color-mix(in srgb, var(--ink) 45%, transparent);
}
