/* Anno XL — base.css
   Ground rules. Palette is pulled off the aerial photo: sea ink, sand,
   lagoon, temple marigold, a little chilli. No border-radius anywhere
   except things that are genuinely round (pins, punch holes, heat dots);
   everything else gets cut corners, like a ticket.                       */

:root {
  --ink: #0c2126;
  --ink-2: #10313a;
  --ink-3: #143d47;
  --lagoon: #2f8fa3;
  --lagoon-2: #7fccdb;
  --sand: #e7d9bd;
  --bone: #f7f0e0;
  --gold: #e6a33e;
  --chili: #d4553a;
  --paper: #f4ecda;
  --paper-ink: #1c3038;
  --paper-mid: #33484f;
  --paper-gold: #8a5a2e;

  --serif: 'Zodiak', Georgia, 'Times New Roman', serif;
  --sans: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --thai: 'Noto Serif Thai', Georgia, serif;

  /* Height for full-bleed PICTURE layers (#sky, #pins, .room-bg, #arcade,
     #haze, body::before/after). One token so the unit is decided in one place.
     The value is refined just below this block — see the @supports rule and
     the html rule for why the unit choice is not obvious. Bottom-anchored
     chrome deliberately does NOT use this; it stays on the real viewport so it
     can never hide under the URL bar or the home indicator. */
  --screen-h: 100vh;

  /* Bottom overshoot for ink panels and full-bleed OVERLAYS (loader, gate,
     onboarding, haze, sheet scrim, grain, vignette): they use
     `top: 0; bottom: calc(-1 * var(--skirt))` instead of a viewport-unit
     height. Measured on a real iPhone (b8): Safari re-resolved --screen-h
     lazily, leaving the loader at the SMALL viewport (686) while #sky sat at
     lvh (786) — a 100px band of photograph under the ink, and the vignette's
     stale bottom edge drew a tonal line across the map. 240px exceeds the
     worst possible shortfall (screen minus small viewport, 226px on the Air),
     so a stale layout still covers the screen; the excess is clipped.
     Centred panels add the same amount of padding-bottom to keep their
     optical centre. Geometry layers (#sky, #pins, .room-bg, #arcade,
     #index-sheet) stay on --screen-h: mapstage measures them, and photos
     would visibly re-crop. */
  --skirt: 240px;

  --ease-dive: cubic-bezier(.64, .02, .16, 1);
  --ease-soft: cubic-bezier(.25, .8, .3, 1);
  --cut-s: polygon(7px 0, calc(100% - 7px) 0, 100% 7px, 100% calc(100% - 7px), calc(100% - 7px) 100%, 7px 100%, 0 calc(100% - 7px), 0 7px);
  --cut-m: polygon(12px 0, calc(100% - 12px) 0, 100% 12px, 100% calc(100% - 12px), calc(100% - 12px) 100%, 12px 100%, 0 calc(100% - 12px), 0 12px);
}

/* Whichever of the two is bigger.
   `100vh` is the only unit correct from the first frame in an iOS standalone
   PWA (see the html rule below), but in Safari it can resolve to the SMALL
   viewport — the height with the URL bar showing — which leaves the picture
   layers stopping at the bar and a visible edge across the photograph.
   `100lvh` is the large viewport, i.e. bars collapsed. Taking the max means
   neither case can under-fill: if lvh misreports at cold start, vh wins; if vh
   is the small viewport, lvh wins. Only ever over-fills, and these are fixed
   layers so overflow is clipped by the screen anyway. */
@supports (height: 100lvh) {
  :root { --screen-h: max(100vh, 100lvh); }
}

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

/* ⚠ html/body MUST be `height: 100vh`. Not 100%, not 100dvh, not min-height.
 *
 * This is the actual cause of the band along the bottom of the standalone PWA,
 * and it is counter-intuitive: `height: 100%` on the root DEFEATS
 * `viewport-fit=cover`. iOS then lays the page out in a viewport that is the
 * screen minus the top inset — measured on an iPhone Air: screen 912,
 * innerHeight 844, safe-area-top 68 — and the leftover 68px shows the page
 * canvas. Every "fill the viewport" fix downstream is then filling a box that
 * is already the wrong size, which is why two earlier attempts changed nothing.
 *
 * 100dvh is no good either: it reports the wrong value at cold start in a PWA.
 * 100vh is the only unit that is correct from the first frame here. In Safari
 * it includes the area behind the toolbar, which for full-bleed picture layers
 * is exactly what we want.
 *
 * Sources: the iPhone PWA fullscreen guide (see GAME STATUS).
 */
html {
  height: 100vh;
  /* Explicit, never inherited: Safari 26 paints its own chrome band (the zone
     below 100lvh that no page can reach) with the root background colour, and
     a transparent root can fall back to WHITE there. main.js swaps this to
     the picture's bottom-edge tone while the map is up. */
  background-color: var(--ink);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  height: 100vh;
  background: var(--ink);
  color: var(--sand);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

/* NO scroll runway. b12 briefly made Safari tabs scrollable by 2px (pinned at
   scrollY 1) chasing the stale-snapshot sliver; the sliver is handled by the
   pagehide curtain in main.js instead, and a scrollable document changes how
   aggressively Safari re-seats its viewport when a load settles — suspected
   cause of the whole background jumping at load-finish. The page stays
   unscrollable on every surface. */

img { display: block; max-width: 100%; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
h1, h2, h3, p, ul, ol, dl, dd, figure { margin: 0; padding: 0; }
ul, ol { list-style: none; }
a { color: var(--gold); text-underline-offset: 3px; text-decoration-thickness: 1px; }

.th { font-family: var(--thai); font-weight: 400; }

::selection { background: var(--gold); color: #142a30; }

:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* Film grain + vignette over everything, under nothing interactive.
   Skirted (see --skirt), not height-sized: an overlay whose bottom edge lands
   anywhere on screen draws a visible horizontal line across the image — the
   vignette especially, since it reaches 50% opacity at its lower edge, and a
   stale-resolved height put that edge mid-photo on a real iPhone. Any
   full-bleed overlay added later must match. */
body::before {
  content: '';
  position: fixed; top: 0; left: 0; right: 0;
  bottom: calc(-1 * var(--skirt));
  z-index: 96; pointer-events: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='170' height='170'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='170' height='170' filter='url(%23n)' opacity='0.5'/></svg>");
  opacity: .085;
  mix-blend-mode: overlay;
}
body::after {
  content: '';
  position: fixed; top: 0; left: 0; right: 0;
  bottom: calc(-1 * var(--skirt));
  z-index: 95; pointer-events: none;
  background: radial-gradient(120% 90% at 50% 44%, transparent 58%, rgba(4, 15, 18, .5) 100%);
}

/* ---- ring cursor (desktop map only) ---------------------------------- */

#cursor {
  position: fixed; left: 0; top: 0; z-index: 99;
  pointer-events: none;
  opacity: 0;
}
#cursor::before {
  content: '';
  display: block;
  width: 34px; height: 34px;
  margin: -17px 0 0 -17px;
  border: 1.5px solid var(--sand);
  border-radius: 50%;
  transition: width .28s var(--ease-soft), height .28s var(--ease-soft),
              margin .28s var(--ease-soft), border-color .28s, background-color .28s;
}
#cursor span {
  position: absolute; left: 0; top: 0;
  transform: translate(-50%, -50%);
  font: 700 10px/1 var(--sans);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: #142a30;
  opacity: 0;
  transition: opacity .2s;
}
#cursor.on { opacity: 1; }
#cursor.big::before {
  width: 62px; height: 62px; margin: -31px 0 0 -31px;
  background: var(--gold); border-color: var(--gold);
}
#cursor.big span { opacity: 1; }
#cursor.press::before { transform: scale(.88); }
body.has-ring #sky, body.has-ring #sky .pin { cursor: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001s !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001s !important;
  }
}
