/* What a map looks like. Written fresh rather than lifted out of plate.css: the creature
 * plate is the project's only green regression and the two surfaces share a shape, not a
 * stylesheet — pulling rules out from under it to save duplication would put 52 passing
 * assertions at risk for nothing a reader can see.
 *
 * Mint is the only colour anything touchable is allowed to be. Every marker state is a real
 * button; dimming is a difference in weight, never a disabled look, because a dead press is
 * the thing this whole design refuses. */

html, body { height: 100%; overflow: hidden; overscroll-behavior: none; }

/* The stage is the window. It is deliberately not inside anything scrollable — focus
   inside a transform would otherwise scroll the page out from under it. */
.map {
  position: fixed;
  inset: 0;
  overflow: clip;
  background: #060A0C;
  touch-action: none;
  cursor: grab;
}
.map.grabbing { cursor: grabbing; }

.map-inner {
  --inv: 1;
  position: absolute;
  left: 0;                    /* physical: the picture does not mirror, so neither does this */
  top: 0;
  transform-origin: 0 0;
  will-change: transform;
}

.map-bg { display: block; width: 100%; height: 100%; user-select: none; }

/* The light sweep is gone (founder, 2026-08-17): the map holds still. */

/* The near occluder rides inside the inner, so it scales and pans with the picture;
   zoomable slides it a little further as the reader pans — near things travel further.
   Cut 8% oversize so its own edge never enters the frame at full pan, and never
   pressable: the markers under it stay the things a finger reaches. */
/* Three bands in one stacking context, and they are what makes the seek real. .map-inner
   carries a transform, so it is the stacking context all of these live in; .marks stays a
   static div with no z-index of its own, because giving it position would make it the
   containing block and collapse every marker to 0x0.
     1  a hidden creature — behind the plane, which is the authored hide itself
     2  the near plane
     3  every other marker — the route down is never behind anything
   Until 2026-08-17 this file carried no z-index at any line and .marks comes last in the
   document, so all six markers painted on top of the plane and not one authored hide
   rendered. Measured rather than reasoned: 0.000% of every marker covered, at fit and at
   all four corners of the pan clamp, against a control that found the plane's own art
   painting inside 28 of 50 of those same boxes. tools/seek_guards.py cannot see this at
   all — it samples the occluder's alpha in data space and never asks the browser what it
   painted, so its green was never evidence here (_runs/2026-08-17_occluder/occ_render.py). */
.plane-occ { position: absolute; inset: 0; z-index: 2; pointer-events: none; will-change: transform; }
.plane-occ .occ { display: block; width: 100%; height: 100%; transform: scale(1.08); }

/* ---- markers ---- */

/* The state ring is an outline rather than a border, and that is a performance decision with
   one visible consequence, written out here because nothing else records it.

   --inv is rewritten on every twelfth-of-an-octave a pinch crosses (zoomable.js:90-93), and
   border-width is a layout property, so each of those ~20 writes re-laid-out every marker
   subtree on the map. Measured on a phone: 35 layouts and 130ms of layout per pinch, 13 janky
   frames. An outline is painted and never laid out, and it is the only other property that can
   be dashed or dotted, which the two states below need. outline-offset pulls it back inside the
   border box so the ring lands on the pixels the border used to own.

   The consequence: a <button> is box-sizing: border-box in every UA stylesheet, so the border
   was eating 2px * --inv off each side of the authored footprint and .mark-cut was rendering
   that much smaller than the map file asked for. Without it the cut-out fills the rectangle the
   placement authored -- 4 screen pixels wider and taller at every zoom, since --inv cancels the
   scale. On a 30px marker that is 13%. Restoring the old size would cost .mark-cut an
   inset: calc(2px * var(--inv)), which is a layout property again and would put back what this
   removes, so it is not restored. */
/* No resting box on any marker (founder, 2026-08-17: «I don't want boxes anywhere»). The
   animal's own cut-out is the marker; a place is its always-visible name. The outline slot
   stays declared at width zero so forced-colours focus below can still hand it back. */
.mark {
  position: absolute;
  z-index: 3;
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  outline: 0 solid transparent;
  border-radius: calc(3px * var(--inv));
  cursor: pointer;
  min-width: 0;
  /* A finger press is answered by the marker's own mint, never by a borrowed blue box. */
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}

/* A marker whose creature has a cut-out shows the animal itself standing on the map; the
   box then only appears when a hand or the keyboard finds it, because the animal is the
   marker now and a frame around a standing creature reads as a sticker. */
.mark-cut {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;
  pointer-events: none;
  /* The animal is lit to sit in the world it stands on. Every backdrop is graded down to the
     realm's own key, and a licensed photograph arrives at the photographer's exposure — put
     the two together untouched and the creature reads as a sticker pasted on. This is CSS,
     never baked into the file: the shipped photograph stays the photograph, and the shadow
     stays a shadow rather than becoming a composite. */
  filter: drop-shadow(0 5px 12px rgba(5, 8, 10, 0.6)) brightness(0.82) saturate(0.88);
}

/* Sky only, and one stop darker. The dusk backdrop is the darkest key on the site, and the
   three birds that stand near the ground -- osprey, woodpecker, hummingbird -- were measured
   against the near-black forest behind them at up to +61 points of luminance, which is a
   daylight photograph sitting on a dusk painting. The other four are already darker than the
   sky they fly in, so this costs them a little of the gap that reads as silhouette; 0.74 is
   the step that takes the daylight highlight down without flattening them (see
   _runs/2026-09-02_fix_sky/grade/GRADE.md for the per-bird numbers). Luminance only: the
   backdrop is final art and is never regraded, and the photograph itself is never touched. */
.map:has(.map-bg[src*="/sky-"]) .mark-cut {
  filter: drop-shadow(0 5px 12px rgba(5, 8, 10, 0.6)) brightness(0.74) saturate(0.88);
}
/* Band 1. A marker carrying a z-index is its own stacking context, so a hidden creature's
   name goes under the plane with it — which is the seek working rather than a side effect:
   a label floating over the kelp would give the hiding place away, and the name arrives on
   press either way. Keyboard focus is the one exception, because a reader who has tabbed
   onto a marker has to be able to see which one they are on; :focus-visible never matches a
   press, so a hand cannot sweep the map with it and find the hides. */
.mark-hidden { z-index: 1; }
.mark-hidden:focus-visible { z-index: 3; }

/* Keyboard focus keeps its ring — the one box that stays, because a keyboard reader on a
   dense map has to see which marker they are on. A hand never sees it.
   Mint, and an outline: white on a photograph read as a big pale box round nothing, and it
   was the only stop on the whole site that was not the mint outline every other one uses
   (2026-09-01 audit F-05). The offset keeps the ring off the cut-out's own edge. */
.mark:focus-visible {
  outline: calc(2px * var(--inv)) solid var(--accent);
  outline-offset: calc(2px * var(--inv));
}
@media (forced-colors: active) {
  .mark:focus-visible { outline: calc(2px * var(--inv)) solid; outline-offset: calc(1px * var(--inv)); }
}

.mark-tag {
  position: absolute;
  /* The 6px gap rides in the transform, not in the inset. inset-block-end took
     calc(100% + 6px * var(--inv)) and an inset is a layout property, so it was the second half
     of the pinch cost measured on .mark above. Inside the transform the translate is scaled by
     the same --inv that counter-scales the label, which is what keeps the gap a constant 6
     screen pixels at every zoom -- and the compositor pays for it instead of layout. */
  inset-block-end: 100%;
  inset-inline-start: 0;
  transform: scale(var(--inv)) translateY(-6px);
  transform-origin: 0 100%;
  white-space: nowrap;
  user-select: none;
  font-family: var(--font-display);
  font-size: 16px;
  color: var(--accent);
  /* A blur is depth, not legibility: over the sky map's bright cloud the mint read at 1.1:1
     and the 6px shadow only spread the dark thinner (2026-09-01 audit F-02). The stroke is
     painted under the fill, so the letters keep their own shape and gain a dark rim that
     travels with them onto cloud, water or rock. One paint instead of a stack of shadows,
     and it counter-scales with the label, so the rim is the same weight at every zoom. */
  paint-order: stroke fill;
  -webkit-text-stroke: 3px rgba(6, 10, 12, 0.85);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.85);
  opacity: 0;
  transition: opacity 260ms ease;
}
[dir="rtl"] .mark-tag { inset-inline-start: auto; inset-inline-end: 0; transform-origin: 100% 100%; }
/* The same label under the marker instead of over it, for a marker standing at the top of
   the picture. mapsurface's onChange sets the class; the 6px gap still rides in the
   transform so it stays 6 screen pixels at every zoom. */
.mark-under .mark-tag {
  inset-block-end: auto;
  inset-block-start: 100%;
  transform: scale(var(--inv)) translateY(6px);
  transform-origin: 0 0;
}
[dir="rtl"] .mark-under .mark-tag { transform-origin: 100% 0; }
/* And from the marker's right edge, for a marker standing against the side of the frame. */
.mark-side .mark-tag { inset-inline: auto; right: 0; transform-origin: 100% 100%; }
.mark-side.mark-under .mark-tag { transform-origin: 100% 0; }
/* A creature's name is the answer, not a sign (founder, 2026-09-02: the reader looks for the
   animals). It shows only under the pointer or the keyboard ring, never at rest and never on
   zoom; the card and the page say it once the reader has found the animal. */
.mark:hover .mark-tag, .mark:focus-visible .mark-tag { opacity: 1; }
.mark-placed .mark-tag, .mark-named .mark-tag { color: rgba(232, 230, 227, 0.75); }
.mark-rich .mark-tag { color: var(--accent); }
/* A place carries no picture, so its name is its whole body on the map — always on,
   and over everything the map draws. It is the one label a reader steers by, so nothing
   may land on it: قنديل البحر hangs directly over غابة أعشاب البحر and its cut-out
   sat on the name at rest (2026-09-01 audit L-05). mapsurface moves the name to whichever
   side of its marker is clear; band 4 is what holds when both sides are taken. */
.mark-place { z-index: 4; }
.mark-place .mark-tag { opacity: 1; color: var(--accent); }
/* A door's name is mint when it shows (2026-09-01 audit B-10, C-06), but it no longer stands
   at rest: the founder's 2026-09-02 rule above wins, and the hunt is the same for every animal. */
.mark-open .mark-tag { color: var(--accent); }

/* ---- chrome over the picture ---- */

/* One h1 on the site. ar-type.css:96 has already said what an h1 is — 800 weight and
   clamp(30px, 3.6vw, 40px) — and a map was quietly answering 27px/700, so البحر on a map and
   البحر on a creature page were different headings of the same rank; at 1280 the gap was
   27 against 40 (2026-09-01 audit F-06). The override is gone rather than re-tuned. */
/* The scrim is the legibility, not the shadow. «البحر» stood at 2.7:1 on depths' bright
   sand (2026-09-01 audit F-01, needs 3.0) and a 14px blur cannot lift that: it spreads the
   dark instead of putting it behind the glyphs. A radial that fades to nothing has no edge
   and so is not one of the boxes the founder took off this site — it is the same darkening
   a title over a photograph has always been given, and it travels with the title onto sand,
   water or rock without any page having to know which it is standing on. */
.map-title {
  position: fixed;
  inset-block-start: max(14px, env(safe-area-inset-top));
  inset-inline-start: 18px;
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(30px, 3.6vw, 40px);
  font-weight: 800;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.8);
  pointer-events: none;
  isolation: isolate;
}
/* The scrim is a layer of its own rather than the heading's own background, because an
   Arabic display face draws outside its line box: on القاع الصخري the tail of the last glyph fell
   past the padding onto bright rock, and no padding could reach it — a background paints the
   box, and those pixels were never in the box. The insets are in em so the darkening grows
   with the type instead of being re-tuned per size, and the heading keeps its own 18px inset
   rather than paying for the scrim out of the layout. */
.map-title::before {
  content: "";
  position: absolute;
  inset: -0.36em -1.05em -0.42em;
  z-index: -1;
  background: radial-gradient(farthest-side ellipse at 50% 50%,
    rgba(6, 10, 12, 0.82) 0%, rgba(6, 10, 12, 0.7) 50%,
    rgba(6, 10, 12, 0.34) 80%, rgba(6, 10, 12, 0) 100%);
}
/* Both sides are held, not just the leading one: with a single inset the sentence stretched
   to the far edge and sat at x=0 under the notch. The safe-area terms are physical, so each
   logical side takes the larger of the two — a hint never has to know which way it mirrors. */
.map-hint {
  position: fixed;
  inset-block-end: max(14px, env(safe-area-inset-bottom));
  inset-inline-start: max(18px, env(safe-area-inset-left), env(safe-area-inset-right));
  inset-inline-end: max(18px, env(safe-area-inset-left), env(safe-area-inset-right));
  margin: 0;
  font-size: 13.5px;
  color: var(--muted);
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.9);
  pointer-events: none;
}
/* The gesture sign that replaced the hint sentence: two finger dots on one track. They slide
   together across the track (drag), then part (pinch out) and meet again. */
.gesture-cue {
  position: relative; display: inline-block; width: 56px; height: 22px;
  vertical-align: bottom;
}
/* The dots travel in +x; on the Arabic page the track is mirrored so they travel inward. */
html[dir='rtl'] .gesture-cue { transform: scaleX(-1); }
.gesture-cue::before, .gesture-cue::after {
  content: ''; position: absolute; top: 4px; width: 14px; height: 14px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 0 2px rgba(10, 14, 15, 0.7);
  animation: gesture-a 2.6s ease-in-out 0.6s 3 both;
}
.gesture-cue::after { animation-name: gesture-b; }
@keyframes gesture-a {
  0% { transform: translate(0, 0); opacity: 0.9; }
  30% { transform: translate(28px, 0); }
  45% { transform: translate(28px, 0); }
  65% { transform: translate(12px, -3px); }
  85%, 100% { transform: translate(28px, 0); }
}
@keyframes gesture-b {
  0% { transform: translate(0, 0); opacity: 0.9; }
  30% { transform: translate(28px, 0); }
  45% { transform: translate(28px, 0); }
  65% { transform: translate(42px, 3px); }
  85%, 100% { transform: translate(28px, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .gesture-cue::before, .gesture-cue::after { animation: none; }
  .gesture-cue::before { transform: translate(12px, -3px); }
  .gesture-cue::after { transform: translate(42px, 3px); }
}
.map-credit {
  position: fixed;
  inset-block-end: max(14px, env(safe-area-inset-bottom));
  inset-inline-end: max(18px, env(safe-area-inset-left), env(safe-area-inset-right));
  padding: 8px 0 4px;
  font-size: 13px;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid rgba(143, 208, 192, 0.35);
}
.map-credit:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* A quiet corner mark (founder, 2026-07-29): small words behind a small picture glyph. */
.map-credit {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 13px;
  opacity: 0.72;
  border-bottom: 0;
}
.map-credit:hover, .map-credit:focus-visible { opacity: 1; }
.map-credit::before {
  content: '';
  width: 13px;
  height: 13px;
  background: currentColor;
  -webkit-mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21 4H3a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h18a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1zM4 18v-2.2l4.6-4.6 3.4 3.4 4.4-4.4L20 13.8V18zM20 11l-3.6-3.6-4.4 4.4-3.4-3.4L4 13V6h16z"/><circle cx="9" cy="8.6" r="1.6"/></svg>') center / contain no-repeat;
  mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21 4H3a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h18a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1zM4 18v-2.2l4.6-4.6 3.4 3.4 4.4-4.4L20 13.8V18zM20 11l-3.6-3.6-4.4 4.4-3.4-3.4L4 13V6h16z"/><circle cx="9" cy="8.6" r="1.6"/></svg>') center / contain no-repeat;
}

/* The picture that can be entered says so under the finger. */
.pop-img.pop-door { cursor: pointer; }

/* Hint and credit are both pinned to the same bottom line with no reserved space between
   them, so on a narrow frame a hint that fits on one line runs straight under the link --
   which is what البحر does at 390px while القاع الصخري happens to wrap and escape it.
   On a phone the hint moves up a line instead, whatever the sentence turns out to be. */
/* Once a phone opens on the whole picture the map is a band on a dark mat, and a title
   pinned to the window sat 450px above the thing it names with nothing in between. The two
   numbers are written by mapsurface's layout() as the band moves, and they are 0 wherever
   the picture still fills the frame. The floor repeats topnav.css's own 65px/53px title
   inset so a title that has no band to hang from still clears the trail — so a laptop, and depths, which has no map surface at
   all, keep the window inset they have always had. The credit stays in the screen's own
   corner: it is a footnote to the page, not a caption to the picture. */
@media (max-width: 560px) {
  /* topnav.css sets this same property on .map-title and loads after this file, so the
     title is named by its element too — the floor below is topnav's own number. */
  h1.map-title { inset-block-start: max(max(65px, calc(env(safe-area-inset-top) + 53px)),
                                        calc(var(--band-top, 0px) - 58px)); }
  /* Under the band, not on it: the hint is about two lines tall (3.6em at its own size), so
     its bottom sits that far plus 18px inside the mat below the picture. */
  .map-hint { inset-block-end: max(calc(max(14px, env(safe-area-inset-bottom)) + 23px),
                                   calc(var(--band-bottom, 0px) - 3.6em - 18px)); }
}

html.popped .map-title, html.popped .map-hint, html.popped .map-credit, html.popped .mark-tag { opacity: 0; }
html:not(.popped) .map-title, html:not(.popped) .map-hint, html:not(.popped) .map-credit {
  transition: opacity 260ms ease 120ms;
}

.a11y-summary {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip-path: inset(50%);
}

/* ---- the pop-up ---- */

.map-pop {
  margin: 0; padding: 0; border: 0; max-width: none; max-height: none;
  width: 100%; height: 100%; background: transparent; color: var(--text); overflow: visible;
}
.map-pop::backdrop { background: transparent; }
.pop-scrim { position: fixed; inset: 0; background: rgba(6, 10, 12, 0.965); cursor: zoom-out; }

.pop-card {
  position: fixed;
  inset: 0;
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  justify-content: center;
  gap: 26px;
  padding: max(24px, env(safe-area-inset-top)) 24px;
  pointer-events: none;
}
.pop-card > * { pointer-events: auto; }

.pop-fig { margin: 0; display: flex; flex-direction: column; align-items: center; }
.pop-img {
  display: block;
  /* --nat is the file's own width, set by mapsurface. See the note beside paint(). */
  max-width: min(56vw, 720px, var(--nat, 100vw));
  max-height: 56vh;
  border-radius: var(--radius);
  background: #0B1013;
}
.pop-img[hidden] { display: none; }

/* Alternates. One mark per photograph of the same creature, under the picture it changes.
   The mark is small and the button around it is finger-sized, which is the whole reason
   these are buttons with padding rather than the dots the creature page draws. */
.pop-shots { display: flex; justify-content: center; gap: 4px; margin: 8px 0 0; }
.pop-shots[hidden] { display: none; }
.pop-shot {
  width: 44px;
  height: 32px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.pop-shot::before {
  content: '';
  display: block;
  width: 26px;
  height: 3px;
  margin: 0 auto;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.22);
  transition: background 180ms ease;
}
.pop-shot[aria-current]::before { background: var(--accent); }
@media (hover: hover) {
  .pop-shot:hover::before { background: rgba(143, 208, 192, 0.55); }
}

.pop-body { flex: 0 1 380px; }
.pop-body h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text);
}
.pop-sci { font-size: 15px; font-weight: 400; font-style: italic; color: var(--muted); }
.pop-line { font-size: 19px; line-height: 1.45; color: var(--accent); margin: 12px 0 0; }
.pop-src { margin: 12px 0 0; font-family: var(--font-mono); font-size: 13px; color: var(--muted); }
.pop-src a {
  display: inline-block;
  padding: 5px 0;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid rgba(143, 208, 192, 0.3);
}
.pop-state { margin: 14px 0 0; font-size: 13px; color: var(--muted); }
.pop-state[hidden] { display: none; }

/* ---- بطاقة وموجة: the rich card ---- */

/* Facts under the hook: each one a lead in bold and its body in the same breath. */
.pop-facts { margin: 16px 0 0; }
.pop-facts[hidden] { display: none; }
.pop-fact { margin: 11px 0 0; font-size: 15px; line-height: 1.7; color: var(--text); }
.pop-fact strong { font-weight: 700; }

/* The species a fact was measured on, and where it came from. Both ride at the end of the
   fact's own paragraph rather than in a footer, because a card may show several facts from
   several sources and a single line at the bottom cannot say which belongs to which. Sized
   and coloured like .pop-src above, which is the same job one level up. */
.pop-fact-who { font-size: 13px; color: var(--muted); }
.pop-fact-src { font-family: var(--font-mono); font-size: 13px; color: var(--muted); }
.pop-fact-src a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid rgba(143, 208, 192, 0.3);
}

/* The wave: short cards in the channel's voice, stepped sideways. The strip owns its own
   sideways scroll so the page body never does, and snap keeps one card composed at rest. */
.pop-wave {
  display: flex;
  gap: 12px;
  margin: 20px -4px 0;
  padding: 4px 4px 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
}
.pop-wave[hidden] { display: none; }
.wave-card {
  flex: 0 0 min(330px, 88%);
  scroll-snap-align: center;
  padding: 15px 17px 17px;
  background: rgba(255, 255, 255, 0.045);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.wave-t { margin: 0; font-family: var(--font-display); font-size: 16px; font-weight: 700; color: var(--accent); }
.wave-b { margin: 9px 0 0; font-size: 14px; line-height: 1.75; color: var(--text); }
.wave-ayah {
  margin: 13px 0 0;
  font-family: 'Amiri Quran', serif;
  font-size: 16px;
  line-height: 2.1;
  color: var(--text);
}
.wave-ref { margin: 5px 0 0; font-size: 13px; color: var(--muted); }

/* A long name and a long binomial fight over the heading line; on a rich card the species
   label always takes its own quiet line instead of wrapping word by word down the column. */
.map-pop.pop-rich .pop-sci { display: block; margin-top: 4px; }

/* A rich card is taller than a frame. On a desktop the words column scrolls inside itself,
   so the scrim stays clickable around it; the phone rule lives in the sheet block below. */
.map-pop.pop-rich .pop-body {
  /* A flex item's automatic minimum is min-content, and the wave strip's min-content is the
     strip unrolled — without this the words column inflates past its column and clips. */
  min-width: 0;
  max-width: 100%;
  max-height: min(78vh, 100%);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-inline-end: 6px;
}

.pop-enter {
  margin-top: 18px;
  padding: 11px 26px;
  min-height: 46px;
  background: none;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  color: var(--accent);
  font-family: var(--font-display);
  font-size: 17px;
  cursor: pointer;
}
.pop-enter:hover, .pop-enter:focus-visible { background: rgba(143, 208, 192, 0.12); }
.pop-enter[hidden] { display: none; }

.pop-close, .pop-prev, .pop-next {
  position: fixed;
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--muted);
  font-family: var(--font-body);
  font-size: 13px;
  min-height: 44px;
  padding: 0 14px;
  cursor: pointer;
}
/* A keyboard reader got the browser's default orange ring here — the one colour on this
   route that is in no palette on the site (2026-09-01 audit B-14). Same mint outline as
   every other stop; the border already changes colour underneath it. */
.pop-close:focus-visible, .pop-prev:focus-visible, .pop-next:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}
.pop-close:hover, .pop-prev:hover, .pop-next:hover,
.pop-close:focus-visible, .pop-prev:focus-visible, .pop-next:focus-visible {
  border-color: var(--accent); color: var(--accent);
}
.pop-close { inset-block-start: 16px; inset-inline-end: 16px; }
.pop-prev { inset-block-end: 16px; inset-inline-start: 16px; }
.pop-next { inset-block-end: 16px; inset-inline-start: 96px; }

.map-pop.anim .pop-body { animation: pop-rise 420ms cubic-bezier(0.22, 0.7, 0.2, 1) both; }
@keyframes pop-rise { from { opacity: 0; transform: translateY(10px); } }

/* On a phone the card stops pretending to be a desktop dialog and becomes what a phone
   already knows: picture edge to edge at the top, words on a sheet under it, and every
   control in the band the thumb actually reaches. Nothing here changes popover.js -- the
   flight still lands on .pop-img, which is now simply the width of the screen. */
@media (max-width: 700px) {
  .pop-card {
    align-content: flex-start;
    gap: 0;
    padding: 0 0 calc(76px + max(16px, env(safe-area-inset-bottom)));
  }
  /* A sheet needs something to be a sheet under. Most markers carry no photograph, and with
     the picture gone the words would hang from the top of the screen with the whole frame
     empty beneath them — so a card with nothing to sit under goes back to the middle. */
  .pop-card:has(.pop-img[hidden]) { align-content: center; }
  .pop-fig { flex: 1 1 100%; }
  .pop-img {
    width: 100vw;
    /* Edge to edge while the file can pay for it; a cut-out cut to a marker's footprint
       cannot, and is shown at its own size inside the same band rather than blown up. */
    max-width: min(100vw, var(--nat, 100vw));
    height: 52vh;
    max-height: 52vh;
    object-fit: cover;
    border-radius: 0;
  }
  /* A picture shown whole (mapsurface marks it) gives the band's height back: the hero
     is the picture's own size, breathing room above it, and the words rise to meet it. */
  .pop-img.pop-whole {
    width: auto;
    height: auto;
    max-height: 42vh;
    margin-top: max(28px, env(safe-area-inset-top));
  }
  .pop-body { flex: 1 1 100%; padding: 20px 20px 0; }
  .pop-body h2 { font-size: 25px; }
  /* A long name and a long binomial do not share a line at this width — the species ends up
     stranded on its own, italic and alone. Given its own line it reads as the small quiet
     label PLAN asks it to be. */
  .pop-sci { display: block; margin-top: 4px; }
  .pop-enter { width: 100%; }

  /* A rich card on a phone scrolls as one sheet: picture first, then the words, the hero
     sliding away as the reader reads. The card takes the pointer back for it, so the
     gap-tap close goes; the close button, Esc and Back all remain. Once the card is a
     scroll container, 100vw lies by a scrollbar's width — everything sizes to the card. */
  .map-pop.pop-rich .pop-card { overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; pointer-events: auto; }
  .map-pop.pop-rich .pop-img { width: 100%; max-width: min(100%, var(--nat, 100vw)); }
  .map-pop.pop-rich .pop-body { max-height: none; overflow-y: visible; padding-inline-end: 20px; }

  .pop-close, .pop-prev, .pop-next {
    inset-block-start: auto;
    inset-block-end: max(16px, env(safe-area-inset-bottom));
    font-size: 13px;
    padding: 0 10px;
  }
  .pop-prev { inset-inline-start: 16px; }
  /* Centred physically: the band reads prev-next-close whichever way the page mirrors. */
  .pop-next { inset-inline-start: auto; inset-inline-end: auto; left: 50%; transform: translateX(-50%); }
  .pop-close { inset-inline-end: 16px; }
}

/* Both halves of the motion rule: the scripted animations go through dur(), and every CSS
   animation named here is stilled by hand. */
@media (prefers-reduced-motion: reduce) {
  .map-pop.anim .pop-body { animation: none; }
  .mark-tag, html:not(.popped) .map-title,
  html:not(.popped) .map-hint, html:not(.popped) .map-credit,
  .pop-shot::before { transition: none; }
}
