/* Virtual Places. BUILD 1. Mobile-first, dark, about the world. */

* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { height: 100%; }
body {
  background: var(--ink);
  color: var(--text);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.5;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input { font: inherit; }
a { color: var(--limb); text-decoration: none; }
button:focus-visible, a:focus-visible, input:focus-visible {
  outline: 2px solid var(--limb);
  outline-offset: 3px;
}
/* The hidden attribute always wins, whatever display a class sets.
   (The Morning Window once rendered as an empty ghost box without
   this; Kent tried to type in it from a hotel in Mexico.) */
[hidden] { display: none !important; }

#app { position: fixed; inset: 0; }

/* ---------- The Earth stage (persists under everything) ---------- */
#globe {
  position: absolute; inset: 0;
  background: var(--ink);
}
/* Poster earth: shown until MapLibre streams in. A dark disk with a
   lit limb, drawn in CSS. The only gradient allowed is this one. */
#globePoster {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  transition: opacity 900ms ease;
}
#globePoster.gone { opacity: 0; pointer-events: none; }
#globePoster .disk {
  width: min(78vw, 420px);
  aspect-ratio: 1;
  border-radius: 50%;
  background:
    radial-gradient(circle at 32% 28%, rgba(var(--limb-rgb),0.16), transparent 55%),
    radial-gradient(circle at 50% 50%, #0c1526 0%, #080e1a 60%, #05090f 100%);
  box-shadow:
    inset -18px -14px 60px rgba(0,0,0,0.75),
    inset 10px 8px 40px rgba(var(--limb-rgb),0.10),
    var(--limb-glow);
}
/* A real sky: canvas starfield drawn once (static, reduced-safe) */
#stars { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

/* The atmosphere halo: the planet wears its own light, breathing */
#halo {
  position: absolute; inset: 0; pointer-events: none;
  /* B51, Kent's field order: a faint glow around the planet, blue
     into green. Two breaths of atmosphere: the limb's blue close in,
     a fainter aurora green further out. World, never chrome. */
  background:
    radial-gradient(ellipse 46% 34% at 50% 40%,
      rgba(var(--limb-rgb), 0.22), rgba(var(--limb-rgb), 0.07) 55%, transparent 72%),
    radial-gradient(ellipse 62% 46% at 50% 42%,
      rgba(var(--aurora-rgb), 0.10), rgba(var(--aurora-rgb), 0.03) 58%, transparent 80%);
  mix-blend-mode: screen;
  animation: halo-breathe 9s ease-in-out infinite;
}
@keyframes halo-breathe { 50% { opacity: 0.82; } }

/* Film grain over the world only: texture on imagery, never chrome */
#grain {
  position: absolute; inset: -20px;
  pointer-events: none;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="220" height="220"><filter id="n"><feTurbulence type="fractalNoise" baseFrequency="0.85" numOctaves="2" stitchTiles="stitch"/></filter><rect width="220" height="220" filter="url(%23n)" opacity="0.55"/></svg>');
  opacity: 0.05;
  mix-blend-mode: overlay;
}

/* The dive speaks: place names fading through the falling sky */
#diveCaption {
  position: absolute;
  left: 50%; top: 34%;
  transform: translateX(-50%);
  max-width: 86vw;
  pointer-events: none;
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(30px, 8vw, 46px);
  color: var(--text);
  text-align: center;
  text-shadow: 0 2px 24px rgba(var(--ink-rgb), 0.9);
  opacity: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#diveCaption.show { animation: caption-through 1050ms ease-in-out; }
@keyframes caption-through {
  0%   { opacity: 0; transform: translateX(-50%) translateY(14px) scale(0.985); }
  30%  { opacity: 1; }
  70%  { opacity: 1; }
  100% { opacity: 0; transform: translateX(-50%) translateY(-16px) scale(1.02); }
}

/* The limb arc: thin curved horizon structuring every overlay screen */
.limb-arc {
  position: absolute; left: 50%; transform: translateX(-50%);
  width: 160vw; height: 160vw; border-radius: 50%;
  pointer-events: none;
  border-top: 1px solid rgba(var(--limb-rgb), 0.35);
  box-shadow: 0 -18px 60px -12px rgba(var(--limb-rgb), 0.28);
}
.limb-arc.amber {
  border-top-color: rgba(var(--sodium-rgb), 0.4);
  box-shadow: 0 -18px 60px -12px rgba(var(--sodium-rgb), 0.3);
}

/* Atmosphere bloom during the dive */
#atmosphere {
  position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(ellipse at 50% 120%, rgba(var(--limb-rgb),0.22), transparent 55%);
  transition: opacity 600ms ease;
}
#atmosphere.bloom { opacity: 1; }

/* ---------- Screens ---------- */
.screen {
  position: absolute; inset: 0;
  display: none;
  flex-direction: column;
}
.screen.on { display: flex; }

/* Rooms rise to meet you: three tiers, one breath. The home veil's
   first three children (arc, wordmark, tagline) keep their own
   arrival choreography and are left alone here. */
#wonders.entering > *, #atlas.entering > *,
#home.entering .veil-scroll > :nth-child(n+3) {
  animation: tier-rise 300ms var(--ease-settle) backwards;
}
#wonders.entering > :nth-child(2), #atlas.entering > :nth-child(2),
#home.entering .veil-scroll > :nth-child(n+5) { animation-delay: 60ms; }
#wonders.entering > :nth-child(n+3), #atlas.entering > :nth-child(n+3),
#home.entering .veil-scroll > :nth-child(n+6) { animation-delay: 120ms; }
@keyframes tier-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- HOME ---------- */
/* The Earth is the point of this room: the veil may NEVER swallow it
   (Kent: we don't see the Earth anymore). The veil caps at ~68vh and
   scrolls inside itself; the top of home stays naked turning planet.
   Bottom anchor is margin-top:auto, NOT justify-end: end-justified
   overflow is unscrollable at the start edge in every engine. */
#home { pointer-events: none; overflow: hidden; display: flex; flex-direction: column; }
#home > * { pointer-events: auto; }
#home .home-veil {
  margin-top: auto;
  /* B51, Kent's field order: bring the words DOWN, show more of the
     turning planet. 68vh gave the Earth 37% of a phone; 55vh gives
     it ~45%. The scroll inside carries whatever no longer fits. */
  max-height: min(55vh, 520px);
  display: flex;
  flex-direction: column;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
}
/* the SCROLL lives one level in, so the limb arc crowning the veil
   never gets clipped by its own scrollbox */
.veil-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
}
.veil-scroll::-webkit-scrollbar { display: none; }

/* How the Earth is lit: the user's call, kept.
   B54, Kent's field find: #home stays displayed under every room
   (the Earth-window law), so the z-raised pill bled through onto
   My places and could even steal taps there. The pill exists only
   while the Earth room is the front room. */
#home:not(.on) .home-mode { display: none; }
/* B65: the whole veil steps out of sight when home is not the room in
   front. It stayed painted under every other room, and showed through
   on the Above and City rungs and under every dive (the wordmark, the
   search bar and the Morning Window over the plate sheet). */
#home:not(.on) .home-veil { visibility: hidden; }
.home-mode {
  position: absolute;
  top: calc(env(safe-area-inset-top) + 14px);
  right: 14px;
  /* above the veil, always: paint order buried it untappable */
  z-index: 5;
  display: flex; gap: 2px;
  /* B51: Kent could not find the pill in the field; it must read
     against bright daylight Earth as clearly as against stars */
  background: rgba(var(--surface-rgb), 0.88);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  padding: 4px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.home-mode button {
  min-height: 44px;
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 12px; font-weight: 600;
  color: var(--text-dim);
  transition: color 200ms ease, background 200ms ease;
}
.home-mode button.on { background: var(--surface-2); color: var(--text); }

.home-veil {
  position: relative;
  padding: var(--pad);
  padding-top: 32px;
  padding-bottom: max(var(--pad), env(safe-area-inset-bottom));
  /* thinner glass: the turning Earth stays present behind the words */
  background: rgba(var(--ink-rgb), 0.66);
  backdrop-filter: blur(14px) saturate(1.2);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
}
.home-veil .limb-arc { top: -22px; }

.wordmark {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(38px, 11vw, 54px);
  line-height: 0.94;
  letter-spacing: -0.025em;
  font-variation-settings: "opsz" 144;
  animation: word-rise 700ms var(--ease-settle) 150ms backwards;
}
.tagline {
  color: var(--text-soft);
  font-size: 16px;
  line-height: 1.4;
  margin: 8px 0 24px;
  animation: word-rise 700ms var(--ease-settle) 280ms backwards;
}
@keyframes word-rise {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}
/* The arc draws itself once at first light */
.home-veil .limb-arc { animation: arc-draw 1100ms ease-out 100ms backwards; }
@keyframes arc-draw {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

/* The Morning Window: a real window now, the place as the backdrop */
.window-card {
  position: relative;
  width: 100%;
  min-height: 128px;
  display: flex; align-items: flex-end; gap: 14px;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  padding: 14px 16px;
  margin-bottom: 12px;
  text-align: left;
  box-shadow: var(--lift-2);
  transition: transform 150ms var(--ease-settle), border-color 200ms ease;
}
.window-card:active { transform: scale(0.98); }
.home-hint {
  color: var(--text-dim);
  font-size: 13px;
  margin: -12px 0 14px;
}

/* Dawn is happening somewhere: a live invitation, no API behind it */
.dawn-line {
  margin-top: 12px;
  width: 100%;
  text-align: left;
  font-family: var(--serif);
  font-style: italic;
  font-size: 15px;
  line-height: 1.4;
  color: var(--sodium);
  opacity: 0.9;
  transition: opacity 200ms ease;
}
.dawn-line:active { opacity: 1; }
.window-card .wc-bg {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
/* the scrim rides the imagery (lawful) and carries the shelf's light */
.window-card .wc-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(var(--ink-rgb), 0.92) 0%, rgba(var(--ink-rgb), 0.35) 55%, rgba(var(--ink-rgb), 0.15) 100%);
  border-left: 2px solid var(--t, var(--sodium));
}
.window-card .wc-body { position: relative; flex: 1; min-width: 0; display: block; }
.window-card .wc-name {
  display: block;
  font-family: var(--serif); font-weight: 600; font-size: 22px; line-height: 1.15;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-shadow: 0 1px 12px rgba(var(--ink-rgb), 0.8);
}
.window-card .wc-line {
  display: block; color: var(--text-soft); font-size: 13px; margin-top: 4px;
  text-shadow: 0 1px 8px rgba(var(--ink-rgb), 0.8);
}
.window-card .wc-go {
  position: relative; flex: none;
  font-size: 13px; font-weight: 600;
  color: var(--sodium);
  text-shadow: 0 1px 8px rgba(var(--ink-rgb), 0.9);
}

/* Voice pinned to a place */
.voice-row { margin: 0 0 10px; }
.voice-cta, .voice-live, .voice-has { display: flex; align-items: center; gap: 10px; }
.voice-cta button, .voice-has button, .voice-live button {
  min-height: 44px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  font-size: 13px; font-weight: 600;
  padding: 8px 14px;
  display: flex; align-items: center; gap: 8px;
  transition: border-color 200ms ease, color 200ms ease;
}
.voice-cta button { flex: 1; justify-content: center; color: var(--text-dim); }
.voice-cta button:hover, .voice-cta button:active { color: var(--text); border-color: var(--sodium); }
.voice-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--sodium); flex: none;
}
.voice-live .voice-dot { animation: voice-pulse 1200ms ease-in-out infinite; }
@keyframes voice-pulse { 50% { opacity: 0.3; transform: scale(0.8); } }
.voice-live .vtime { font-family: var(--mono); font-size: 13px; color: var(--sodium); flex: 1; }
.voice-live button { border-color: var(--sodium); color: var(--text); }
.voice-has .vlen { font-family: var(--mono); font-size: 12px; color: var(--text-dim); flex: 1; }
.voice-has button.playing { border-color: var(--sodium); color: var(--sodium); }

/* Atlas tools */
.film-btn {
  min-height: 44px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  font-size: 13px; font-weight: 600;
  padding: 6px 14px;
  color: var(--text-dim);
  transition: color 200ms ease, border-color 200ms ease;
}
.film-btn:hover, .film-btn:active { color: var(--text); border-color: var(--sodium); }
/* Atlas custody: the calm ask that keeps a kept life safe (B55) */
#custody {
  margin: 0 0 16px;
  padding: 16px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  box-shadow: var(--lift-1);
}
.cust-name {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 18px;
  margin-bottom: 6px;
}
.cust-line {
  color: var(--text-dim);
  font-size: 13px;
  line-height: 1.5;
  margin-bottom: 8px;
}
.cust-row { display: flex; gap: 10px; margin-top: 10px; }
.cust-row button {
  min-height: 44px;
  padding: 8px 16px;
  border-radius: 999px;
  font-size: 13px; font-weight: 600;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--line);
}
.cust-row .cust-how { background: var(--sodium); color: var(--on-sodium); border-color: transparent; }
/* POST-REVIEW: the review's press-physics gap: these buttons give too */
.cust-row button, #ddShare, #ddStand {
  transition: transform 150ms var(--ease-settle), border-color 200ms ease;
}
.cust-row button:active, #ddShare:active, #ddStand:active { transform: scale(0.96); }

.atlas-tools {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  padding: 26px var(--pad) 0;
  max-width: 720px; margin: 0 auto;
}
.atlas-tools button {
  min-height: 44px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  color: var(--text-faint);
  font-size: 13px;
  transition: color 200ms ease, border-color 200ms ease;
}
.atlas-tools button:hover, .atlas-tools button:active { color: var(--text-dim); border-color: var(--silver); }

/* The local air: live radio pinned to the ground you stand on */
.radio-row { margin-top: 10px; }
.radio-btn {
  width: 100%;
  min-height: 44px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--text-dim);
  font-size: 13px; font-weight: 600;
  padding: 8px 14px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  transition: border-color 200ms ease, color 200ms ease;
}
.radio-btn:hover, .radio-btn:active { color: var(--text); border-color: var(--limb); }
.radio-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--limb); flex: none;
}
.radio-dot.tuning, .radio-dot.live { animation: voice-pulse 1200ms ease-in-out infinite; }
.radio-on {
  display: flex; align-items: center; gap: 10px;
  min-height: 44px;
  border: 1px solid rgba(var(--limb-rgb), 0.4);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  padding: 8px 8px 8px 14px;
}
.radio-on .radio-name {
  flex: 1; min-width: 0;
  font-size: 13px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.radio-on #radioOff {
  flex: none;
  min-height: 44px;
  padding: 6px 12px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-strong);
  color: var(--text-dim);
  font-size: 13px; font-weight: 600;
}
.radio-on #radioOff:hover, .radio-on #radioOff:active { color: var(--text); }
.radio-quiet {
  display: block; text-align: center;
  color: var(--text-faint); font-size: 13px;
  padding: 12px 0;
}

/* Then: the archive chips, NYC first */
.then-row {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 10px; margin-top: 12px;
}
.then-chip {
  display: flex; align-items: center; justify-content: center;
  min-height: 44px;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  color: var(--silver);
  font-size: 13px; font-weight: 600;
  padding: 8px;
  transition: color 200ms ease, border-color 200ms ease;
}
.then-chip:hover, .then-chip:active { color: var(--text); border-color: var(--silver); }

.searchbar {
  display: flex; gap: 10px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  padding: 6px 6px 6px 16px;
  align-items: center;
  transition: border-color 200ms ease, box-shadow 200ms ease;
}
.searchbar:focus-within { border-color: rgba(var(--limb-rgb),0.5); box-shadow: var(--limb-glow); }
.searchbar input {
  flex: 1; min-width: 0;
  background: none; border: 0; outline: 0;
  color: var(--text);
  font-size: 16px;
  padding: 10px 0;
}
.searchbar input::placeholder { color: var(--text-faint); }
.searchbar .mic {
  flex: none;
  width: 44px; min-height: 44px;
  border-radius: var(--r-sm);
  color: var(--text-dim);
  font-size: 12px;
  transition: color 200ms ease;
}
.searchbar .mic.listening { color: var(--sodium); animation: voice-pulse 1200ms ease-in-out infinite; }
.searchbar .go {
  background: var(--limb);
  color: var(--on-limb);
  font-weight: 600;
  border-radius: var(--r-sm);
  padding: 10px 18px;
  transition: transform 150ms var(--ease-settle), filter 150ms ease;
}
.searchbar .go:active { transform: scale(0.96); filter: brightness(1.15); }

.chips {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 14px;
}
.chip {
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 10px;
  min-height: 48px;
  padding: 12px 14px;
  font-size: 15px;
  color: var(--text-dim);
  text-align: left;
  transition: color 200ms ease, border-color 200ms ease;
}
.chip:hover, .chip:active { color: var(--text); border-color: var(--line-strong); }

/* The teleport strip: your places, one tap from the door */
.teleport {
  display: flex; gap: 14px;
  margin-top: 16px;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  padding: 2px;
  cursor: grab;
}
.teleport:active { cursor: grabbing; }
/* the fade only while there IS more: at the strip's end it was
   dissolving the last thumb into nothing (deep-dive catch) */
.teleport.more-right, .seven-strip.more-right {
  mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 40px), transparent);
  -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 40px), transparent);
}
.teleport::-webkit-scrollbar { display: none; }
.tp {
  flex: none; width: 64px;
  display: grid; justify-items: center; gap: 6px;
}
.tp img {
  width: 56px; height: 56px;
  border-radius: 50%; object-fit: cover;
  box-shadow: 0 0 0 2px var(--t, var(--line-strong));
  filter: saturate(0.9);
  transition: transform 150ms var(--ease-settle);
}
.tp:active img { transform: scale(0.92); }
.tp span {
  font-size: 11px; font-weight: 600; /* the caption role, one voice */
  letter-spacing: 0.02em;
  color: var(--text-dim);
  max-width: 64px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.buildtag {
  margin-top: 10px;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--text-faint);
  display: flex; justify-content: flex-end;
  opacity: 0.6;
}

/* ---------- PLACE ---------- */
#place { pointer-events: none; }
#place > * { pointer-events: auto; }
/* The layout spacer must never eat a tap meant for the world beneath:
   it sat exactly where a Daily Drop guess lands (Kent's dead globe) */
#place > .spacer { pointer-events: none; }

.place-top {
  display: flex; align-items: center; gap: 12px;
  padding: max(14px, env(safe-area-inset-top)) var(--pad) 10px;
  position: relative; z-index: 45; /* always above the panorama */
}

/* The lens pill: four ways of seeing the same world */
.lens-pill {
  display: flex; gap: 2px;
  background: rgba(var(--surface-rgb), 0.72);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 4px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.lens-pill button {
  min-height: 44px;
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 12px; font-weight: 600;
  color: var(--text-dim);
  transition: color 200ms ease, background 200ms ease;
}
.lens-pill button.on { background: var(--surface-2); color: var(--text); }
.back {
  width: 44px; height: 44px; border-radius: 50%;
  background: rgba(var(--surface-rgb), 0.8);
  border: 1px solid var(--line);
  display: grid; place-items: center;
  font-size: 18px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

/* The pin: one tap keeps the ground you are standing on */
.pin-btn {
  margin-left: auto;
  width: 44px; height: 44px; border-radius: 50%;
  background: rgba(var(--surface-rgb), 0.8);
  border: 1px solid var(--line);
  display: grid; place-items: center;
  color: var(--text-dim);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: color 200ms ease, border-color 200ms ease;
  z-index: 45;
}
.pin-btn svg {
  width: 20px; height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.pin-btn.pinned { color: var(--sodium); border-color: rgba(var(--sodium-rgb), 0.5); }
.pin-btn.pinned svg { fill: rgba(var(--sodium-rgb), 0.25); }
.pin-btn:active { transform: scale(0.94); }

/* Street panel: fills the stage when street rung is active.
   Keyless it is GLASS: the live satellite stays visible underneath,
   one sodium streetlight marks the rooftop, a slim band hands off. */
#streetPanel {
  position: absolute; inset: 0;
  display: none;
  background: var(--ink);
  z-index: 5; /* under the controls, always */
}
#streetPanel.on { display: block; }
#streetPanel.fallback { background: transparent; pointer-events: none; }
#streetPanel iframe { width: 100%; height: 100%; border: 0; }

.street-dot {
  position: absolute; left: 50%; top: 50%;
  width: 10px; height: 10px; margin: -5px 0 0 -5px;
  border-radius: 50%;
  background: var(--sodium);
  box-shadow: var(--sodium-glow);
  animation: dot-in 600ms var(--ease-settle) backwards;
}
@keyframes dot-in {
  from { transform: scale(0); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}

.street-band {
  pointer-events: auto;
  position: absolute;
  left: 20px; right: 84px;
  top: calc(env(safe-area-inset-top) + 70px);
  max-width: 420px;
  display: flex; align-items: center; gap: 12px;
  background: rgba(var(--surface-rgb), 0.88);
  border: 1px solid var(--line-strong);
  border-top: 1px solid rgba(var(--sodium-rgb), 0.45);
  border-radius: var(--r-md);
  padding: 12px 14px;
}
.street-band .sb-body { flex: 1; min-width: 0; }
.street-band h3 {
  font-family: var(--serif); font-weight: 600; font-size: 20px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.street-band p { color: var(--text-dim); font-size: 13px; margin-top: 1px; }
.street-band .open-street {
  flex: none;
  background: var(--sodium);
  color: var(--on-sodium);
  font-weight: 600; font-size: 13px;
  border-radius: var(--r-sm);
  min-height: 44px;
  padding: 10px 14px;
  transition: transform 150ms var(--ease-settle);
}
.street-band .open-street:active { transform: scale(0.96); }

/* Orbit panel: today's Earth, centered in the air ABOVE the sheet
   so the photograph and its caption are never covered */
#orbitPanel {
  position: absolute; inset: 0;
  display: none;
  background: var(--ink);
  place-items: center;
  padding: calc(env(safe-area-inset-top) + 60px) 0 176px;
  z-index: 5;
}
#orbitPanel.on { display: grid; }
#orbitPanel .orbit-wrap {
  position: relative; display: block;
  width: min(86vw, 40vh, 480px);
  /* the story lines widened the figure and the Earth drifted off
     center (Kent's sideways planet); the disk owns the middle */
  margin: 0 auto;
}

/* Tonight breathes: the room arrives in tiers, the halo swells like
   slow breathing, every day-swap re-enters. All of it stands down
   under reduced motion. */
@media (prefers-reduced-motion: no-preference) {
  #orbitPanel .orbit-wrap::after {
    content: ""; position: absolute; inset: -5%;
    border-radius: 50%;
    box-shadow: 0 0 90px 10px rgba(var(--limb-rgb), 0.32);
    /* its OWN keyframes: reusing halo-breathe silently retuned the
       home halo (last definition wins document-wide; deep-dive) */
    animation: orbit-halo-breathe 7s ease-in-out infinite;
    pointer-events: none;
  }
  #orbitPanel figure > * { animation: tier-rise 400ms var(--ease-settle) backwards; }
  #orbitPanel .orbit-wrap { animation: disk-arrive 700ms var(--ease-settle) backwards; }
  #orbitPanel figcaption { animation-delay: 90ms; }
  #orbitPanel .night-head { animation-delay: 160ms; }
  #orbitPanel .sky-lines { animation-delay: 230ms; }
  #orbitPanel .time-strip { animation-delay: 300ms; }
}
@keyframes orbit-halo-breathe { 50% { opacity: 0.4; } }
@keyframes disk-arrive {
  from { opacity: 0; transform: scale(0.94); }
  to   { opacity: 1; transform: scale(1); }
}
#orbitPanel img {
  width: 100%;
  border-radius: 50%;
  box-shadow: var(--limb-glow);
  display: block;
}
/* The bright star: where the place is, on today's actual Earth */
.orbit-star {
  position: absolute;
  width: 10px; height: 10px;
  margin: -5px 0 0 -5px;
  border-radius: 50%;
  background: var(--sodium);
  box-shadow: 0 0 10px 2px rgba(var(--sodium-rgb), 0.9), 0 0 26px 8px rgba(var(--sodium-rgb), 0.35);
  animation: star-breathe 2600ms ease-in-out infinite;
}
@keyframes star-breathe {
  50% { box-shadow: 0 0 14px 3px rgba(var(--sodium-rgb), 1), 0 0 34px 12px rgba(var(--sodium-rgb), 0.45); }
}

/* The stride: walk the street with two big honest buttons */
.stride {
  position: absolute;
  left: max(14px, env(safe-area-inset-left)); top: 50%;
  transform: translateY(-50%);
  display: flex; flex-direction: column; gap: 10px;
  z-index: 40;
}
.stride .step {
  width: 54px; height: 54px;
  border-radius: 50%;
  background: rgba(var(--surface-rgb), 0.85);
  border: 1px solid var(--line-strong);
  color: var(--sodium);
  font-size: 16px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: transform 150ms var(--ease-settle), border-color 200ms ease;
  /* holding is a gesture now: no double-tap zoom, no long-press
     menu, and NO panning from the buttons at all: a held finger's
     tiny drift was turning the walk into a page-pan and cutting
     the chain (B53, Kent on Fuji) */
  touch-action: none;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
}
/* until the first real held walk, the arrow teaches itself: three
   soft breaths on every fresh street, then never again */
.stride.teach .fwd { animation: walk-teach 2.4s ease-in-out 3; }
@keyframes walk-teach {
  50% { box-shadow: 0 0 14px 3px rgba(var(--sodium-rgb), 0.55); transform: scale(1.06); }
}
.stride .step:active { transform: scale(0.92); border-color: var(--sodium); }
/* A lone photosphere has no exits: the walk buttons step aside */
.stride.no-walk .fwd, .stride.no-walk .bck { display: none; }
/* B48, the walk feel: the arrow leans the way the road bends, dims
   past a walkable turn, and pulses while the hands-free walk is on */
.stride .fwd .glyph { display: inline-block; transition: transform 240ms var(--ease-settle); }
.stride.off-axis .fwd { opacity: 0.55; }
.stride.walking .fwd { border-color: var(--sodium); animation: walk-pulse 1700ms ease-in-out infinite; }
@keyframes walk-pulse { 50% { box-shadow: 0 0 12px 2px rgba(var(--sodium-rgb), 0.5); } }
/* Every stride is felt: one breath of forward motion per step */
#streetPanel.stepping { animation: step-in 280ms var(--ease-settle); }
@keyframes step-in {
  0% { transform: scale(1); }
  35% { transform: scale(1.035); }
  100% { transform: scale(1); }
}
/* In the theater, the door out wears a plain X and stronger ink */
.stride .step.exit {
  color: var(--text);
  border-color: var(--line-strong);
  background: rgba(var(--surface-rgb), 0.94);
  font-size: 20px;
}
#orbitPanel figcaption {
  margin-top: 14px; text-align: center;
  font-family: var(--mono); font-size: 12px; color: var(--text-dim);
  /* the line ran edge to edge at phone width (B62): breathing room,
     and the two lines balance instead of orphaning the credit */
  padding: 0 22px;
  text-wrap: balance;
  line-height: 1.5;
}

/* Turning back the days: the Earth of other days, photographs only */
/* Tonight's voice: the place of the night, named */
.night-head {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 600;
  font-size: 18px;
  line-height: 1.4;
  color: var(--text);
  text-align: center;
  max-width: 360px;
  margin: 14px auto 0;
  cursor: pointer;
  text-decoration: underline dotted rgba(var(--sodium-rgb), 0.5);
  text-underline-offset: 4px;
}
.sky-lines {
  margin-top: 8px;
  text-align: center;
}
.sky-lines p {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
  /* the ISS line was printing edge to edge into the notch zone */
  max-width: 340px;
  margin-left: auto;
  margin-right: auto;
}

.time-strip {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 8px;
  margin: 14px auto 0;
  max-width: 300px; /* two by two, never three and one */
}
.time-strip button {
  min-height: 44px;
  padding: 8px 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--text-dim);
  font-size: 13px; font-weight: 600;
  transition: color 200ms ease, border-color 200ms ease, background 200ms ease,
    transform 150ms var(--ease-settle);
}
.time-strip button:active { transform: scale(0.95); }
.time-strip button:active { color: var(--text); }
.time-strip button.on {
  background: var(--surface-2);
  color: var(--text);
  border-color: var(--line-strong);
}

/* Altitude rail: 4 rungs + the readout, right edge, clear of the
   plate on every phone height (top-anchored, not centered) */
.rail {
  position: absolute; right: 10px;
  z-index: 45;
  top: calc(env(safe-area-inset-top) + 76px);
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  background: rgba(var(--surface-rgb), 0.72);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 8px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.rung {
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--mono); font-size: 10px;
  color: var(--text-dim);
  transition: background 200ms ease, color 200ms ease, transform 150ms var(--ease-settle);
}
.rung:active { transform: scale(0.94); }
.rung.on { background: var(--limb); color: var(--on-limb); }

/* Altimeter readout: counts the descent, lands on 0 M at the thump.
   Lives at the rail's foot so it can never collide with the plate. */
.altimeter {
  font-family: var(--mono); font-size: 10px;
  color: var(--text-dim);
  writing-mode: vertical-rl;
  letter-spacing: 0.08em;
  opacity: 0.85;
  padding: 6px 0 10px;
  min-height: 58px;
  transition: color 300ms ease;
}
.altimeter.live { color: var(--limb); }
/* Touchdown: the number lands with one bright flick */
.altimeter.flick { animation: alt-flick 320ms ease-out; }
@keyframes alt-flick {
  0% { color: var(--sodium); filter: brightness(1.9); }
  100% { filter: none; }
}

/* The dive holds the instruments back; touchdown releases them.
   The rail keeps its own transition (it carries the altimeter). */
.place-top, .plate {
  transition: opacity 500ms var(--ease-settle), transform 500ms var(--ease-settle);
}
.rail { transition: opacity 500ms var(--ease-settle), background 200ms ease; }
#place.diving .place-top,
#place.diving .plate {
  opacity: 0;
  transform: translateY(18px);
  pointer-events: none;
}
#place.diving .rail { opacity: 0; pointer-events: none; }
#place.diving .altimeter { opacity: 1; }
/* During the dive only the falling number shows, riding the rail spot */
#place.diving .rail.counting { opacity: 1; background: transparent; border-color: transparent; }
#place.diving .rail.counting .rung { opacity: 0; }

/* The plate: one caption card pinned beneath every altitude */
.plate {
  position: relative;
  z-index: 30;
  margin: 0 var(--pad);
  /* the navbar lives below at all times now */
  margin-bottom: calc(max(var(--pad), env(safe-area-inset-bottom)) + 66px);
  background: rgba(var(--surface-rgb), 0.92);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  padding: 18px;
  overflow: hidden;
  animation: plate-in 400ms var(--ease-settle);
}
@keyframes plate-in {
  from { transform: translateY(14px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}
.plate .limb-arc {
  top: -158vw; opacity: 0.5;
  border-top-color: var(--arc-c, rgba(var(--limb-rgb), 0.35));
  box-shadow: 0 -18px 60px -12px var(--arc-g, rgba(var(--limb-rgb), 0.28));
}
.plate h2 {
  font-family: var(--serif); font-weight: 600;
  font-size: clamp(25px, 7vw, 32px); line-height: 1.15;
}
.plate .coords {
  font-family: var(--mono); font-size: 12px;
  color: var(--text-dim);
  margin: 5px 0 10px;
  letter-spacing: 0.03em;
  min-height: 1.2em;
}
.plate .coords .cur { animation: cur-blink 900ms steps(1) infinite; }
@keyframes cur-blink { 50% { opacity: 0; } }
/* When the photograph was really made: the honesty line */
.plate .seen {
  font-family: var(--mono); font-size: 10px;
  color: var(--text-faint);
  letter-spacing: 0.05em;
  margin: -6px 0 8px;
}
/* How far this street is from the first one */
.plate .fromhome {
  font-family: var(--mono); font-size: 10px;
  color: var(--silver);
  letter-spacing: 0.08em;
  margin: -6px 0 8px;
}
/* The memory line: what you wrote, standing there */
.plate .memory {
  font-family: var(--serif); font-style: italic; font-weight: 400;
  font-size: 20px; line-height: 1.35;
  margin: 0 0 8px;
}
.plate .intel {
  color: var(--text-dim); font-size: 13px;
  min-height: 1.4em;
}
.plate .intel + .intel { margin-top: 2px; }
.plate .actions {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 10px; margin-top: 14px;
}
.plate .actions button {
  border-radius: var(--r-md);
  padding: 13px 10px;
  font-weight: 600; font-size: 15px;
  transition: transform 150ms var(--ease-settle);
}
.plate .actions button:active { transform: scale(0.97); }
.keep { background: var(--sodium); color: var(--on-sodium); }
.share { background: var(--surface-2); border: 1px solid var(--line-strong); color: var(--text); }
/* the quiet third door: the view as a wallpaper */
.poster-link {
  width: 100%; margin-top: 12px;
  min-height: 44px;
  color: var(--text-faint);
  font-size: 13px;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.poster-link:hover, .poster-link:active { color: var(--silver); }
#place.earth-mode .poster-link, #place.drop-mode .poster-link { display: none; }

/* ---------- ATLAS ---------- */
#atlas {
  background: var(--ink);
  overflow-y: auto;
  padding: max(14px, env(safe-area-inset-top)) 0 40px;
}
.atlas-head {
  display: flex; align-items: center; gap: 12px;
  padding: 0 var(--pad) 6px;
}
.atlas-head h1 { font-family: var(--serif); font-weight: 600; font-size: 26px; flex: 1; }
.atlas-count { font-family: var(--mono); font-size: 12px; color: var(--text-dim); }

/* Two readings of one atlas */
.atlas-pill {
  display: flex; gap: 2px;
  margin: 8px var(--pad) 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 4px;
  width: fit-content;
}
.atlas-pill button {
  min-height: 44px;
  padding: 7px 16px;
  border-radius: 999px;
  font-size: 13px; font-weight: 600;
  color: var(--text-dim);
  transition: color 200ms ease, background 200ms ease;
}
.atlas-pill button.on { background: var(--surface-2); color: var(--text); }

/* The timeline: a life in decades, hung on one thin light */
.tl {
  margin: 18px var(--pad) 0;
  padding-left: 18px;
  border-left: 1px solid rgba(var(--limb-rgb), 0.28);
  max-width: 560px;
}
.tl-decade {
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.14em;
  color: var(--silver);
  margin: 22px 0 10px;
  position: relative;
}
.tl-decade:first-child { margin-top: 4px; }
.tl-decade::before {
  content: ""; position: absolute;
  left: -22.5px; top: 5px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--limb);
  box-shadow: 0 0 10px rgba(var(--limb-rgb), 0.6);
}
.tl-row {
  position: relative;
  width: 100%;
  display: flex; align-items: center; gap: 12px;
  padding: 8px 10px 8px 0;
  border-radius: var(--r-md);
  text-align: left;
  transition: transform 150ms var(--ease-settle);
  animation: plate-in 240ms var(--ease-settle) backwards;
  animation-delay: calc(var(--i, 0) * 30ms);
}
.tl-row:active { transform: scale(0.98); }
.tl-row .tl-dot {
  position: absolute; left: -22.5px; top: 50%;
  width: 8px; height: 8px; margin-top: -4px;
  border-radius: 50%;
  background: var(--t, var(--line-strong));
}
.tl-row img {
  width: 46px; height: 46px; flex: none;
  border-radius: 10px; object-fit: cover;
  box-shadow: 0 0 0 1.5px var(--t, var(--line-strong));
  filter: saturate(0.9);
}
.tl-row .tl-body { flex: 1; min-width: 0; }
.tl-row .tl-name {
  display: block;
  font-family: var(--serif); font-weight: 600; font-size: 16px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tl-row .tl-note {
  display: block;
  font-family: var(--serif); font-style: italic; font-weight: 400;
  font-size: 13px; color: var(--text-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tl-row .tl-year {
  flex: none;
  font-family: var(--mono); font-size: 12px;
  color: var(--text-dim);
}
.tl-empty, .tl-hint {
  margin: 26px var(--pad) 0;
  color: var(--text-faint);
  font-size: 13px;
  max-width: 400px;
}
.tl .tl-hint { margin: 4px 0 14px; }

.shelf { padding: 14px var(--pad) 0; }
.shelf h3 {
  font-size: 13px; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-dim);
  display: flex; align-items: center; gap: 8px;
}
.shelf h3 .dot { width: 8px; height: 8px; border-radius: 50%; }
.shelf-grid {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 12px; margin-top: 10px;
}

/* A saved place is a plate */
.place-card {
  position: relative; overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  text-align: left;
  transition: transform 150ms var(--ease-settle), border-color 200ms ease;
}
.place-card:active { transform: scale(0.97); }
.place-card img {
  width: 100%; aspect-ratio: 8 / 5;
  object-fit: cover; display: block;
  filter: saturate(0.9);
}
.place-card .pc-body { padding: 10px 12px 12px; }
.place-card .pc-name {
  font-family: var(--serif); font-weight: 600; font-size: 15px;
  line-height: 1.3;
}
.place-card .pc-meta {
  font-family: var(--mono); font-size: 10px;
  color: var(--text-dim); margin-top: 3px;
}
.place-card .pc-note {
  font-family: var(--serif); font-style: italic; font-weight: 400;
  font-size: 13px;
  color: var(--text-dim); margin-top: 5px;
}
/* Shelf entrance: plates arrive in reading order */
.place-card {
  animation: plate-in 240ms var(--ease-settle) backwards;
  animation-delay: calc(var(--i, 0) * 30ms);
}
.place-card .pc-temp {
  position: absolute; top: 0; left: 0; right: 0; height: 2px;
}
/* Collection temperatures */
.t-grewup .pc-temp { background: var(--temp-grewup); }
.t-been   .pc-temp { background: var(--temp-been); }
.t-dream  .pc-temp { background: var(--temp-dream); }
.t-gone   .pc-temp { background: var(--temp-gone); }
/* shelf plates print in their own temperature */
.place-card.t-grewup img { filter: grayscale(1) sepia(1) saturate(1.35) brightness(0.8) contrast(1.15); }
.place-card.t-dream img { filter: grayscale(1) sepia(1) hue-rotate(212deg) saturate(1.05) brightness(0.76) contrast(1.15); }
.place-card.t-gone img { filter: grayscale(1) contrast(1.1) brightness(0.8); }

/* Empty collection: dashed orbit ring circling one empty slot */
.empty-slot {
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  aspect-ratio: 8 / 7;
  display: grid; place-items: center;
  color: var(--text-faint);
  font-size: 13px;
  text-align: center;
  padding: 12px;
  position: relative;
}
.empty-slot::before {
  content: ""; position: absolute;
  width: 54px; height: 54px;
  border: 1px dashed var(--line-strong);
  border-radius: 50%;
  animation: orbit-spin 14s linear infinite;
  top: 18px;
}
@keyframes orbit-spin { to { transform: rotate(360deg); } }
.empty-slot span { margin-top: 66px; }

/* ---------- Save dialog ---------- */
#saveDialog {
  border: 0; border-radius: var(--r-lg) var(--r-lg) 0 0;
  background: var(--surface);
  color: var(--text);
  width: 100%; max-width: 560px;
  margin: auto auto 0;
  padding: 22px var(--pad) max(22px, env(safe-area-inset-bottom));
}
#saveDialog::backdrop { background: rgba(var(--scrim-rgb), 0.6); backdrop-filter: blur(4px); }
#saveDialog h3 { font-family: var(--serif); font-weight: 600; font-size: 22px; }
#saveDialog .sd-place { color: var(--text-dim); font-size: 15px; margin: 2px 0 16px; }
.coll-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
}
.coll-btn {
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  padding: 14px 12px;
  text-align: left;
  font-size: 15px; font-weight: 600;
  display: flex; align-items: center; gap: 10px;
  transition: border-color 150ms ease, background 150ms ease;
}
.coll-btn .dot { width: 10px; height: 10px; border-radius: 50%; flex: none; background: var(--t); }
.coll-btn.sel { background: var(--surface-2); border-color: var(--t); }
#saveDialog .fields { display: grid; grid-template-columns: 100px 1fr; gap: 10px; margin-top: 12px; }
#saveDialog input {
  background: var(--ink);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  color: var(--text);
  padding: 11px 12px;
  outline: 0;
}
#saveDialog input:focus { border-color: rgba(var(--limb-rgb),0.5); }
#saveDialog .sd-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 16px; }
#saveDialog .sd-actions button { border-radius: var(--r-md); padding: 13px; font-weight: 600; }
.sd-cancel { background: var(--surface-2); border: 1px solid var(--line-strong); }
.sd-keep { background: var(--sodium); color: var(--on-sodium); }
.sd-drop {
  width: 100%; margin-top: 14px;
  min-height: 44px;
  color: var(--text-faint);
  font-size: 13px;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.sd-drop:hover, .sd-drop:active { color: var(--silver); }
/* Save confirmation: the plate stamps down */
@keyframes stamp {
  0% { transform: scale(1.06); opacity: 0; }
  60% { transform: scale(0.99); opacity: 1; }
  100% { transform: scale(1); }
}
.stamped { animation: stamp 350ms var(--ease-settle); }

/* The whole Earth has no altitude ladder: Tonight is one view */
#place.earth-mode .rail { display: none; }
/* the orbit photograph covers the map: the lens pill steps off */
#place.orbit-view .lens-pill, #place.earth-mode .lens-pill { display: none; }

/* The plate assembles rather than appearing (its arc keeps its own
   transform and stays out of the cascade) */
.plate.assemble > :not(.limb-arc) { animation: plate-in 260ms var(--ease-settle) backwards; }
.plate.assemble > :nth-child(3) { animation-delay: 40ms; }
.plate.assemble > :nth-child(4) { animation-delay: 80ms; }
.plate.assemble > :nth-child(5) { animation-delay: 120ms; }
.plate.assemble > :nth-child(n+6) { animation-delay: 160ms; }

/* Instrument numerals: aligned like instruments everywhere */
.plate .coords, .altimeter, .dd-num span, .fromhome, .tl-year,
.atlas-count, .buildtag, #orbitPanel figcaption {
  font-variant-numeric: tabular-nums;
}

/* The street warms up unseen while the dive falls. Opacity, not
   visibility: a hidden container starves Google's renderer and its
   internals throw; an invisible one lets it warm honestly. */
#place.diving #streetPanel { opacity: 0; pointer-events: none; }
#streetPanel { transition: opacity 300ms ease; }

/* ---------- STREET MODE: the photograph owns the screen ---------- */
#place.street-mode .lens-pill { display: none; }
#place.street-mode .rail { padding: 6px; }
/* B70: the rung keeps its 44px box on the street; only the paint shrinks
   (a 36px target under a thumb missed, and the rail said 44 everywhere) */
#place.street-mode .rung { width: 44px; height: 44px; font-size: 10px; background-clip: content-box; padding: 4px; }
#place.street-mode .altimeter { display: none; }
/* but the FALL always shows its number, even on warm street dives */
#place.street-mode.diving .altimeter { display: block; }

/* The plate as a sheet: name row visible, tap to open the rest */
.plate.sheet {
  max-height: 76px;
  overflow: hidden;
  cursor: pointer;
  transition: max-height 380ms var(--ease-settle);
}
/* B71: the sheet's grab, a real button over the handle and the name
   row; the tap on the rest of the sheet still works (plate onclick) */
.sheet-grab {
  position: absolute; top: 0; left: 0; right: 0; height: 44px;
  background: transparent; border: 0; border-radius: var(--r-lg) var(--r-lg) 0 0;
  z-index: 2; cursor: pointer;
}
.sheet-grab:focus-visible { outline: 2px solid var(--limb); outline-offset: -2px; }
#place.diving .sheet-grab { visibility: hidden; } /* not reachable behind the curtain */
.plate.sheet::before {
  content: "";
  position: absolute; top: 8px; left: 50%;
  width: 36px; height: 4px; margin-left: -18px;
  border-radius: 999px;
  background: var(--line-strong);
}
.plate.sheet h2 { margin-top: 8px; font-size: 20px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }
/* The opened sheet must never clip its own actions (Codex 11):
   a full NYC plate outgrows a fixed cap, so it scrolls */
.plate.sheet.open {
  max-height: min(70vh, 560px);
  max-height: min(70dvh, 560px);
  overflow-y: auto;
}

/* ---------- THEATER: the panorama takes everything ----------
   Real fullscreen is forbidden on iOS Safari; this is ours, and it
   works everywhere. Only the stride column stays, to keep walking. */
#place.theater .place-top,
#place.theater .rail,
#place.theater .plate { opacity: 0; pointer-events: none; visibility: hidden; transition: opacity 300ms ease, visibility 0s linear 300ms; }
/* B71: out of the tab order too; the visibility flip waits for the fade */
#place.theater ~ .navbar { opacity: 0; pointer-events: none; visibility: hidden; transition: opacity 400ms ease, visibility 0s linear 400ms; }
#place.theater #streetPanel { z-index: 35; }

/* ---------- THE DAILY DROP: walk a mystery, guess the world ------- */
#place.drop-mode .plate,
#place.drop-mode .rail,
#place.drop-mode .lens-pill { display: none; }
/* Tonight names itself: the Earth plate sheet only buried the time
   strip on small phones (deep-dive blocker) */
#place.earth-mode .plate { display: none; }
/* the rail steps aside while the street sheet stands tall */
.rail { transition: opacity 200ms ease; }
#place.sheet-open .rail { opacity: 0; pointer-events: none; visibility: hidden; transition: opacity 200ms ease, visibility 0s linear 200ms; } /* B71: out of the tab order too */
#place.drop-guess #streetPanel { display: none; }

.drop-bar {
  position: absolute;
  left: var(--pad); right: var(--pad);
  bottom: calc(max(var(--pad), env(safe-area-inset-bottom)) + 74px);
  z-index: 45;
  background: rgba(var(--surface-rgb), 0.8);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  padding: 14px 16px;
  animation: plate-in 400ms var(--ease-settle);
}
.drop-bar p {
  font-family: var(--serif);
  font-size: 16px;
  margin-bottom: 10px;
}
/* Name your guess: the second door into the same pin */
.drop-bar .db-name {
  display: flex; gap: 8px; align-items: center;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  padding: 4px 4px 4px 12px;
  margin-bottom: 10px;
  transition: border-color 200ms ease;
}
.drop-bar .db-name:focus-within { border-color: rgba(var(--limb-rgb), 0.5); }
.drop-bar .db-name input {
  flex: 1; min-width: 0;
  background: none; border: 0; outline: 0;
  color: var(--text);
  font-size: 16px; /* 16 keeps iOS from zooming the focused field */
  padding: 9px 0;
}
.drop-bar .db-name input::placeholder { color: var(--text-faint); }
.drop-bar .db-go {
  flex: none;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  min-height: 44px;
  padding: 0 14px;
  font-weight: 600; font-size: 13px;
  color: var(--text);
  transition: transform 150ms var(--ease-settle), opacity 200ms ease;
}
.drop-bar .db-go:disabled { opacity: 0.5; }
.drop-bar .db-go:active { transform: scale(0.96); }
.drop-bar .db-standing {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  margin: -2px 0 10px;
}
.drop-bar .db-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.drop-bar .db-main {
  width: 100%;
  background: var(--sodium); color: var(--on-sodium);
  font-weight: 600; font-size: 15px;
  border-radius: var(--r-md);
  min-height: 48px;
  transition: transform 150ms var(--ease-settle), opacity 200ms ease;
}
.drop-bar .db-main:disabled { opacity: 0.45; }
.drop-bar .db-main:active { transform: scale(0.97); }
.drop-bar .db-back {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  min-height: 48px;
  font-weight: 600; font-size: 15px;
}

#dropDialog {
  border: 0; border-radius: var(--r-lg) var(--r-lg) 0 0;
  background: var(--surface);
  color: var(--text);
  width: 100%; max-width: 560px;
  margin: auto auto 0;
  padding: 22px var(--pad) max(22px, env(safe-area-inset-bottom));
}
#dropDialog::backdrop { background: rgba(var(--scrim-rgb), 0.6); backdrop-filter: blur(4px); }
#dropDialog h3 { font-family: var(--serif); font-weight: 600; font-size: 22px; }
#dropDialog .dd-place {
  font-family: var(--serif); font-style: italic;
  color: var(--text-soft); font-size: 16px; margin-top: 2px;
}
.dd-nums { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 14px 0 10px; }
.dd-num {
  background: var(--ink);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  padding: 12px; text-align: center;
}
.dd-num span { font-family: var(--mono); font-size: 26px; color: var(--limb); display: block; }
.dd-num.sod span { color: var(--sodium); }
.dd-num label {
  font-size: 11px; color: var(--text-dim);
  letter-spacing: 0.05em; text-transform: uppercase;
}
.dd-line { color: var(--text-dim); font-size: 15px; min-height: 1.4em; }
.dd-duel { color: var(--sodium); font-size: 15px; margin-top: 6px; }
.dd-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 16px; }
.dd-actions button { border-radius: var(--r-md); padding: 13px; font-weight: 600; }
#ddShare { background: var(--surface-2); border: 1px solid var(--line-strong); }
#ddStand { background: var(--sodium); color: var(--on-sodium); }
.dd-close {
  width: 100%; margin-top: 14px;
  min-height: 44px;
  color: var(--text-faint);
  font-size: 13px;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.dd-close:hover, .dd-close:active { color: var(--silver); }

@media (min-width: 720px) { .drop-bar { max-width: 560px; margin-left: auto; margin-right: auto; } }

/* A postcard opens like an envelope */
#dedication {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center;
  background: var(--ink);
  font-family: var(--serif); font-style: italic; font-weight: 600;
  font-size: clamp(22px, 6vw, 30px);
  color: var(--text);
  animation: word-rise 700ms var(--ease-settle);
  transition: opacity 600ms ease;
}
#dedication.leaving { opacity: 0; }

/* Toast */
#toast {
  position: fixed; left: 50%; bottom: 34px;
  transform: translateX(-50%) translateY(20px);
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  padding: 10px 20px;
  font-size: 15px;
  opacity: 0; pointer-events: none;
  transition: opacity 250ms ease, transform 250ms var(--ease-settle);
  z-index: 60;
}
#toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  /* enter with a settle, leave without ceremony (council) */
  animation: toast-in 380ms var(--ease-settle);
}
@keyframes toast-in {
  0% { opacity: 0; transform: translateX(-50%) translateY(16px); }
  70% { transform: translateX(-50%) translateY(-2px); }
  100% { transform: translateX(-50%) translateY(0); }
}

/* ---------- THE LIFE PASS (council motion spec) ---------- */
/* a caption that is waiting breathes instead of freezing */
#orbitPanel figcaption.waiting { animation: cap-wait 1200ms ease-in-out infinite; }
@keyframes cap-wait { 50% { opacity: 0.45; } }
/* an honest miss shakes its head */
.time-strip.shake { animation: strip-shake 180ms ease-in-out 2; }
@keyframes strip-shake { 25% { transform: translateX(-3px); } 75% { transform: translateX(3px); } }
/* the outgoing Earth dissolves over the incoming one */
.orbit-ghost { position: absolute; pointer-events: none; z-index: 2; transition: opacity 500ms ease; }
.orbit-ghost.fading { opacity: 0; }
.orbit-ghost .orbit-star { animation: none; }
/* press physics: every pressable gives under the thumb; press is
   fast implicit, release rides the settle */
.coll-btn, .sd-actions button, .atlas-tools button, .voice-cta button, .tp {
  transition: transform 240ms var(--ease-settle), border-color 200ms ease,
    background 200ms ease, color 200ms ease, opacity 200ms ease;
}
.coll-btn:active, .sd-actions button:active, .atlas-tools button:active,
.voice-cta button:active { transform: scale(0.96); }
.tp:active { transform: scale(0.98); }
/* the sheet's grabber answers the hand */
.plate.sheet::before { transition: transform 200ms var(--ease-settle), background 200ms ease; }
.plate.sheet:active::before { transform: scaleX(1.4); background: var(--text-dim); }

/* Touchdown settle: one frame vignette pulse + scale settle */
@keyframes touchdown {
  0% { transform: scale(1.015); }
  100% { transform: scale(1); }
}
.settling { animation: touchdown 60ms ease-out; }
#vignette {
  position: absolute; inset: 0; pointer-events: none; opacity: 0;
  box-shadow: inset 0 0 120px rgba(0,0,0,0.8);
}
#vignette.pulse { animation: vg 120ms ease-out; }
@keyframes vg { 0% { opacity: 1; } 100% { opacity: 0; } }

/* ---------- The opening film: a miniature world, once ---------- */
#intro {
  position: fixed; inset: 0; z-index: 80;
  background: var(--ink);
  display: flex; align-items: center; justify-content: center;
}
#intro video {
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 700ms ease;
}
#intro video.rolling { opacity: 1; }
#intro.leaving { animation: intro-out 700ms ease forwards; }
@keyframes intro-out { to { opacity: 0; } }
#introSkip {
  position: absolute;
  bottom: max(28px, env(safe-area-inset-bottom));
  left: 50%; transform: translateX(-50%);
  color: var(--text-dim);
  font-size: 13px; font-weight: 600;
  letter-spacing: 0.04em;
  padding: 12px 22px;
  border-radius: 999px;
  background: rgba(var(--ink-rgb), 0.5);
  border: 1px solid var(--line);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

/* ---------- Bottom navigation: four rooms of the house ---------- */
.navbar {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: none;
  grid-template-columns: repeat(4, 1fr);
  gap: 2px;
  padding: 8px max(12px, env(safe-area-inset-left)) max(8px, env(safe-area-inset-bottom));
  /* real glass: the world glows through the house (Peliteca's bar;
     its law rides along: no press state on the glass element itself,
     backdrop-filter blinks) */
  background: rgba(var(--ink-rgb), 0.55);
  border-top: 1px solid rgba(var(--limb-rgb), 0.14);
  backdrop-filter: blur(18px) saturate(1.3);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
}
.navbar.show { display: grid; }
.navbar { transition: opacity 400ms ease; z-index: 50; } /* the ONE z-index (a stale 40 sat in the main block) */
/* the dive is the one moment the house recedes */
#place.diving ~ .navbar { opacity: 0; pointer-events: none; }
.navbar button {
  min-height: 52px;
  border-radius: var(--r-sm);
  font-size: 11px; font-weight: 600; /* the caption role, one voice */
  letter-spacing: 0.02em;
  /* dim not faint, and a breath of shadow: over noon-bright streets
     the faint labels washed to ~1.3:1 (deep-dive measurement) */
  color: var(--text-dim);
  text-shadow: 0 1px 8px rgba(var(--ink-rgb), 0.9);
  transition: color 200ms ease, background 200ms ease;
}
.navbar button.on { color: var(--text); background: rgba(var(--sodium-rgb), 0.08); }
/* the instrument cluster: four drawn glyphs, sodium when home */
.navbar button svg {
  display: block;
  width: 20px; height: 20px;
  margin: 0 auto 3px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: stroke 200ms ease, transform 150ms var(--ease-settle);
}
.navbar button.on svg { stroke: var(--sodium); }
.navbar button:active svg { transform: scale(0.88); }

/* ---------- WONDERS: visit the world ---------- */
#wonders {
  background: var(--ink);
  overflow-y: auto;
  padding: max(14px, env(safe-area-inset-top)) 0 96px;
}
.wonders-head { padding: 0 var(--pad) 4px; max-width: 720px; margin: 0 auto; }
.wonders-head h1 { font-family: var(--serif); font-weight: 600; font-size: 26px; }
.wonders-head p { color: var(--text-dim); font-size: 15px; margin-top: 2px; }
.tour-btn {
  margin-top: 12px;
  min-height: 46px;
  padding: 10px 20px;
  border-radius: var(--r-md);
  background: var(--sodium);
  color: var(--on-sodium);
  font-weight: 600; font-size: 15px;
  box-shadow: var(--lift-2); /* glow is for the world, not a rectangle */
  transition: transform 150ms var(--ease-settle);
}
.tour-btn:active { transform: scale(0.97); }

.wonders-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px;
  padding: 14px var(--pad) 0;
  max-width: 720px; margin: 0 auto;
}
@media (min-width: 720px) { .wonders-grid { grid-template-columns: repeat(4, 1fr); } }
.wo-cat {
  grid-column: 1 / -1;
  font-size: 13px; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-dim);
  margin-top: 10px;
}
.wo-cat:first-child { margin-top: 0; }

/* The classic eight: one strip, shoulder to shoulder */
.seven-strip {
  grid-column: 1 / -1;
  display: flex; gap: 12px;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  padding: 2px;
  cursor: grab;
}
.seven-strip:active { cursor: grabbing; }
.seven-strip::-webkit-scrollbar { display: none; }
.wonder-mini {
  flex: none; width: 108px;
  text-align: left;
  transition: transform 240ms var(--ease-settle);
}
.wonder-mini:active { transform: scale(0.95) rotate(-0.6deg); }
.wonder-mini img {
  width: 108px; height: 108px;
  border-radius: var(--r-md);
  object-fit: cover; display: block;
  /* a coal of sodium around every window on the world (Kent: give
     the squares radiant life) */
  border: 1px solid rgba(var(--sodium-rgb), 0.28);
  box-shadow: 0 0 14px -6px rgba(var(--sodium-rgb), 0.35);
  filter: saturate(0.95);
  transition: border-color 240ms ease, box-shadow 240ms ease;
}
@media (hover: hover) {
  .wonder-mini:hover { transform: translateY(-3px) rotate(-0.8deg); }
  .wonder-mini:hover img {
    border-color: rgba(var(--sodium-rgb), 0.65);
    box-shadow: 0 0 22px -4px rgba(var(--sodium-rgb), 0.55);
  }
}
.wonder-mini span {
  font-family: var(--serif); font-weight: 600;
  font-size: 13px; line-height: 1.25;
  margin-top: 6px;
  height: 32px; /* two lines reserved: the strip stays lined up */
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.wonder-card {
  position: relative; overflow: hidden;
  background: var(--surface);
  border: 1px solid rgba(var(--sodium-rgb), 0.24);
  box-shadow: 0 0 18px -8px rgba(var(--sodium-rgb), 0.3);
  border-radius: var(--r-md);
  text-align: left;
  transition: transform 240ms var(--ease-settle), border-color 240ms ease, box-shadow 240ms ease;
  animation: plate-in 240ms var(--ease-settle) backwards;
  animation-delay: calc(var(--i, 0) * 25ms);
}
.wonder-card:active { transform: scale(0.97) rotate(-0.5deg); }
@media (hover: hover) {
  .wonder-card:hover {
    transform: translateY(-4px) rotate(-0.6deg) scale(1.01);
    border-color: rgba(var(--sodium-rgb), 0.6);
    box-shadow: 0 0 26px -4px rgba(var(--sodium-rgb), 0.5), var(--lift-2);
  }
}
.wonder-card img {
  width: 100%; aspect-ratio: 1; object-fit: cover; display: block;
  filter: saturate(0.95);
}
.wonder-card .wo-body { padding: 9px 11px 11px; display: block; }
.wonder-card .wo-name {
  display: block;
  font-family: var(--serif); font-weight: 600; font-size: 15px; line-height: 1.25;
}
.wonder-card .wo-meta {
  display: block;
  font-family: var(--mono); font-size: 10px;
  color: var(--text-dim); margin-top: 2px;
  text-transform: uppercase; letter-spacing: 0.06em;
}

/* Screens that carry the navbar leave room for it */
#home .home-veil { padding-bottom: calc(max(var(--pad), env(safe-area-inset-bottom)) + 66px); }
#atlas { padding-bottom: 110px; }

/* MapLibre chrome, dressed for the dark */
.maplibregl-ctrl-attrib { background: rgba(var(--ink-rgb), 0.55) !important; }
/* B70: readable when unfolded (10px faint ink on ink was not) */
.maplibregl-ctrl-attrib a, .maplibregl-ctrl-attrib { color: var(--text-dim) !important; font-size: 11px; }
.maplibregl-ctrl-attrib-button { filter: invert(0.8); }
/* B70: the credits belong to the map's rooms only; they used to float
   over Wonders, My places and Tonight at full opacity */
body:not(:has(#home.on)):not(:has(#place.on)) #globeMap .maplibregl-ctrl-top-left { display: none; }

/* ---------- Reduced motion: same story, told in stills ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    /* delays must clamp too: a backwards-fill stagger with a live
       delay leaves content BLANK under reduced motion (council catch) */
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
  }
}

/* ---------- NIGHT PLATES: no raw noon suburbia in a night app ------
   Every satellite thumbnail prints as a moonlit lith in limb blue;
   the atlas shelves override with their own temperatures above. */
.wonder-card img, .wonder-mini img, .place-card img,
.tl-row img, .tp img {
  /* --lith-lum: each wonder plate measures its own raw light and
     dims toward one shared moonlit band (B51: Petra's bright desert
     read as a highlight next to the Great Wall's dark forest).
     Plates that never measure keep the classic 1. */
  filter: grayscale(1) sepia(1) hue-rotate(var(--lith-hue)) saturate(1.1) brightness(calc(0.78 * var(--lith-lum, 1))) contrast(1.18);
}
/* the Window's backdrop keeps its daylight, dimmed to evening */
.window-card .wc-bg { filter: saturate(0.75) brightness(0.85) contrast(1.05); }

/* ---------- ELEVATION: depth instead of more hairlines ---------- */
.plate, .searchbar, .window-card { box-shadow: var(--lift-2); }
.wonder-card, .place-card, .drop-bar { box-shadow: var(--lift-1); }
#saveDialog, #dropDialog, #pastDialog, #shareDialog { box-shadow: var(--lift-3); }

/* ---------- Share preview: what goes out, shown first ---------- */
#shareDialog {
  border: 0; border-radius: var(--r-lg) var(--r-lg) 0 0;
  background: var(--surface);
  color: var(--text);
  width: 100%; max-width: 560px;
  margin: auto auto 0;
  padding: 22px var(--pad) max(22px, env(safe-area-inset-bottom));
}
#shareDialog::backdrop { background: rgba(var(--scrim-rgb), 0.6); backdrop-filter: blur(4px); }
#shareDialog h3 { font-family: var(--serif); font-weight: 600; font-size: 22px; }
#shareImg {
  display: block;
  width: auto; max-width: 100%;
  max-height: 38vh;
  margin: 14px auto 0;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-strong);
}
.sh-text {
  font-family: var(--serif);
  font-style: italic;
  font-size: 15px;
  line-height: 1.5;
  color: var(--text-soft);
  margin: 12px 0 4px;
}
.sh-link {
  font-size: 12px;
  color: var(--text-dim);
  margin-bottom: 14px;
}
.sh-miss {
  font-family: var(--serif);
  font-style: italic;
  font-size: 13px;
  color: var(--sodium);
  opacity: 0.85;
  margin-top: 12px;
}
.sh-text:last-of-type { margin-bottom: 14px; }
.sh-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.sh-actions button {
  min-height: 48px;
  border-radius: var(--r-md);
  font-weight: 600; font-size: 15px;
}
#shareCancel { background: var(--surface-2); border: 1px solid var(--line-strong); }
#shareSend { background: var(--limb); color: var(--on-limb); }
#shareSend:active { transform: scale(0.97); }

/* the tappable nearby line: the story waits behind it */
.intel.tappable {
  text-decoration: underline dotted;
  text-underline-offset: 3px;
  cursor: pointer;
}

/* ---------- The story: the world's memory, read in-app ---------- */
#storyDialog {
  border: 0; border-radius: var(--r-lg) var(--r-lg) 0 0;
  background: var(--surface);
  color: var(--text);
  width: 100%; max-width: 560px;
  margin: auto auto 0;
  padding: 22px var(--pad) max(22px, env(safe-area-inset-bottom));
  box-shadow: var(--lift-3);
}
#storyDialog::backdrop { background: rgba(var(--scrim-rgb), 0.6); backdrop-filter: blur(4px); }
#storyDialog h3 { font-family: var(--serif); font-weight: 600; font-size: 22px; }
#stImg {
  display: block;
  width: 100%;
  max-height: 30vh;
  object-fit: cover;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  margin-top: 12px;
}
.st-text {
  font-size: 15px;
  line-height: 1.6;
  color: var(--text-soft);
  margin: 12px 0 14px;
  max-height: 32vh;
  overflow-y: auto;
}
.st-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  align-items: center;
}
.st-row a {
  text-align: center;
  font-size: 13px;
  color: var(--text-dim);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ---------- The past near here: a sheet of silver plates ---------- */
#pastDialog {
  border: 0; border-radius: var(--r-lg) var(--r-lg) 0 0;
  background: var(--surface);
  color: var(--text);
  width: 100%; max-width: 560px;
  margin: auto auto 0;
  padding: 22px var(--pad) max(22px, env(safe-area-inset-bottom));
}
#pastDialog::backdrop { background: rgba(var(--scrim-rgb), 0.6); backdrop-filter: blur(4px); }
#pastDialog h3 { font-family: var(--serif); font-weight: 600; font-size: 22px; }
.past-doors {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  margin-top: 12px;
}
.past-line {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  margin: 10px 0;
}
.past-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  max-height: 44vh; overflow-y: auto;
  margin-bottom: 12px;
}
.past-card {
  position: relative;
  border-radius: var(--r-sm);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--ink);
  display: block;
}
.past-card img {
  width: 100%; height: 116px;
  object-fit: cover; display: block;
  /* the archive prints in the Gone shelf's silver, never full color:
     the past keeps its own temperature */
  filter: grayscale(1) sepia(0.12) brightness(0.94) contrast(1.04);
}
.past-card span {
  position: absolute; left: 8px; bottom: 6px;
  font-family: var(--mono); font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.85);
}

/* The viewer: the photograph opens INSIDE the app, credited */
.past-view img {
  display: block;
  width: 100%;
  max-height: 46vh;
  object-fit: contain;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--ink);
  margin-top: 10px;
  /* full silver in the viewer too: the past keeps its temperature */
  filter: grayscale(1) sepia(0.12) brightness(0.96) contrast(1.03);
}
.pv-cap {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  margin: 10px 0 12px;
}
.pv-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  align-items: center;
  margin-bottom: 12px;
}
.pv-row button {
  min-height: 44px;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  font-weight: 600; font-size: 13px;
}
.pv-row a {
  text-align: center;
  font-size: 13px;
  color: var(--text-dim);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* the dream shelf's printing press */
.board-btn {
  margin-left: auto;
  min-height: 44px;
  padding: 4px 12px;
  border-radius: 999px;
  border: 1px solid rgba(var(--violet-rgb), 0.45);
  color: var(--temp-dream, #a99bd6);
  font-size: 12px; font-weight: 600;
  transition: opacity 200ms ease;
}
.board-btn:disabled { opacity: 0.5; }

/* Wider screens: the phone frame stays the star */
@media (min-width: 720px) {
  .home-veil, .plate { max-width: 560px; margin-left: auto; margin-right: auto; }
  /* B70: the navbar-aware margin (the rule above) must survive the
     wide-screen centering; 28px buried the sheet and the wallpaper
     link under the navbar on every tablet and desktop */
  .plate { margin-bottom: calc(max(var(--pad), env(safe-area-inset-bottom)) + 66px); }
  .shelf { max-width: 720px; margin: 0 auto; }
  .shelf-grid { grid-template-columns: repeat(4, 1fr); }
}

/* THE LIFE LINE FILM's card: the year and the memory over the ground
   you knew, one stop at a time (B65) */
.film-card {
  position: absolute;
  left: 20px; right: 20px;
  top: calc(env(safe-area-inset-top) + 76px);
  z-index: 45;
  display: grid; gap: 6px;
  text-align: center;
  pointer-events: none;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.65);
}
.film-card .fc-year {
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: 0.12em;
  color: var(--sodium);
}
.film-card .fc-line {
  font-family: var(--serif);
  font-style: italic;
  font-size: 26px;
  line-height: 1.25;
  color: var(--text);
  text-wrap: balance;
}
.film-card .fc-count {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--text-dim);
}
@media (prefers-reduced-motion: no-preference) {
  .film-card.show { animation: fc-in 700ms var(--ease-settle) both; }
  @keyframes fc-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
}
/* the street's waiting line: one honest sentence instead of a black
   void while the engine answers (B62) */
.street-wait {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .street-wait { animation: wait-breathe 1800ms ease-in-out infinite; }
  @keyframes wait-breathe { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } }
}
/* Google's logo and terms sit along the panorama's bottom edge: in the
   ordinary street view the panel now ends above the name sheet and
   the navbar so they stay visible and tappable (rights, B62); the
   theater keeps the whole screen and hides both */
#place.street-mode:not(.theater) #streetPanel {
  bottom: calc(max(var(--pad), env(safe-area-inset-bottom)) + 148px);
}
/* the ground under the name sheet is ink, never the home screen showing
   through the glass (the strip the panel no longer covers; B63) */
#place.street-mode:not(.theater):not(.diving)::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: calc(max(var(--pad), env(safe-area-inset-bottom)) + 148px);
  background: var(--ink);
  z-index: 4; /* under the panel (5), the sheet and the navbar */
  pointer-events: none;
}
/* the map's own credits (Esri, NASA, OpenStreetMap) ride the top left,
   under the back button, instead of hiding beneath every screen (B62) */
#globeMap .maplibregl-ctrl-top-left { top: calc(env(safe-area-inset-top) + 10px); left: 10px; }
#globeMap .maplibregl-ctrl-top-left .maplibregl-ctrl { margin: 0; }
/* on the place screen the back button owns that corner */
body:has(#place.on) #globeMap .maplibregl-ctrl-top-left { top: calc(env(safe-area-inset-top) + 64px); }
/* the save sheet's own hint: a toast painted under the dialog's scrim
   and read as a dead button (B62) */
.sd-hint {
  margin: 8px 0 0;
  font-size: 13px;
  color: var(--sodium);
}
/* the Morning Window's forecast credit, words on the card (B62) */
.wc-credit {
  display: block;
  margin-top: 2px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  opacity: 0.72;
}

/* ---------- Where this comes from: every source, named (B61) ----------
   Open-Meteo's data is CC BY, so its credit stands beside the line it
   feeds, linked and visible. The sheet names the rest. */
.credit-line {
  display: inline-block;
  margin-top: 2px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--text-faint);
  text-decoration: underline dotted;
  text-underline-offset: 3px;
}
.credit-line:hover, .credit-line:active { color: var(--text-dim); }
#nCredit a { color: inherit; text-decoration: underline dotted; text-underline-offset: 3px; }
.credits-link {
  display: block;
  margin: 14px auto 0;
  min-height: 44px;
  padding: 0 12px;
  color: var(--text-faint);
  font-size: 13px;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.credits-link:hover, .credits-link:active { color: var(--silver); }
#creditsDialog {
  border: 0; border-radius: var(--r-lg) var(--r-lg) 0 0;
  background: var(--surface);
  color: var(--text);
  width: 100%; max-width: 560px;
  margin: auto auto 0;
  padding: 22px var(--pad) max(22px, env(safe-area-inset-bottom));
  box-shadow: var(--lift-3);
}
#creditsDialog::backdrop { background: rgba(var(--scrim-rgb), 0.6); backdrop-filter: blur(4px); }
#creditsDialog h3 { font-family: var(--serif); font-weight: 600; font-size: 22px; }
.cr-lede {
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-soft);
  margin: 10px 0 12px;
}
.cr-list {
  list-style: none; margin: 0; padding: 0;
  max-height: 46vh; overflow-y: auto;
  border-top: 1px solid var(--line);
}
.cr-list li {
  display: grid; gap: 2px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
  font-size: 14px; line-height: 1.4;
}
.cr-list a {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--line-strong);
}
.cr-list span { color: var(--text-dim); font-size: 13px; }

/* B73: the top row passes taps through its empty space (it hid the map
   credits' "i" under the back button); its buttons still take taps */
#place > .place-top { pointer-events: none; } /* beats #place > * (line 586) */
/* never during the dive (the row is hidden then), and never in the theater:
   the row fades for 300ms as it opens and its buttons took taps meanwhile (B74) */
#place:not(.diving):not(.theater) > .place-top > * { pointer-events: auto; }

/* B73: in the Daily Drop the street ends above the guess bar, so Google's
   logo and terms stay in sight (the bar used to cover them); the ink
   strip below matches. The bar's height is measured in js (dropBarSet).
   B74: the theater still takes the whole screen. */
#place.drop-mode.street-mode:not(.theater) #streetPanel {
  bottom: calc(max(var(--pad), env(safe-area-inset-bottom)) + 74px + var(--drop-bar-h, 140px) + 8px);
}
#place.drop-mode.street-mode:not(.theater):not(.diving)::after {
  height: calc(max(var(--pad), env(safe-area-inset-bottom)) + 74px + var(--drop-bar-h, 140px) + 8px);
}

/* B75: A SHORT STREET (a phone held sideways; the Drop's bar takes the
   lower half): the stride and the rail each become one row along the top,
   beside the back button and the pin, so every button takes its own tap
   and Google's logo and links stay clear. app.js sets short-street from
   the street panel's own height. */
#place.short-street #streetPanel .stride {
  flex-direction: row; gap: 8px;
  top: max(14px, env(safe-area-inset-top));
  left: calc(var(--pad) + 54px);
  transform: none;
}
#place.short-street #streetPanel .stride .step { width: 44px; height: 44px; }
#place.street-mode.short-street:not(.diving) .rail {
  flex-direction: row;
  top: calc(max(14px, env(safe-area-inset-top)) - 6px);
  right: calc(var(--pad) + 54px);
}

/* B76: the SVLTMK crew mark in the credits: Vela, the monster who runs KeptAtlas at the studio (2026-10-16) */
#creditsDialog .crew-mark { display:inline-flex; align-items:center; gap:12px; margin:8px 0 14px; padding:6px 16px 6px 8px; border-radius:22px;
  background:rgba(139,108,201,.16); border:1px solid rgba(139,108,201,.5); color:inherit; text-decoration:none; font-weight:600; font-size:14px; }
#creditsDialog .crew-mark img { height:96px; width:auto; border-radius:12px; display:block; box-shadow:0 0 0 2px #8B6CC9; transform-origin:50% 100%; }
@media (prefers-reduced-motion: no-preference) { #creditsDialog .crew-mark img { animation:crew-bob 3s ease-in-out 1; } #creditsDialog .crew-mark:hover img, #creditsDialog .crew-mark:focus-visible img { animation:crew-bob 3s ease-in-out infinite; } @keyframes crew-bob { 0%, 100% { transform:translateY(0) rotate(-1deg); } 50% { transform:translateY(-4px) rotate(1deg); } } }
