/* ============================================================
   Skies of Fight — style.css
   Mango 9 Sep 26: one page. The sky is the title card; below the
   horizon the page falls into night and holds the chapters. The
   palette is lifted straight off the logo — sky blue for the world,
   hot orange for anything the visitor is meant to click.
   ============================================================ */

:root {
  /* --- sky --- */
  --sky-high:   #1663AE;
  --sky-mid:    #4E9BDA;
  --sky-low:    #9FCDEC;
  --sky-haze:   #DCEAF4;
  --sea-high:   #7FB2D6;
  --sea-low:    #4B84B4;

  /* --- night, everything below the horizon ---
     Mango 10 Sep 26: the chapters ride on a gradient that follows the
     four wave screenshots, one tone per picture, top to bottom: day
     sea, sunset, the shmup's deep blue, then night. Each tone is a
     darkened cut of the picture that sits on it, so the picture reads
     as a wash of colour on its own hue.
     --wave-alpha is how much of the picture shows through. */
  --wave-1:     #2D363D;
  --wave-2:     #7C3712;
  --wave-3:     #0B2C7A;
  --wave-4:     #000000;
  --wave-5:     #23103C;
  --wave-alpha: 0.24;
  --night:      #000000;
  --night-text: rgba(255, 255, 255, 0.78);
  --night-rule: rgba(255, 255, 255, 0.13);

  /* --- the loud one --- */
  --flame:      #F07216;
  --flame-hot:  #FF9227;
  --flame-deep: #C4520A;

  /* How deep the sea band is, measured up from the bottom of the hero.
     The horizon is wherever this band starts, and the hero pads its
     content clear of it, so the horizon can never cut through a line of
     text at any window size. Raise this to bring the horizon up. */
  --sea-h: clamp(76px, 14vh, 158px);
  --hero-pad-y: clamp(56px, 9vh, 96px);
  /* Mango 14 Sep 26: the top is tighter than the bottom now that the
     cabinet lives on the sky. The banner carries its own sky above the
     wordmark, so the logo floats clear of the edge without much help. */
  --hero-pad-top: clamp(12px, 2.5vh, 28px);

  /* --- the arcade cabinet ---
     How wide the cabinet is on a big screen, and how far the contents
     stay in from the picture's edges so they sit inside the window. All
     four are a share of the cabinet's width, top and bottom included.
     Grow a number to push the contents away from that side of the bezel. */
  --cabinet-w: 900px;
  --cab-top:    4.5%;
  --cab-right:  9.0%;
  --cab-bottom: 6.0%;
  --cab-left:   7.5%;

  /* One typeface does the whole page, the way the arcade cabinets did
     it: weight and size carry the hierarchy, not a second family. */
  --font: "Sora", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* One place to retune the whole site's rhythm. */
  --gutter: clamp(20px, 5vw, 64px);
  --section-y: clamp(64px, 10vw, 128px);
  --measure: 62ch;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--night);
  color: var(--night-text);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3 {
  font-family: var(--font);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.02em;
  text-wrap: balance;
  margin: 0;
}

p { margin: 0; }
p + p { margin-top: 1.05em; }

a { color: var(--flame-deep); }

/* Reachable by screen readers, invisible to everyone else. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* The one word that gets to be loud. */
.flame { color: var(--flame-hot); }


/* ============================================================
   BUTTONS
   ============================================================ */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  color: #fff;
  background: linear-gradient(180deg, var(--flame-hot), var(--flame));
  border: 0;
  border-radius: 3px;
  /* A hard darker lip instead of a soft shadow: the button reads as a
     physical cabinet key, and pressing it actually travels downward. */
  box-shadow: 0 4px 0 var(--flame-deep), 0 6px 18px rgba(11, 30, 49, 0.28);
  transition: transform 0.09s ease, box-shadow 0.09s ease, filter 0.15s ease;
}
.btn:hover { filter: brightness(1.07); }
.btn:active {
  transform: translateY(3px);
  box-shadow: 0 1px 0 var(--flame-deep), 0 2px 8px rgba(11, 30, 49, 0.28);
}
.btn:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }

.btn-big { padding: 16px 32px; font-size: clamp(18px, 2.3vw, 23px); }


/* ============================================================
   THE SKY
   Stacked CSS layers, no hero image to download.
   ============================================================ */

.sky { position: absolute; inset: 0; }

.sky-gradient {
  position: absolute; inset: 0;
  background: linear-gradient(
    180deg,
    var(--sky-high)  0%,
    var(--sky-mid)   calc((100% - var(--sea-h)) * 0.50),
    var(--sky-low)   calc((100% - var(--sea-h)) * 0.87),
    var(--sky-haze)  calc(100% - var(--sea-h))
  );
}

/* A soft sun bloom sitting just above the horizon. */
.sky-glow {
  position: absolute;
  left: 50%; top: calc(100% - var(--sea-h));
  width: 150vmax; height: 70vmax;
  transform: translate(-50%, -50%);
  background: radial-gradient(
    ellipse at center,
    rgba(255, 246, 226, 0.55) 0%,
    rgba(255, 236, 200, 0.20) 32%,
    rgba(255, 236, 200, 0) 62%
  );
}

/* --- cloud bands ---------------------------------------------
   Each band is one wide tile of soft ellipses, scrolled sideways
   by animating background-position. The tile repeats, so the loop
   is seamless with no JS and no image files.
   ------------------------------------------------------------- */
.cloud-band {
  position: absolute;
  left: -10%; right: -10%;
  background-repeat: repeat-x;
  will-change: background-position;
}

.cloud-far {
  top: 8%; height: 26%;
  opacity: 0.5;
  background-image:
    radial-gradient(70px 14px at 120px 60%, rgba(255,255,255,0.85), rgba(255,255,255,0) 70%),
    radial-gradient(110px 18px at 420px 40%, rgba(255,255,255,0.7),  rgba(255,255,255,0) 70%),
    radial-gradient(80px 13px at 760px 72%, rgba(255,255,255,0.8),  rgba(255,255,255,0) 70%),
    radial-gradient(130px 20px at 1080px 30%, rgba(255,255,255,0.6), rgba(255,255,255,0) 70%);
  background-size: 1300px 100%;
  animation: drift-left 130s linear infinite;
}

.cloud-mid {
  top: 26%; height: 30%;
  opacity: 0.6;
  background-image:
    radial-gradient(150px 26px at 200px 50%, rgba(255,255,255,0.9),  rgba(255,255,255,0) 72%),
    radial-gradient(210px 34px at 640px 30%, rgba(255,255,255,0.75), rgba(255,255,255,0) 72%),
    radial-gradient(170px 28px at 1050px 66%, rgba(255,255,255,0.85), rgba(255,255,255,0) 72%);
  background-size: 1450px 100%;
  animation: drift-left 78s linear infinite;
}

.cloud-near {
  bottom: var(--sea-h); height: 20%;
  opacity: 0.42;
  background-image:
    radial-gradient(260px 40px at 260px 40%, rgba(255,255,255,0.85), rgba(255,255,255,0) 72%),
    radial-gradient(320px 52px at 900px 62%, rgba(255,255,255,0.7),  rgba(255,255,255,0) 72%);
  background-size: 1600px 100%;
  animation: drift-left 42s linear infinite;
}

@keyframes drift-left {
  from { background-position-x: 0; }
  to   { background-position-x: -1600px; }
}

/* --- sea ------------------------------------------------------ */
.sea {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: var(--sea-h);
  background: linear-gradient(180deg, var(--sea-high) 0%, var(--sea-low) 100%);
  overflow: hidden;
}
/* A hairline of glare exactly where sky meets water. */
.sea::before {
  content: "";
  position: absolute; left: 0; right: 0; top: 0;
  height: 2px;
  background: linear-gradient(90deg,
    rgba(255,255,255,0) 0%,
    rgba(255,255,255,0.85) 35%,
    rgba(255,255,255,0.95) 50%,
    rgba(255,255,255,0.85) 65%,
    rgba(255,255,255,0) 100%);
}
.sea-shimmer {
  position: absolute; inset: 0;
  background-image: repeating-linear-gradient(
    180deg,
    rgba(255,255,255,0.16) 0px,
    rgba(255,255,255,0.16) 1px,
    rgba(255,255,255,0) 1px,
    rgba(255,255,255,0) 7px
  );
  animation: shimmer 9s ease-in-out infinite;
}
@keyframes shimmer {
  0%, 100% { opacity: 0.55; transform: translateY(0); }
  50%      { opacity: 0.9;  transform: translateY(2px); }
}

.sky-vignette {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse at 50% 45%,
    rgba(0,0,0,0) 45%, rgba(4, 24, 44, 0.36) 100%);
}


/* ============================================================
   THE TITLE SECTION
   ============================================================ */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  padding: var(--hero-pad-top) var(--gutter)
           calc(var(--hero-pad-y) + var(--sea-h));
  text-align: center;
}

.hero-content {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  max-width: 1000px;
}

.hero-logo {
  display: block;
  width: min(94vw, 1040px);
  height: auto;
  filter: drop-shadow(0 10px 26px rgba(4, 22, 42, 0.45));

  /* The banner is a photo of a sky sitting on top of a live sky, so its
     edges would otherwise read as a rectangle pasted on. Two gradients
     intersected feather all four sides: the vertical stops are pulled in
     tight because the wordmark itself occupies 14%-85% of the image and
     must not be touched. If a browser ignores masks the image simply
     shows in full, which is merely less pretty. */
  --edge-x: linear-gradient(90deg,
    transparent 0%, #000 11%, #000 89%, transparent 100%);
  --edge-y: linear-gradient(180deg,
    transparent 0%, #000 9%, #000 88%, transparent 100%);
  -webkit-mask-image: var(--edge-x), var(--edge-y);
  -webkit-mask-composite: source-in;
  mask-image: var(--edge-x), var(--edge-y);
  mask-composite: intersect;
}

/* --- the writing on the sky -----------------------------------
   Type on the sky, nothing else. A box around it would compete
   with the one real button on the page. The measure is short so
   the lines stay easy to read against a moving background.
   --------------------------------------------------------------- */
.hero-intro {
  margin-top: clamp(4px, 1.2vh, 14px);
  max-width: 54ch;
  color: #fff;
  font-size: clamp(17px, 2vw, 21px);
  font-weight: 500;
  line-height: 1.5;
  text-shadow: 0 2px 14px rgba(4, 22, 42, 0.72), 0 1px 3px rgba(4, 22, 42, 0.55);
}

/* Mango 14 Sep 26: the "Hold up!" heading. Rank stays h2 so the page
   keeps its single h1; size and colour are what make it shout. */
.hero-shout {
  font-size: clamp(34px, 4.6vw, 56px);
  color: var(--flame-hot);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  margin-bottom: 8px;
}

.hero-cta { margin-top: clamp(22px, 4vh, 40px); }

/* --- the scroll cue -------------------------------------------
   A chevron drawn from two borders on a rotated square, so there
   is no glyph and no image to load. Orange because it has to hold
   against both the pale haze and the darker water underneath it.
   --------------------------------------------------------------- */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: calc(var(--sea-h) + 24px);
  z-index: 2;
  transform: translateX(-50%);
  padding: 12px;
  animation: cue-bob 2.4s ease-in-out infinite;
}
.scroll-cue-mark {
  display: block;
  width: 18px; height: 18px;
  border-right: 3px solid var(--flame);
  border-bottom: 3px solid var(--flame);
  transform: rotate(45deg);
  filter: drop-shadow(0 1px 2px rgba(255, 255, 255, 0.7));
}
.scroll-cue:focus-visible { outline: 3px solid var(--flame); outline-offset: 2px; }

@keyframes cue-bob {
  0%, 100% { transform: translate(-50%, 0); }
  50%      { transform: translate(-50%, 7px); }
}


/* ============================================================
   PLAY IN THE BROWSER
   Mango 13 Sep 26. The screen is a 16:9 box. The poster sits in it
   until Play is pressed; the iframe main.js creates then fills the
   same box. Fullscreen keeps the game at 16:9 on a black field
   rather than stretching it.

   Mango 14 Sep 26: the arcade cabinet. Three layers, back to front:
   a black interior placed where the picture's window is, the blurb /
   screen / controls stacked inside that interior, and the cabinet
   picture painted over everything. The bezel is solid right out to
   the picture's corners, so the interior can overlap the window's
   edges freely and the picture hides the overlap.

   Every size inside the cabinet is a percentage, so the whole thing
   scales as one piece from a desktop down to a phone.
   ============================================================ */

.play {
  width: min(100%, var(--cabinet-w));
  margin-top: clamp(16px, 3vh, 30px);
  text-align: center;
}

.cabinet {
  position: relative;
  /* The picture's own proportions, so the window lands where measured. */
  aspect-ratio: 802 / 634;
}
.cabinet-frame {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  pointer-events: none;   /* clicks fall through to the screen beneath */
  filter: drop-shadow(0 14px 30px rgba(4, 22, 42, 0.5));
}
.cabinet-screen {
  position: absolute;
  z-index: 1;
  inset: 0;               /* black under the whole picture; the bezel hides the rest */
  background: #000;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  /* Percent padding is measured against the width, even top and bottom,
     which is what keeps the layout proportional as the cabinet scales. */
  padding: var(--cab-top) var(--cab-right) var(--cab-bottom) var(--cab-left);
  gap: 2%;
}

.play-blurb {
  color: var(--night-text);
  font-size: clamp(11px, 1.55vw, 16px);
  line-height: 1.4;
  text-wrap: balance;
}

.play-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #000;
  border-radius: 4px;
  overflow: hidden;
  box-shadow: 0 0 0 1px var(--night-rule);
}

.play-poster {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
}
.play-poster img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Dim the screenshot so the button is the brightest thing in the box. */
  filter: brightness(0.55) saturate(0.9);
}
.play-start { position: relative; z-index: 1; }
/* Once the game is running the poster is gone for good. */
.play-frame.is-live .play-poster { display: none; }

.play-game {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  background: #000;
}

/* --- fullscreen ------------------------------------------------
   The frame itself goes fullscreen, and the game inside it is sized
   to the largest 16:9 box the screen can hold. Both the standard
   and the older WebKit pseudo-class, so Safari gets the same layout.
   --------------------------------------------------------------- */
.play-frame:fullscreen,
.play-frame:-webkit-full-screen {
  aspect-ratio: auto;
  width: 100%;
  height: 100%;
  border-radius: 0;
  box-shadow: none;
  display: grid;
  place-items: center;
}
.play-frame:fullscreen .play-game,
.play-frame:-webkit-full-screen .play-game {
  position: static;
  width: min(100vw, calc(100vh * 16 / 9));
  height: min(100vh, calc(100vw * 9 / 16));
}

/* --- the row under the frame ------------------------------------ */
.play-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px 20px;
}
.play-expand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 7px 14px;
  font-family: var(--font);
  font-size: clamp(11px, 1.4vw, 14px);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #fff;
  background: transparent;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-radius: 3px;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.play-expand:hover { border-color: var(--flame-hot); background: rgba(240, 114, 22, 0.14); }
.play-expand:focus-visible { outline: 3px solid var(--flame-hot); outline-offset: 3px; }
/* Four corner ticks drawn from two borders, the usual "go big" glyph. */
.play-expand-mark {
  width: 14px; height: 14px;
  border: 2px solid currentColor;
  border-radius: 2px;
  -webkit-mask: linear-gradient(#000 0 0) top left / 5px 5px no-repeat,
                linear-gradient(#000 0 0) top right / 5px 5px no-repeat,
                linear-gradient(#000 0 0) bottom left / 5px 5px no-repeat,
                linear-gradient(#000 0 0) bottom right / 5px 5px no-repeat;
  mask: linear-gradient(#000 0 0) top left / 5px 5px no-repeat,
        linear-gradient(#000 0 0) top right / 5px 5px no-repeat,
        linear-gradient(#000 0 0) bottom left / 5px 5px no-repeat,
        linear-gradient(#000 0 0) bottom right / 5px 5px no-repeat;
}
.play-tab {
  font-size: clamp(11px, 1.45vw, 15px);
  color: rgba(255, 255, 255, 0.62);
}
.play-tab:hover { color: var(--flame-hot); }


/* ============================================================
   IMAGE SLOTS
   Mango 9 Sep 26: a picture is shown whole, at whatever shape it
   happens to be. Only the empty placeholder needs a made-up shape,
   because it has no picture to measure.
   ============================================================ */

.shot {
  display: block;
  width: 100%;
  border-radius: 5px;
  box-shadow: 0 8px 24px rgba(11, 30, 49, 0.18);
}

/* The image sets its own height from its own proportions. */
img.shot { height: auto; }

/* The placeholder borrows a 16:9 box so it holds the right space. */
div.shot {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 16 / 9;
  background: linear-gradient(160deg, var(--sky-low), var(--sea-low));
}
.shot span {
  font-family: var(--font);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
  border: 2px dashed rgba(255, 255, 255, 0.5);
  border-radius: 3px;
  padding: 9px 16px;
  text-align: center;
}


/* ============================================================
   THE CHAPTERS
   The band spans the window so the night gradient reaches both
   edges; the reading column is the inner div.
   ============================================================ */

.chapters {
  position: relative;
  padding: var(--section-y) var(--gutter);
  /* Five pictures, five stops, each at the centre of its fifth. The
     fair stops for N pictures are (i + 0.5) / N, so a sixth would be
     8.3 / 25 / 41.7 / 58.3 / 75 / 91.7%. */
  background: linear-gradient(180deg,
    var(--wave-1) 10%,
    var(--wave-2) 30%,
    var(--wave-3) 50%,
    var(--wave-4) 70%,
    var(--wave-5) 90%);
}
.chapters-inner {
  position: relative;
  z-index: 1;            /* the reading column sits above the pictures */
  max-width: 1180px;
  margin: 0 auto;
}

/* --- the wave stage ------------------------------------------
   Mango 10 Sep 26. .chapters-bg is a layer the exact size of the
   band. Inside it the stage is position: sticky, so it rides along
   pinned to the viewport for as long as the band is on screen, then
   lets go when the band's bottom edge arrives. The pictures stack
   inside the stage; main.js sets --wave-mix (0..1) on each one to
   crossfade, and --wave-drift for a slow parallax slide.

   The stage is scaled up a touch so the drift never shows an edge.
   ------------------------------------------------------------- */
.chapters-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.wave-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
}
.wave {
  --wave-mix: 0;
  --wave-drift: 0px;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  opacity: calc(var(--wave-alpha) * var(--wave-mix));
  transform: scale(1.12) translateY(var(--wave-drift));
  will-change: opacity, transform;
}
/* The first picture shows before the script runs, so the band is
   never bare while the page is still loading. */
.no-js .wave:first-child { --wave-mix: 1; }

.chapter {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(28px, 4.5vw, 64px);
  align-items: center;
}
.chapter + .chapter {
  margin-top: var(--section-y);
  padding-top: var(--section-y);
  border-top: 1px solid var(--night-rule);
}

/* Every other chapter puts its art on the left. Ordering the grid
   items rather than reordering the markup keeps the reading order
   intact for screen readers. */
.chapter-flip .chapter-text { order: 2; }
.chapter-flip .chapter-art  { order: 1; }

.chapter-text h2 {
  font-size: clamp(27px, 3.6vw, 40px);
  margin-bottom: 16px;
  color: #fff;
}
.chapter-text p { color: var(--night-text); max-width: var(--measure); }

.chapter-art { display: grid; gap: clamp(12px, 1.6vw, 18px); }


/* ============================================================
   THE STUDIO CARD
   Mango 11 Sep 26: the logo with a row of link buttons under it.
   Five separate images in a flex row rather than one picture with
   an image map: each button gets its own hover, focus ring and alt
   text, and the row wraps on a narrow screen instead of shrinking.
   ============================================================ */

.links-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(20px, 3vw, 36px);
}

.links-logo {
  display: block;
  width: min(100%, 440px);
  height: auto;
  filter: drop-shadow(0 6px 18px rgba(0, 0, 0, 0.45));
}

.links-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(12px, 2vw, 22px);
}

/* --links-size is the one number that sizes every button. The source
   images are different pixel sizes; the img fills the anchor so they
   all land at the same width regardless. */
.links-btn {
  --links-size: clamp(52px, 7vw, 84px);
  display: block;
  width: var(--links-size);
  height: var(--links-size);
  border-radius: 22%;
  transition: transform 0.15s ease, filter 0.15s ease;
}
.links-btn img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.links-btn:hover { transform: translateY(-4px); filter: brightness(1.12); }
.links-btn:focus-visible { outline: 3px solid var(--flame-hot); outline-offset: 4px; }


/* ============================================================
   FOOTER
   ============================================================ */

.site-footer {
  padding: 44px var(--gutter) 56px;
  background: var(--night);
  color: rgba(255, 255, 255, 0.62);
  text-align: center;
}
.footer-title {
  font-family: var(--font);
  font-weight: 700;
  font-size: 18px;
  color: #fff;
  margin-bottom: 8px;
}
.footer-meta { font-size: 15px; }
.footer-meta + .footer-meta { margin-top: 6px; }
.site-footer a { color: var(--flame-hot); text-decoration: none; }
.site-footer a:hover { text-decoration: underline; }


/* ============================================================
   SCROLL REVEAL
   .reveal is the resting state; main.js adds .in when the element
   scrolls into view. The .no-js rule is the safety net: if the
   script never runs, nothing stays invisible.
   ============================================================ */

.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
.reveal.in { opacity: 1; transform: none; }
.no-js .reveal { opacity: 1; transform: none; }


/* ============================================================
   MOTION PREFERENCES
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .cloud-band, .sea-shimmer { animation: none; }
  .scroll-cue { animation: none; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .btn, .links-btn { transition: none; }
  /* The crossfade moves at scroll pace so it stays; only the drift goes. */
  .wave { transform: scale(1.12); }
}


/* ============================================================
   NARROW SCREENS
   ============================================================ */

@media (max-width: 820px) {
  .chapter { grid-template-columns: minmax(0, 1fr); }
  /* On one column the art always follows its text, flip or not. */
  .chapter-flip .chapter-text { order: 0; }
  .chapter-flip .chapter-art  { order: 0; }
  .chapter-art { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 640px) {
  .hero-logo { width: 100vw; max-width: none; }
  .chapter-art { grid-template-columns: minmax(0, 1fr); }
  /* The cue costs vertical room the small screen does not have. */
  .scroll-cue { display: none; }
}
