/* ---------------------------------------------------------------
   How Wes Anderson Makes Movies — hero
   --------------------------------------------------------------- */

@font-face {
  font-family: "Futura PT";
  src: url("assets/fonts/futura-pt-book.otf") format("opentype");
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "Tilda Petite";
  src: url("assets/fonts/tilda-petite.ttf") format("truetype");
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "Futura PT Condensed";
  src: url("assets/fonts/futura-pt-cond-bold.otf") format("opentype");
  font-weight: 700;
  font-display: swap;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

/* the zoom is driven by scroll gestures, not by scrolling the page, so the
   page itself never moves and no scroll bar appears */
html,
body {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  scrollbar-width: none;
  /* every gesture drives the page's own scenes: no browser panning, pinch,
     pull-to-refresh or bounce getting in the way on touch screens */
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
}

/* no "save image" callout or ghost drag on a long press */
img,
video,
canvas {
  -webkit-touch-callout: none;
  -webkit-user-drag: none;
  user-select: none;
}

html::-webkit-scrollbar { display: none; }

body {
  margin: 0;
  background: #b36041;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  color: #2b1c14;
}

/* --- hero shell ------------------------------------------------ */

.hero {
  position: relative;
  width: 100%;
  height: 100svh;
  min-height: 100svh;
  overflow: hidden;
  display: flex;
  justify-content: center;
  /* headline sits in the sky, above the mountains */
  padding: clamp(2rem, 6vh, 6rem) clamp(1rem, 4vw, 5rem) 0;
}

.hero__cover {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 100%;
  z-index: 0;
  user-select: none;
  pointer-events: none;
}

/* the zoom frames are drawn on a canvas laid exactly over the cover (same
   crop rules); it takes over from the cover once the first frame is drawn */
.hero__zoom {
  opacity: 0;
  transition: opacity 0.12s linear;
}

.hero__zoom.is-active { opacity: 1; }

/* --- after the zoom: lobby, story, then the frame shrinks --------- */

/* behind the frame once it starts shrinking */
.hero__black {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: #000;
  opacity: 0;
  pointer-events: none;
}

/* 60% black over the lobby: fades in when the zoom lands (class), fades out
   as the frame shrinks (JS drives the inner fill) */
.shade {
  position: absolute;
  inset: 0;
  z-index: 1;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s ease;
}

.shade__fill {
  position: absolute;
  inset: 0;
  background: #000;
  opacity: 0.6;
}

.hero.is-post .shade {
  opacity: 1;
  transition: opacity 1s ease 0.1s;
}

/* The story is laid out on a stage with the proportions of the reference
   draft (1573 x 798). One unit, --u, is 1% of the stage width, and the
   stage is as large as fits the screen, so the title, text and map keep
   the draft's sizes and positions on any screen shape. Phones stack. */
.story {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  color: #f3ece1;
  pointer-events: none;
  will-change: transform;
  /* 15% larger than the draft relative to the screen. The stage itself then
     overflows, but its content spans only 12-88% of it, so everything stays
     on screen. Capped at 23px so it stops growing on very large screens */
  --u: min(1.15vw, calc(100svh / 50.73 * 1.15), 23px);
}

.hero.is-post .story { pointer-events: auto; }

.story__stage {
  position: relative;
  flex: none;
  width: calc(100 * var(--u));
  height: calc(50.73 * var(--u));
  /* centred across, but sits high: 22% of any spare height goes above it, 78% below */
  margin-top: max(0px, calc((100svh - 50.73 * var(--u)) * 0.22));
}

.story__title {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(4.2 * var(--u));
  margin: 0;
  font-family: "Futura PT Condensed", "Futura", "Avenir Next Condensed", "Arial Narrow", sans-serif;
  font-weight: 700;
  font-size: calc(8.9 * var(--u));
  line-height: 1;
  letter-spacing: 0.01em;
  text-align: center;
  white-space: nowrap;
  color: #f5bd02;
}

.story__text {
  position: absolute;
  left: calc(11.95 * var(--u));
  top: calc(21.1 * var(--u));
  /* 22.58em reproduces the draft's line breaks exactly (valid 22.42-22.74em) */
  width: 22.58em;
  margin: 0;
  font-family: "Futura PT", "Futura", "Century Gothic", "Trebuchet MS", sans-serif;
  font-size: calc(1.618 * var(--u));
  line-height: 1.24;
}

.story__map {
  position: absolute;
  left: calc(65.9 * var(--u));
  top: calc(19.2 * var(--u));
  width: calc(22.3 * var(--u));
  margin: 0;
}

.story__map img {
  display: block;
  width: 100%;
  height: auto;
  box-shadow: 0 calc(0.8 * var(--u)) calc(1.6 * var(--u)) rgba(0, 0, 0, 0.45);
}

/* all three arrive together; leaving is quick */
.story__title,
.story__text,
.story__map {
  opacity: 0;
  translate: 0 1.25rem;
  transition: opacity 0.3s ease, translate 0.3s ease;
}

.hero.is-post .story__title,
.hero.is-post .story__text,
.hero.is-post .story__map {
  opacity: 1;
  translate: 0 0;
  transition: opacity 0.8s ease 0.35s, translate 0.9s cubic-bezier(0.2, 0.8, 0.25, 1) 0.35s;
}

@media (prefers-reduced-motion: reduce) {
  .story__title, .story__text, .story__map { translate: 0 0; }
}

/* phones and tablets held upright: one column, words above pictures.
   Held sideways they keep the side-by-side layout, scaled to the height */
@media (orientation: portrait) and (max-width: 1100px) {
  .story { align-items: flex-start; }
  /* title, words and map share one column, left and right edges alike */
  .story__stage {
    container-type: inline-size; /* the title is sized off this column */
    width: 100%;
    max-width: 32rem;
    box-sizing: border-box;
    height: auto;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    padding: 4.5rem 1.5rem 3rem;
  }
  .story__title,
  .story__text,
  .story__map { position: static; }
  /* the title's letters span the column exactly: the column's own width
     over the letters' inked width in ems (5.72); the box overhangs by the
     glyphs' own side space. (The column, not the screen: a screen width can
     include a scroll bar on some computers, and the title would overshoot) */
  .story__title {
    font-size: calc(100cqw / 5.72);
    margin: 0 -0.177em 0 -0.063em; /* more side space after the S than before the H */
    white-space: nowrap;
    text-align: center;
  }
  /* the words and gaps scale with the column like the title does, so the
     block keeps its proportions at any width (16.8px text on a 375px phone) */
  .story__text { width: auto; margin-top: calc(100cqw * 0.098); font-size: clamp(15px, 100cqw / 19.5, 26px); line-height: 1.5; text-align: center; }
  .story__map { width: 100%; margin-top: calc(100cqw * 0.122); }
}

/* --- the reel: two film stills, a sentence, a card --------------- */

/* JS places it exactly over the 1.85:1 frame the lobby shrinks into, and
   grows it to the full page at the end. Its type is sized in cqw (1% of
   its own width), so the text always fills the frame the way the drafts do */
.reel {
  position: absolute;
  z-index: 3;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  overflow: hidden;
  visibility: hidden;
  pointer-events: none;
  container-type: size;
}

.reel__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
}

.reel__img { object-fit: cover; display: block; }

.reel__line {
  position: absolute;
  inset: 0;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-family: "Futura PT Condensed", "Futura", "Avenir Next Condensed", "Arial Narrow", sans-serif;
  font-weight: 700;
  text-transform: uppercase;
  color: #fff;
}

.reel__line {
  font-size: 6.8cqw;
  line-height: 0.98;
  text-shadow: 0 0.15cqw 0.6cqw rgba(0, 0, 0, 0.25);
}

.reel__word { opacity: 0; }

/* --- the split: the full-page card parts to reveal a still --------- */

/* two copies of the full-page card, one showing only its top half and one
   only its bottom half; JS slides them apart with the scroll while the
   still behind them zooms out */
.split {
  position: absolute;
  inset: 0;
  z-index: 4;
  overflow: hidden;
  visibility: hidden;
  pointer-events: none;
  /* transparent while the picture is framed on black; JS paints it white for
     the closing screen */
  background: transparent;
}

/* the last video: 121 frames drawn here, framed at first and then filling
   the page, played by scroll exactly like the zoom in the first section */
.split__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* --- the closing screens ------------------------------------------- */

/* Three sections on white, stacked one screen apart and scrolled as a block.
   Each is laid out on a stage with the draft's proportions (1483 x 748), so
   the picture and type keep their sizes against each other on any screen. */
.pages {
  position: absolute;
  inset: 0;
  z-index: 5;
  /* no background here: the container covers the whole screen and would hide
     the canvas that draws the first picture. Each screen paints its own white */
  color: #101010;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  will-change: transform;
  --u: min(1vw, calc(100svh / 50.44), 20px);
}

.page {
  position: relative;
  /* shorter than the screen, so the three sit closer as the block scrolls.
     The spare pixel and negative margin let them overlap by a hair, so
     rounding can never leave a seam line between them */
  height: calc(76svh + 1px);
  min-height: calc(76svh + 1px);
  margin-bottom: -1px;
  /* each screen paints its own white: the block scrolls, so the container's
     own background would slide away and reveal the card underneath */
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
}

.page__stage {
  position: relative;
  flex: none;
  width: calc(100 * var(--u));
  height: calc(50.44 * var(--u));
}

/* the picture sits where the video settles; the flipped section mirrors it */
/* The picture and the words share one vertical centre line: both are
   centred on the middle of the stage, so they stay aligned with each other
   however long each section's paragraph is. */
.page__img {
  position: absolute;
  left: calc(48.79 * var(--u));
  top: calc(50% - 27.81 * var(--u) / 2);
  width: calc(48.64 * var(--u));
  height: calc(27.81 * var(--u));
  object-fit: cover;
  display: block;
}

.page__copy {
  position: absolute;
  left: calc(4.72 * var(--u));
  top: 50%;
  transform: translateY(-50%);
}

.page__title {
  margin: 0;
  font-family: "Futura PT Condensed", "Futura", "Avenir Next Condensed", "Arial Narrow", sans-serif;
  font-weight: 700;
  font-size: calc(7.3 * var(--u));
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
}

.page__text {
  margin: calc(2.49 * var(--u)) 0 0;
  font-family: "Futura PT", "Futura", "Century Gothic", "Trebuchet MS", sans-serif;
  /* never below 13px (a phone held sideways), and then never so wide that
     it reaches the picture */
  font-size: max(calc(1.464 * var(--u)), 13px);
  line-height: 1.2;
  /* 25.12em reproduces the draft's line breaks */
  width: min(25.12em, calc(41 * var(--u)));
}

/* Once the picture lands, the words and the other sections' pictures fade
   in. The layer itself never fades: the SYMMETRY picture hands over from the
   canvas to the still inside it, and must never pass through a half-see-
   through layer on the way, which read as a blank flash. */
.page__copy,
.page:not(:first-child) .page__img {
  opacity: 0;
  transition: opacity 0.35s ease;
}

.pages.is-landed .page__copy,
.pages.is-landed .page:not(:first-child) .page__img { opacity: 1; }

/* picture on the left, words on the right */
.page--flipped .page__img { left: calc(2.57 * var(--u)); }
.page--flipped .page__copy { left: calc(58.50 * var(--u)); }

/* the first picture is drawn on the canvas while it settles, so that screen
   stays see-through until the block starts scrolling; then the still takes
   over, in exactly the same place, and the screen paints its own white */
.pages .page:first-child .page__img { visibility: hidden; }
.pages:not(.is-scrolling) .page:first-child { background: transparent; }
.pages.is-scrolling .page:first-child .page__img { visibility: inherit; }

@media (orientation: portrait) and (max-width: 1100px) {
  /* on a phone each section is one full screen, its words and picture
     centred in it, so a section stop shows exactly one of them */
  .page {
    height: auto;
    min-height: calc(100svh + 1px);
    align-items: center;
    padding: 3rem 1.5rem;
    box-sizing: border-box;
  }
  .page__stage {
    width: 100%;
    max-width: 36rem;
    height: auto;
    display: flex;
    flex-direction: column;
  }
  .page__img,
  .page__copy { position: static; transform: none; }
  /* the same proportion as on large screens, whatever the file's own */
  .page__img { width: 100%; height: auto; aspect-ratio: 48.64 / 27.81; order: 2; margin-top: 1.75rem; }
  .page__copy { order: 1; }
  .page__title { font-size: clamp(2.5rem, 14vw, 4rem); }
  .page__text { width: auto; margin-top: 1rem; font-size: 1rem; line-height: 1.35; }
}

/* the same single column on an upright tablet, with a little more room */
@media (orientation: portrait) and (min-width: 701px) and (max-width: 1100px) {
  .page__text { font-size: 1.2rem; }
}

/* --- the very end ---------------------------------------------------- */

/* the same trick as the card split: two copies of what is on screen, one
   showing its top half and one its bottom, sliding apart with the scroll
   while the last still is revealed behind them and eases out of its zoom */
.split2 {
  position: absolute;
  inset: 0;
  z-index: 6;
  overflow: hidden;
  visibility: hidden;
  pointer-events: none;
  background: #000;
}

.split2__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transform: scale(1.3);
  will-change: transform;
}

.split2__end {
  position: absolute;
  left: 0;
  right: 0;
  top: 44%;
  margin: 0;
  transform: translateY(-50%);
  text-align: center;
  font-family: "Tilda Petite", "Snell Roundhand", cursive;
  font-weight: 400;
  font-size: 14.66vw;
  line-height: 1;
  color: #ffc20e;
  opacity: 0;
}

/* on a tall screen, set against the width alone it would look tiny */
@media (max-aspect-ratio: 1 / 1) {
  .split2__end { font-size: 27vw; }
}

.split2__half {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: #fff;
  will-change: transform;
}

.split2__half--top    { clip-path: inset(0 0 50% 0); }
.split2__half--bottom { clip-path: inset(50% 0 0 0); }

/* the clone of the closing screens inside each half */
/* 'inherit', never 'visible': a child forced visible shows through its
   hidden parent, which left these copies painted over the whole page —
   frozen on SYMMETRY — after a visit to the end and back */
.split2__half .pages {
  position: absolute;
  visibility: inherit;
  opacity: 1;
}

/* the headline rises and grows out of frame from its own centre. It must
   not stretch to the hero's full height, or 'its centre' becomes mid-screen */
.ransom {
  align-self: flex-start;
  transform-origin: 50% 50%;
}

/* --- ransom-note headline -------------------------------------- */

.ransom {
  position: relative;
  z-index: 1;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(0.95rem, 2.5vw, 2.85rem);
  width: 100%;

  /* one knob drives the whole headline; on short screens (a phone held
     sideways) the height caps it too, so it stays up in the sky */
  --cut: clamp(40px, min(8.6vw, 15svh), 160px);
}

.line {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: clamp(0.8rem, 2.35vw, 2.75rem);
}

.word {
  display: flex;
  align-items: flex-start;
}

.scrap {
  display: block;
  position: relative;
  z-index: var(--z, 1);
}

/* the layer the pointer actually grabs: hover scale + drag offset live
   here, kept clear of the entrance (.scrap) and the boil (img) so none
   of the three ever fight over `transform` */
.drag {
  display: block;
  cursor: grab;
  touch-action: none;
  transform: translate(var(--dx, 0px), var(--dy, 0px)) scale(var(--hs, 1));
  transition: transform 0.42s cubic-bezier(0.22, 1.2, 0.36, 1);
}

/* only where there's a real pointer: on touch, :hover sticks after a tap */
@media (hover: hover) {
  .drag:hover { --hs: 1.14; }
}

/* while held, the scrap tracks the pointer 1:1 and rides above the rest */
.drag.dragging {
  cursor: grabbing;
  transition: none;
}

.scrap.dragging { z-index: 999; }

.ransom img {
  display: block;
  height: var(--cut);
  width: auto;

  /* jitter distance tracks --cut so the boil reads the same at any size */
  --j: calc(var(--cut) * 0.030);

  transform:
    translateY(var(--y, 0px))
    rotate(var(--r, 0deg))
    scale(var(--s, 1));
  transform-origin: center center;
  user-select: none;
  -webkit-user-drag: none;
}

/* the paper scraps genuinely overlap, like real cut-outs */
/* matched to the visible paper edges: ~3px of paper overlap between letters */
.word .scrap + .scrap { margin-left: calc(var(--cut) * -0.123); }

/* --- motion: pop in from centre, then never stop moving --------- */

@media (prefers-reduced-motion: no-preference) {

  /* the wrapper pops (opacity + scale from its own centre) while the
     image inside boils — two elements, so neither waits on the other
     and both start at t=0 with no dead gap between them */
  .scrap {
    animation: pop 0.5s cubic-bezier(0.2, 1.1, 0.35, 1) both;
  }
  .ransom img {
    animation: boil var(--d, 1.7s) steps(1, end) var(--pd, 0s) infinite;
  }
  .ransom img.v2 { animation-name: boil-b; }
  .ransom img.v3 { animation-name: boil-c; }

  /* scale + fade only — no vertical travel, so the letter appears out
     of its own centre rather than dropping in from above */
  @keyframes pop {
    from { opacity: 0; transform: scale(0.82); }
    to   { opacity: 1; transform: scale(1); }
  }

  /* Three jitter loops so neighbouring scraps never move in unison.
     Each cycle is a chain of DISTINCT held poses at uneven intervals —
     a scrap snaps to a new angle and stays there until its next move,
     rather than springing back to where it started. Only one of the
     four poses per loop sits at the letter's base angle. Combined with
     a per-letter --d and --pd, few letters ever snap at the same beat. */
  @keyframes boil {
    0%   { transform: translate(0, var(--y, 0px)) rotate(var(--r, 0deg)) scale(var(--s, 1)); }
    26%  { transform: translate(calc(var(--j) *  0.62), calc(var(--y, 0px) + var(--j) * -0.70)) rotate(calc(var(--r, 0deg) + 5.4deg)) scale(calc(var(--s, 1) * 1.022)); }
    48%  { transform: translate(calc(var(--j) * -0.30), calc(var(--y, 0px) + var(--j) *  0.24)) rotate(calc(var(--r, 0deg) - 2.6deg)) scale(calc(var(--s, 1) * 0.988)); }
    80%  { transform: translate(calc(var(--j) *  0.18), calc(var(--y, 0px) + var(--j) *  0.58)) rotate(calc(var(--r, 0deg) + 3.1deg)) scale(calc(var(--s, 1) * 1.010)); }
  }

  @keyframes boil-b {
    0%   { transform: translate(calc(var(--j) * -0.68), calc(var(--y, 0px) + var(--j) *  0.58)) rotate(calc(var(--r, 0deg) - 5.8deg)) scale(calc(var(--s, 1) * 1.018)); }
    19%  { transform: translate(0, var(--y, 0px)) rotate(var(--r, 0deg)) scale(var(--s, 1)); }
    52%  { transform: translate(calc(var(--j) *  0.74), calc(var(--y, 0px) + var(--j) * -0.40)) rotate(calc(var(--r, 0deg) + 4.2deg)) scale(calc(var(--s, 1) * 0.978)); }
    68%  { transform: translate(calc(var(--j) * -0.22), calc(var(--y, 0px) + var(--j) * -0.62)) rotate(calc(var(--r, 0deg) - 2.2deg)) scale(calc(var(--s, 1) * 1.008)); }
  }

  @keyframes boil-c {
    0%   { transform: translate(calc(var(--j) *  0.34), calc(var(--y, 0px) + var(--j) *  0.66)) rotate(calc(var(--r, 0deg) + 2.8deg)) scale(calc(var(--s, 1) * 0.992)); }
    34%  { transform: translate(calc(var(--j) * -0.72), calc(var(--y, 0px) + var(--j) *  0.44)) rotate(calc(var(--r, 0deg) - 6.0deg)) scale(calc(var(--s, 1) * 1.020)); }
    55%  { transform: translate(calc(var(--j) *  0.48), calc(var(--y, 0px) + var(--j) * -0.76)) rotate(calc(var(--r, 0deg) + 4.6deg)) scale(calc(var(--s, 1) * 0.982)); }
    88%  { transform: translate(0, var(--y, 0px)) rotate(var(--r, 0deg)) scale(var(--s, 1)); }
  }
}

/* --- small screens --------------------------------------------- */

@media (max-width: 700px) and (orientation: portrait) {
  .hero {
    min-height: 100svh;
    align-items: flex-start;
    /* continues the cover's top edge (#b36041) upward */
    background: linear-gradient(#a95a3c 0%, #b36041 40%, #b36041 100%);
    padding-top: clamp(1.5rem, 5vh, 3rem);
  }
  /* the scene fills most of the screen, anchored at the bottom and cropped
     from the sides, its sky fading softly into the page colour at the top */
  .hero__cover {
    inset: auto 0 0 0;
    height: 84%;
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 16%);
            mask-image: linear-gradient(to bottom, transparent 0, #000 16%);
  }
  /* the zoom has the whole screen: it starts in the cover's place, soft
     edge and all, and grows to fill it (see draw() in script.js) */
  .hero__zoom {
    inset: 0;
    height: 100%;
    -webkit-mask-image: none;
            mask-image: none;
  }
  /* big letters, one word per line where the pair won't fit:
     HOW WES / ANDERSON / MAKES / MOVIES */
  .ransom {
    --cut: clamp(34px, 15.5vw, 76px);
    gap: calc(var(--cut) * 0.32);
  }
  /* the same space between every line, wrapped or not */
  .line { gap: calc(var(--cut) * 0.32) 0.85rem; }
  .word .scrap + .scrap { margin-left: calc(var(--cut) * -0.11); }
}

/* --- loading screen --------------------------------------------- */

/* Black, above everything, until the opening is ready; then it lifts off
   the site. (The earlier version, a field of film stills fading up while
   the camera pushes in, is kept in archive/loader-tiles/.) */
.loader {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: #000;
  color: #f4e8d8;
  overflow: hidden;
  transition: opacity 0.7s ease;
  /* a last resort: never leave the site covered if the script can't run */
  animation: loader-failsafe 0s linear 25s forwards;
}

.loader.is-gone { opacity: 0; pointer-events: none; }

@keyframes loader-failsafe { to { opacity: 0; visibility: hidden; } }

/* the headline holds its entrance until the loading screen lifts */
html.is-loading .scrap { animation-play-state: paused; }

/* "WES ANDERSON" in the middle, faint, filling with white from the bottom
   up as the site loads (--p, 0 to 1, set by script.js). Two copies of the
   title share one spot: the faint one, and a white one masked so only the
   part below the rising line shows, cut off sharp. */
.loader__title {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
  opacity: 0;               /* waits for its font */
  transition: opacity 0.4s ease, transform 0.7s cubic-bezier(0.4, 0, 0.2, 1);
}

.loader.has-font .loader__title { opacity: 1; }

.loader__words {
  grid-area: 1 / 1;
  font-family: "Futura PT Condensed", "Futura", "Avenir Next Condensed", "Arial Narrow", sans-serif;
  font-weight: 700;
  /* 5.54em wide: about 83% of the screen, with room either side */
  font-size: min(15vw, 30vh);
  /* tight to the capitals, so the fill runs from their foot to their top */
  line-height: 0.74;
  letter-spacing: 0.01em;
  white-space: nowrap;
  text-align: center;
  color: rgba(255, 255, 255, 0.12);
}

.loader__words--fill {
  color: #fff;
  /* a hard line, no fade: both stops at the same height */
  -webkit-mask-image: linear-gradient(to top, #000 calc(var(--p, 0) * 104%), transparent calc(var(--p, 0) * 104%));
          mask-image: linear-gradient(to top, #000 calc(var(--p, 0) * 104%), transparent calc(var(--p, 0) * 104%));
}

/* upright screens: one word above the other, so it can be bigger */
@media (orientation: portrait) {
  /* ANDERSON (3.83em wide) spans the screen less the usual 1.5rem margins */
  .loader__words { font-size: min(calc((100vw - 3rem) / 3.9), 19vh); }
  .loader__w { display: block; }
}

/* at the end the title steps forward as it fades */
.loader--title.is-done .loader__title { opacity: 0; transform: scale(1.04); }

/* stills that pop up under the pointer as it moves */
.loader__pop {
  position: absolute;
  z-index: 1;
  display: block;
  object-fit: cover;
  pointer-events: none;
  opacity: 0;
  transform: scale(0.6);
  transition: opacity 0.18s ease-out, transform 0.42s cubic-bezier(0.2, 1.35, 0.4, 1);
}

.loader__pop.is-in { opacity: 1; transform: scale(1); }

.loader__pop.is-out {
  opacity: 0;
  transform: scale(0.9);
  transition: opacity 0.45s ease-in, transform 0.45s ease-in;
}

.loader__pop.is-bumped { transition: opacity 0.25s ease-in, transform 0.25s ease-in; }

.loader--title.is-done .loader__pop { opacity: 0; transition: opacity 0.4s ease; }

@media (prefers-reduced-motion: reduce) {
  .loader__pop,
  .loader__pop.is-in,
  .loader__pop.is-out { transform: none; transition: opacity 0.25s linear; }
}
