/* ═══════════════════════════════════════════════════════════════════════
   MOBILE LAYER — Al Millennium
   ═══════════════════════════════════════════════════════════════════════

   The site's stylesheets are desktop-first. This sheet is loaded LAST on
   every visitor-facing layout (public / reader / vault-bare) and carries
   the phone + touch corrections in one reviewable place, instead of
   scattering them across seventeen stylesheets.

   Rules of the house:
   - EVERY rule in this file lives inside a media query. On a desktop
     pointer this sheet changes nothing — it can only ever narrow the blast
     radius of a mistake to small screens.
   - No new colours, no new fonts. Tokens from style.css only
     (DESIGN_SYSTEM §2/§3). Nothing here invents layout — it only makes the
     existing design fit a phone.
   - Fixes belong here when the desktop value is right and only the small
     screen needs a different one. When a value is simply wrong at every
     size (a clamp() floor that can never fit), fix it at the source.

   Breakpoints match the ones the codebase already uses:
     960px  reader panels go off-canvas
     900px  the left wordmark rail drops
     860px  the nav collapses into the hamburger
     640px  phone
     480px  small phone

   Contents
     1. Typography that has to fit
     2. Fixed-nav clearance
     3. Forms — the iOS zoom trap
     4. Touch targets
     5. Touch pointers — hover affordances that never fire
     6. Horizontal scrollers
     7. The ambient music player
     8. The story reader
     9. Viewport units + safe areas
   ═══════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────────────────
   1. TYPOGRAPHY THAT HAS TO FIT

   Display type is set with clamp(). Where the clamp FLOOR is larger than
   a phone can hold, the headline is clipped by body{overflow-x:hidden} —
   no scrollbar, just a word cut in half. These floors are the ones that
   were measured overflowing at 360px; the vw term and the max are
   untouched, so every width the design was actually drawn at is identical.
   ─────────────────────────────────────────────────────────────────────── */
@media (max-width: 620px) {
  /* "Relics of the MILLENNIUM" — floor 50px needs 361px for one word. */
  .sh-title { font-size: clamp(32px, 8vw, 108px); }

  /* Nation hero name — floor 3rem needs 382px for "Frostbreath". */
  .nh-hero2-name { font-size: clamp(2.1rem, 7vw, 5.5rem); }

  /* "The Codex" — floor 52px needs 380px, and because the hero is a grid
     the oversized h1 pushed the whole column wider than the page (a grid
     item's automatic minimum is its content). min-width:0 lets the column
     obey its track again once the type fits. */
  .lore-hero-left h1 { font-size: clamp(34px, 7vw, 96px); }
  .lore-hero-inner > * { min-width: 0; }

  /* Long single words in display headings break rather than get clipped.
     This only engages when there is no other break opportunity. */
  .sh-title, .nh-hero2-name, .srp-title, .fv h2, .fsec-head h2 { overflow-wrap: break-word; }
}

/* Section headers pair a title with a "→ All Stories" link on one baseline.
   Below ~560px the pair no longer fits, so let it stack instead of pushing
   the link off the edge. */
@media (max-width: 560px) {
  .fsec-head { flex-wrap: wrap; gap: 10px 24px; }
  .fsec-head .more { flex-shrink: 0; }
}

/* The signal panel's inner padding is a desktop figure. Combined with the
   old 56px page gutter it left 168px of usable width on a 360px phone —
   the heading, the copy and the whole form were clipped. */
@media (max-width: 700px) {
  .fv { padding-top: 90px; padding-bottom: 96px; }
  .fv-panel > div { padding: 44px 24px; }
}


/* ───────────────────────────────────────────────────────────────────────
   2. FIXED-NAV CLEARANCE

   The nav is fixed at var(--nav-h). Heroes that centre their content in a
   vh-sized box drift under it once the box gets short — on the Codex the
   "Reference Archive" eyebrow sat behind the nav bar.
   ─────────────────────────────────────────────────────────────────────── */
@media (max-width: 860px) {
  .lore-hero { padding-top: var(--nav-h); }
}


/* ───────────────────────────────────────────────────────────────────────
   3. FORMS — THE iOS ZOOM TRAP

   Safari on iOS zooms the whole page in when a focused field's text is
   under 16px, and never zooms back out. Every field on the site was
   10–15px. The 16px floor applies to the CONTROL only; the surrounding
   eyebrow/label type keeps its designed size, so the forms still read as
   ours. Range/checkbox/radio are exempt — they have no text to zoom to.
   ─────────────────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="hidden"]),
  select,
  textarea { font-size: 16px; }

  /* Placeholders that were set smaller than their input follow it up, so a
     field doesn't render its hint at a third of its own type size. */
  .lh-hero-search-input::placeholder,
  .email-input::placeholder,
  .srp-form input[type="text"]::placeholder { font-size: inherit; }

  /* These two carry heavy tracking meant for 9–10px mono. At 16px it
     overruns the field, so ease it back to body-copy tracking. */
  .lh-hero-search-input,
  .lh-hero-search-input::placeholder { letter-spacing: 0.08em; }

  /* "↵ to search" is a keyboard hint. There is no Enter key to hint at
     here, and it was taking 86px out of the Codex search bar. */
  .lh-hero-search-kbd { display: none; }
}

/* Inline "field + button" bars stop being a single row long before a phone
   is done narrowing — the button was clipped off the right edge on the
   homepage signal form and the search page. Stack them instead. */
@media (max-width: 560px) {
  .email-form { flex-wrap: wrap; }
  .email-input { flex: 1 0 100%; }
  .email-submit {
    flex: 1 0 100%;
    border-left: none;
    border-top: 1px solid var(--border);
    padding: 15px 22px;
  }

  .srp-form { flex-wrap: wrap; padding: 4px 12px 12px; }
  .srp-form input[type="text"] { flex: 1 0 100%; }
  .srp-form button { flex: 1 0 100%; }
}


/* ───────────────────────────────────────────────────────────────────────
   4. TOUCH TARGETS

   The nav controls are drawn at 24–32px, which is fine for a mouse and
   under the ~44px a finger needs. The nav bar is 56px tall, so 44px fits
   without changing the bar's height or the icons' drawn size — only the
   hit area grows.
   ─────────────────────────────────────────────────────────────────────── */
@media (max-width: 860px) {
  /* min-height only — never `display`. .nav-shop-browse is a .nav-vault-btn
     that components.css hides with display:none below 600px (it folds into
     the hamburger); re-declaring display here would put it back. */
  .nav-vault-btn,
  .nav-cart-btn,
  .nav-member-btn { min-height: 44px; }
  .nav-search,
  .nav-hamburger { width: 44px; min-height: 44px; }
  /* The 30px mark stays 30px — only the box around it grows. */
  .nav-logo { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; margin-left: -7px; }

  /* Footer links are 9px Cinzel — ~13px tall as drawn. Pad the box, not
     the type, so the row still looks like a row of hairline labels. */
  .footer-links a { padding-block: 15px; }
  .footer-social a { width: 44px; height: 44px; }
  .footer-links { gap: 0 20px; }

  /* Consent/remember checkboxes render at 13px. */
  input[type="checkbox"], input[type="radio"] { width: 20px; height: 20px; }
}


/* ───────────────────────────────────────────────────────────────────────
   5. TOUCH POINTERS — HOVER AFFORDANCES THAT NEVER FIRE

   Coarse pointers have no hover, but mobile browsers fake a sticky one
   after a tap: whatever you last touched keeps :hover until you tap
   elsewhere. Anything that only appears on hover is therefore either
   invisible or stuck open.
   ─────────────────────────────────────────────────────────────────────── */
@media (hover: none) and (pointer: coarse) {
  /* Custom map cursors follow the real cursor. With no cursor to follow
     they park at the top-left corner and sit under the nav. They are
     decorative (aria-hidden, pointer-events:none) — the underlying map
     stays fully tappable. */
  .wi-atlas-cursor,
  .nmap-cursor,
  .fatlas-cursor { display: none; }

  /* A visible tap flash, in the site's gold rather than the browser blue.
     Browsers without color-mix simply keep their default highlight. */
  a, button, [role="button"], summary {
    -webkit-tap-highlight-color: color-mix(in srgb, var(--gold-light) 16%, transparent);
  }
}


/* ───────────────────────────────────────────────────────────────────────
   6. HORIZONTAL SCROLLERS

   Filter bars and the nation rails are real overflow-x:auto scrollers, so
   they already work under a finger. What they lack is somewhere to land:
   without snapping, a flick leaves a chip half-cut at the edge.
   ─────────────────────────────────────────────────────────────────────── */
@media (max-width: 860px) {
  .filter-group,
  .nh-rail {
    scroll-snap-type: x proximity;
    scroll-padding-inline: var(--page-pad);
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;   /* a flick past the end must not navigate back */
  }
  .filter-group > *,
  .nh-rail > * { scroll-snap-align: start; }
}


/* ───────────────────────────────────────────────────────────────────────
   7. THE AMBIENT MUSIC PLAYER

   A fixed orb bottom-left that expands into a 360px panel. On a phone the
   expanded panel is wider than the screen, and the sticky-hover above can
   leave it open on top of the page after any tap near it. So on touch the
   panel opens only from the orb (focus) or from its own timed peek, and it
   is capped to the viewport.
   ─────────────────────────────────────────────────────────────────────── */
@media (hover: none) and (pointer: coarse) {
  .alm-music:hover .alm-panel { max-width: 0; opacity: 0; margin-left: 0; }
  .alm-music:focus-within .alm-panel,
  .alm-music.peek .alm-panel { max-width: 360px; opacity: 1; margin-left: 10px; }
}

@media (max-width: 640px) {
  .alm-music:hover .alm-panel,
  .alm-music:focus-within .alm-panel,
  .alm-music.peek .alm-panel { max-width: calc(100vw - 90px); }
  .alm-panel-inner { gap: 11px; padding: 9px 13px; }
  .alm-music-orb { width: 44px; height: 44px; }
  /* Clear the iOS home indicator / Android gesture bar. */
  .alm-music { bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
}


/* ───────────────────────────────────────────────────────────────────────
   8. THE STORY READER

   The reader's default "dock" layout keeps a 44px Contents strip pinned to
   the left edge, which expands to 300px on hover. On a wide screen the
   680px reading column is centred and never meets it. On a phone the
   column is the whole width, so the strip sat ON TOP of the prose and ate
   the first character of every line.

   Below 960px the strip becomes an off-canvas drawer — exactly what the
   "rail" layout already does at this width — driven by the Contents button
   that is already in the top bar (data-act="toc", reader-lab.js).
   ─────────────────────────────────────────────────────────────────────── */
@media (max-width: 960px) {
  body[data-layout="dock"] .rdr-toc,
  body[data-layout="dock"] .rdr-toc:hover {
    width: 300px;
    max-width: 86vw;
    transform: translateX(-100%);
    transition: transform 0.36s var(--ease-out);
    background: var(--bg-glass);
    border-right: 1px solid var(--border-faint);
  }
  body[data-layout="dock"] .rdr-toc.open { transform: translateX(0); }

  /* Off-canvas means the whole panel is on show when it is open — the
     ghost strip and the fade-in choreography belong to the 44px state. */
  body[data-layout="dock"] .toc-ghost { display: none; }
  body[data-layout="dock"] .rdr-toc .toc-inner { opacity: 1; pointer-events: all; }
  body[data-layout="dock"] .toc-close { display: flex; opacity: 1; }

  /* Give the drawer its opener back. */
  body[data-layout="dock"] .rdr-top-tools { display: flex; }
  body[data-layout="dock"] .rdr-top-toc { display: inline-flex; }

  /* Reader top-bar icons are 38px — the icon stays 38px, the hit area grows. */
  .rdr-ic { width: 44px; height: 44px; }
}


/* ───────────────────────────────────────────────────────────────────────
   9. VIEWPORT UNITS + SAFE AREAS

   100vh on a phone is the viewport with the browser's address bar HIDDEN,
   so a 100vh panel is taller than the screen until you scroll. dvh tracks
   the bar as it collapses. Only full-height fixed panels need this —
   min-height:100vh page shells are fine either way.
   ─────────────────────────────────────────────────────────────────────── */
@media (max-width: 960px) {
  body[data-layout="rail"] .rdr-toc,
  body[data-layout="dock"] .rdr-toc,
  body[data-layout="immersive"] .rdr-toc { height: 100dvh; }
}

/* Notched / gesture-bar phones: keep the fixed furniture out of the
   rounded corners and off the home indicator. */
@media (max-width: 860px) {
  .site-nav { padding-left: max(20px, env(safe-area-inset-left, 0px)); padding-right: max(20px, env(safe-area-inset-right, 0px)); }
  .nav-drawer { padding-bottom: calc(48px + env(safe-area-inset-bottom, 0px)); }
  .sh-drawer-panel { padding-bottom: env(safe-area-inset-bottom, 0px); }
  .site-footer { padding-bottom: calc(40px + env(safe-area-inset-bottom, 0px)); }
}
