/* ============================================================
   PixiePal — view-specific styles

   Deliberately NOT code-split alongside the JS views. The JS is split because
   parse cost scales with bytes; CSS is not, and a per-view stylesheet would add
   a render-blocking fetch at the exact moment you tap a nav item. One file,
   precached once, every route instant thereafter.

   Sections:
     1. Home            5. Plan / timeline      9. Journal
     2. Map             6. Guide / lists       10. Settings
     3. Hunt (eggs)     7. Play (bingo/quiz)   11. Shared bits
     4. Ask (chat)      8. History
   ============================================================ */

/* ============================================================
   1. HOME
   ============================================================ */
.eyebrow {
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: .14em;
  font-weight: 800;
  color: var(--accent);
  opacity: .95;
}

.hero {
  position: relative;
  overflow: hidden;
  padding: var(--s-5);
  background:
    linear-gradient(145deg, color-mix(in oklab, var(--accent) 22%, var(--surface)), var(--surface) 62%);
  border-radius: var(--r-xl);
  border: 1px solid var(--hairline-strong);
  box-shadow: var(--shadow-lift);
}
.hero__glow {
  position: absolute;
  inset: -40% -20% auto -20%;
  height: 240px;
  background: radial-gradient(closest-side, color-mix(in oklab, var(--accent) 45%, transparent), transparent);
  filter: blur(26px);
  pointer-events: none;
  animation: heroDrift 14s var(--ease-out) infinite alternate;
}
@keyframes heroDrift {
  from { transform: translate3d(-6%, 0, 0) scale(1); }
  to   { transform: translate3d(8%, 6%, 0) scale(1.12); }
}
.hero__title {
  position: relative;
  font-family: var(--font-display);
  font-size: var(--t-2xl);
  font-weight: 900;
  letter-spacing: -.03em;
  line-height: 1.08;
  margin-top: var(--s-2);
}
.hero__sub {
  position: relative;
  margin-top: var(--s-2);
  color: var(--ink-2);
  font-size: var(--t-sm);
  line-height: 1.5;
}
.hero__where {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: var(--s-3);
  padding: 6px 12px 6px 10px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  font-size: var(--t-xs);
  font-weight: 700;
}

/* the "you are here" heartbeat */
.pulse-dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 0 0 color-mix(in oklab, var(--ok) 70%, transparent);
  animation: pulseDot 2s ease-out infinite;
  flex: none;
}
@keyframes pulseDot {
  70%  { box-shadow: 0 0 0 11px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* "Right now" list */
.nowlist { display: grid; gap: 2px; }
.nowrow {
  display: grid;
  grid-template-columns: 34px 1fr auto;
  align-items: center;
  gap: var(--s-3);
  padding: 11px var(--s-2);
  border-radius: var(--r-md);
  text-align: left;
  width: 100%;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition: background var(--dur) var(--ease-out);
}
.nowrow + .nowrow { border-top: 1px solid var(--hairline); }
.nowrow:hover, .nowrow:focus-visible { background: var(--surface-2); }
.nowrow:active { transform: scale(.985); }
.nowrow__ico {
  display: grid; place-items: center;
  width: 34px; height: 34px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  font-size: 17px;
}
.nowrow__title { font-weight: 700; font-size: var(--t-sm); line-height: 1.25; }
.nowrow__sub   { font-size: var(--t-xs); color: var(--ink-3); margin-top: 2px; line-height: 1.35; }
.nowrow__badge { font-variant-numeric: tabular-nums; }

/* Horizontal "near you" rail */
.nearcard {
  flex: 0 0 auto;
  width: 158px;
  padding: var(--s-3);
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--hairline);
  text-align: left;
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition: transform var(--dur) var(--ease-spring), border-color var(--dur);
}
.nearcard:active { transform: scale(.96); }
.nearcard:hover { border-color: var(--accent); }
.nearcard__top  { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.nearcard__ico  { font-size: 22px; }
.nearcard__name {
  font-weight: 700; font-size: var(--t-xs); line-height: 1.3; margin-top: 8px;
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.nearcard__meta { font-size: 11px; color: var(--ink-3); margin-top: 6px; font-variant-numeric: tabular-nums; }

/* Quick-action tiles */
.tilegrid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-2);
}
@media (max-width: 359px) { .tilegrid { grid-template-columns: repeat(2, 1fr); } }
.tile {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px;
  min-height: 84px;
  padding: var(--s-3) 6px;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--hairline);
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--dur) var(--ease-spring), background var(--dur);
}
.tile:active { transform: scale(.94); }
.tile:hover  { background: var(--surface-2); }
.tile__ico   { font-size: 22px; line-height: 1; }
.tile__label { font-size: 11.5px; font-weight: 700; text-align: center; line-height: 1.2; }
.tile__hint  { font-size: 10px; color: var(--ink-3); text-align: center; }

/* Daily spark */
.spark {
  border-left: 3px solid var(--accent);
  background: linear-gradient(100deg, color-mix(in oklab, var(--accent) 12%, var(--surface)), var(--surface) 70%);
}
.spark__tag   { font-size: 10px; text-transform: uppercase; letter-spacing: .16em; font-weight: 800; color: var(--accent); }
.spark__title { font-weight: 800; font-size: var(--t-md); margin-top: 6px; line-height: 1.25; }
.spark__body  { font-size: var(--t-sm); color: var(--ink-2); margin-top: 8px; line-height: 1.6; }

/* ============================================================
   2. MAP
   ============================================================ */
.map {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--hairline-strong);
  background: var(--surface);
  box-shadow: var(--shadow);
}
.map__stage {
  height: min(62vh, 520px);
  touch-action: none;         /* we own pan + pinch; stops the page from scrolling */
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
}
.map__stage:active { cursor: grabbing; }
.map__svg { display: block; width: 100%; height: 100%; --inv: 1; }
.map__filters { padding-bottom: 2px; }

.map__world { transition: transform 90ms linear; }

/* --- OpenStreetMap underlay ---------------------------------------------
   Deliberately low-contrast: this layer is orientation, not information. The
   pins, land tints and your own position are what the eye should catch, so
   every value here is a muted wash that reads as "texture" until you look for
   it. Stroke widths use var(--inv) so they stay hairline-thin at every zoom
   instead of turning into fat slabs when you pinch in.                      */
.map__basemap { pointer-events: none; }        /* never steals a tap from a pin */

/* The thumb-sized target behind each pin. `fill: none` would make it invisible
   to hit-testing too, so it needs a real fill at zero opacity. */
.map__pin-hit {
  fill: #000;
  fill-opacity: 0;
  pointer-events: all;
}
.map__bm { vector-effect: non-scaling-stroke; }

.map__bm--green    { fill: #4ADE80; fill-opacity: .10; stroke: none; }
.map__bm--water    { fill: #38BDF8; fill-opacity: .22; stroke: #38BDF8; stroke-opacity: .35; stroke-width: .8; }
.map__bm--sand     { fill: #FBBF24; fill-opacity: .12; stroke: none; }
.map__bm--building { fill: var(--fg); fill-opacity: .11;  stroke: var(--fg); stroke-opacity: .20; stroke-width: .6; }
.map__bm--bridge   { fill: none; stroke: var(--fg); stroke-opacity: .28; stroke-width: 2.2; stroke-linecap: round; }
.map__bm--path     { fill: none; stroke: var(--fg); stroke-opacity: .21; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.map__bm--rail     { fill: none; stroke: var(--fg); stroke-opacity: .30; stroke-width: 1.1; stroke-dasharray: 5 4; }

.map__meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}
.map__meta .map__info { margin: 0; }
.map__attrib {
  font-size: 10px;
  line-height: 1.3;
  opacity: .5;
  white-space: nowrap;
  margin-left: auto;      /* stays right-aligned even when the info text wraps */
}

.map__land { transition: fill-opacity var(--dur); }
.map__landlabel {
  font-size: calc(13px * var(--inv));
  font-weight: 900;
  letter-spacing: calc(.18em * var(--inv));
  opacity: .55;
  pointer-events: none;
  paint-order: stroke;
  stroke: var(--bg);
  stroke-width: calc(3px * var(--inv));
}

.map__pin { cursor: pointer; }
.map__pin-halo { opacity: .18; }
.map__pin-dot  { stroke: var(--bg); stroke-width: calc(1.5px * var(--inv)); }
.map__pin:hover .map__pin-halo,
.map__pin:focus-visible .map__pin-halo { opacity: .4; }
.map__pin.is-selected .map__pin-halo { opacity: .55; }
.map__pin.is-selected .map__pin-dot  { stroke: var(--gold-400); stroke-width: calc(2.5px * var(--inv)); }
.map__pin.is-found .map__pin-dot     { fill: var(--ok); }
.map__pin-glyph {
  font-size: calc(9px * var(--inv));
  font-weight: 900;
  fill: #10061f;
  pointer-events: none;
}
.map__pinlabel {
  font-size: calc(9.5px * var(--inv));
  font-weight: 600;
  fill: var(--ink-2);
  pointer-events: none;
  paint-order: stroke;
  stroke: var(--bg);
  stroke-width: calc(2.6px * var(--inv));
}
.map__wait     { fill: var(--surface-solid); stroke-width: 0; }
.map__wait--ok   { fill: var(--ok); }
.map__wait--warn { fill: var(--warn); }
.map__wait--bad  { fill: var(--bad); }
.map__waittext {
  font-size: calc(9px * var(--inv));
  font-weight: 800;
  fill: #10061f;
  pointer-events: none;
}

.map__routeline {
  stroke: var(--gold-400);
  stroke-width: calc(2.5px * var(--inv));
  stroke-dasharray: calc(7px * var(--inv)) calc(6px * var(--inv));
  opacity: .8;
  animation: dashRun 1s linear infinite;
}
@keyframes dashRun { to { stroke-dashoffset: -26px; } }

.map__acc   { fill: color-mix(in oklab, var(--ok) 22%, transparent); stroke: var(--ok); stroke-opacity: .35; stroke-width: 1; }
.map__cone  { fill: color-mix(in oklab, var(--ok) 30%, transparent); }
.map__youdot{ fill: var(--ok); stroke: #fff; stroke-width: calc(2.5px * var(--inv)); }
.map__youping {
  fill: none; stroke: var(--ok); stroke-width: 2;
  transform-box: fill-box; transform-origin: center;
  animation: youPing 2.4s ease-out infinite;
}
@keyframes youPing {
  0%   { transform: scale(1);   opacity: .8; }
  100% { transform: scale(3.4); opacity: 0; }
}

.map__controls {
  position: absolute;
  right: 10px; top: 10px;
  display: grid; gap: 6px;
}
.map__ctrl {
  /* Was 38px. These are the controls you use one-handed, walking, in sunlight —
     the last place to shave 6px off Apple's 44pt minimum. */
  width: var(--tap); height: var(--tap);
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  background: color-mix(in oklab, var(--surface-solid) 88%, transparent);
  -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border: 1px solid var(--hairline-strong);
  color: var(--ink);
  font-size: 15px;
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: transform var(--dur) var(--ease-spring);
}
.map__ctrl:active { transform: scale(.9); }
.map__info { padding: 0 2px; line-height: 1.5; }

/* ============================================================
   3. HUNT — easter eggs & photo reveals
   ============================================================ */
.hunt__progress {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-4);
  align-items: center;
}
.eggrid { display: grid; gap: var(--s-3); }
@media (min-width: 620px) { .eggrid { grid-template-columns: 1fr 1fr; } }

.egg {
  position: relative;
  overflow: hidden;
  padding: 0;
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  background: var(--surface);
  text-align: left;
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition: transform var(--dur) var(--ease-spring), border-color var(--dur);
}
.egg:active { transform: scale(.985); }
.egg.is-found { border-color: color-mix(in oklab, var(--ok) 55%, var(--hairline)); }
.egg.is-near  { border-color: var(--gold-400); box-shadow: 0 0 0 3px color-mix(in oklab, var(--gold-400) 22%, transparent); }

.egg__media {
  position: relative;
  aspect-ratio: 16 / 10;
  background: linear-gradient(150deg, var(--violet-800), var(--violet-950));
  display: grid; place-items: center;
  overflow: hidden;
}
.egg__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* The veil is the whole point: a heavy blur + scrim so a passing glance can't
   spoil the answer, but the shape underneath still teases that there IS one. */
.egg__veil {
  position: absolute; inset: 0;
  display: grid; place-items: center; gap: 6px;
  align-content: center;
  padding: var(--s-4);
  text-align: center;
  background: color-mix(in oklab, var(--violet-950) 62%, transparent);
  -webkit-backdrop-filter: blur(18px) saturate(.5); backdrop-filter: blur(18px) saturate(.5);
  transition: opacity .5s var(--ease-out), -webkit-backdrop-filter .5s, backdrop-filter .5s;
}
.egg.is-found .egg__veil,
.egg__veil.is-lifted { opacity: 0; pointer-events: none; -webkit-backdrop-filter: blur(0); backdrop-filter: blur(0); }
.egg__veil-ico  { font-size: 30px; filter: drop-shadow(0 2px 8px rgba(0,0,0,.5)); }
.egg__veil-text { font-size: var(--t-xs); font-weight: 700; color: #fff; opacity: .92; }

.egg__body { padding: var(--s-4); display: grid; gap: 8px; }
.egg__title { font-weight: 800; font-size: var(--t-md); line-height: 1.25; }
.egg__teaser { font-size: var(--t-sm); color: var(--ink-2); line-height: 1.55; }
.egg__meta { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

.diff { letter-spacing: .1em; color: var(--gold-400); font-size: 12px; }

.egg__found-stamp {
  position: absolute; top: 10px; right: 10px;
  display: grid; place-items: center;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--ok);
  color: #05230f;
  font-weight: 900;
  box-shadow: var(--shadow-lift);
  animation: stampIn .45s var(--ease-spring) both;
}
@keyframes stampIn {
  from { transform: scale(0) rotate(-30deg); opacity: 0; }
  to   { transform: scale(1) rotate(-8deg); opacity: 1; }
}

/* the reveal moment */
.reveal {
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--hairline);
}
.reveal__img { width: 100%; display: block; background: var(--surface-2); }
.reveal__cap { padding: var(--s-3); font-size: var(--t-xs); color: var(--ink-3); background: var(--surface-2); }

.photoframe {
  position: relative;
  border-radius: var(--r-md);
  overflow: hidden;
  aspect-ratio: 1;
  background: var(--surface-2);
  border: 1px solid var(--hairline);
}
.photoframe img { width: 100%; height: 100%; object-fit: cover; display: block; }
.photoframe__del {
  /* 10px, not 4px: .photoframe is overflow:hidden, which clips pointer hits as
     well as paint. At 4px the 46pt target below would be cut off past the top
     and right edges; at 10px its centre sits 23px in and the whole square fits. */
  position: absolute; top: 10px; right: 10px;
  width: 26px; height: 26px; border-radius: 50%;
  border: 0; cursor: pointer;
  background: rgba(0,0,0,.6); color: #fff; font-size: 13px;
  display: grid; place-items: center;
}
/* Stays 26px to the eye — a bigger badge would cover the photo it deletes — but
   claims a full 44pt to the thumb. Deleting a memory by accident is the worst
   miss in the app, so the target grows without the dot growing. */
.photoframe__del::before {
  content: ''; position: absolute;
  top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: var(--tap); height: var(--tap);
}

/* ============================================================
   4. ASK — chat with the oracle / home brain
   ============================================================ */
.chat {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding-bottom: var(--s-4);
}
.msg { max-width: 88%; display: grid; gap: 5px; animation: msgIn .28s var(--ease-out) both; }
@keyframes msgIn { from { opacity: 0; transform: translateY(8px); } }
.msg--me  { justify-self: end; }
.msg--pal { justify-self: start; }
.msg__body {
  padding: 11px 14px;
  border-radius: 18px;
  font-size: var(--t-sm);
  line-height: 1.6;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.msg--me .msg__body {
  background: var(--accent);
  color: var(--accent-ink);
  border-bottom-right-radius: 6px;
  font-weight: 600;
}
.msg--pal .msg__body {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-bottom-left-radius: 6px;
}
.msg__meta { font-size: 10.5px; color: var(--ink-3); padding: 0 6px; display: flex; gap: 8px; align-items: center; }
.msg--me .msg__meta { justify-content: flex-end; }

/* Which tier answered — the user should always know. */
.tier { display: inline-flex; align-items: center; gap: 4px; font-weight: 700; }
.tier--brain   { color: var(--accent); }
.tier--offline { color: var(--info); }
.tier--cache   { color: var(--ink-3); }

.srcs { display: flex; flex-wrap: wrap; gap: 5px; padding: 0 6px; }
.src {
  font-size: 10.5px;
  padding: 3px 8px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  color: var(--ink-2);
  text-decoration: none;
}
.src:hover { border-color: var(--accent); color: var(--ink); }

.caret::after {
  content: '▋';
  animation: blink 1s steps(2) infinite;
  color: var(--accent);
  margin-left: 1px;
}
@keyframes blink { 50% { opacity: 0; } }

.composer {
  position: sticky;
  /* --nav-h already embeds safe-area-inset-bottom (core.css). Adding the inset
     again floated the composer a home-indicator's height above the nav bar. */
  bottom: var(--nav-h);
  display: flex;
  gap: 8px;
  padding: var(--s-3) 0;
  background: linear-gradient(to top, var(--bg) 62%, transparent);
  z-index: 5;
}
.composer textarea {
  flex: 1;
  resize: none;
  min-height: var(--tap);
  max-height: 140px;
  padding: 12px 14px;
  border-radius: 22px;
  background: var(--surface);
  border: 1px solid var(--hairline-strong);
  color: var(--ink);
  font: inherit;
  font-size: 16px;     /* < 16px makes iOS Safari zoom on focus */
  line-height: 1.4;
}
.composer textarea:focus { outline: none; border-color: var(--accent); }
.composer .send {
  width: var(--tap); height: var(--tap);
  flex: none;
  border-radius: 50%;
  border: 0;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 18px;
  cursor: pointer;
  transition: transform var(--dur) var(--ease-spring);
}
.composer .send:active { transform: scale(.88); }
.composer .send:disabled { opacity: .4; cursor: default; }

.suggests { display: flex; flex-wrap: wrap; gap: 6px; }

/* ============================================================
   5. PLAN — day timeline
   ============================================================ */
.tl { display: grid; gap: 0; position: relative; }
.tlitem {
  display: grid;
  grid-template-columns: 54px 22px 1fr;
  gap: var(--s-2);
  align-items: start;
  padding: var(--s-3) 0;
}
.tlitem__time {
  font-variant-numeric: tabular-nums;
  font-weight: 800;
  font-size: var(--t-sm);
  padding-top: 2px;
  color: var(--ink-2);
}
.tlitem__rail { position: relative; display: grid; justify-items: center; padding-top: 4px; }
.tlitem__rail::before {
  content: '';
  position: absolute;
  top: 0; bottom: -100%;
  width: 2px;
  background: var(--hairline-strong);
}
.tlitem:last-child .tlitem__rail::before { display: none; }
.tlitem__dot {
  position: relative;
  width: 13px; height: 13px;
  border-radius: 50%;
  background: var(--surface-solid);
  border: 2.5px solid var(--accent);
  z-index: 1;
}
.tlitem.is-now .tlitem__dot { background: var(--gold-400); border-color: var(--gold-400); }
.tlitem.is-past { opacity: .48; }
.tlitem.is-past .tlitem__dot { border-color: var(--ink-3); }
.tlitem__body { display: grid; gap: 4px; }
.tlitem__title { font-weight: 700; font-size: var(--t-sm); line-height: 1.3; }
.tlitem__sub { font-size: var(--t-xs); color: var(--ink-3); line-height: 1.45; }

.nowline {
  position: relative;
  height: 0;
  border-top: 2px dashed var(--gold-400);
  margin: 2px 0;
}
.nowline::after {
  content: 'now';
  position: absolute; right: 0; top: -9px;
  font-size: 9.5px; font-weight: 900; letter-spacing: .1em; text-transform: uppercase;
  color: var(--gold-400);
  background: var(--bg);
  padding: 0 5px;
}

/* ============================================================
   6. GUIDE — searchable lists
   ============================================================ */
/* --top-total = topbar + safe-area-inset-top. Using bare --top-h parked the
   sticky search field under the notch on an iPhone. */
.searchbar { position: sticky; top: calc(var(--top-total) + 4px); z-index: 6; padding: 6px 0; background: var(--bg); }
.searchbar input {
  width: 100%;
  height: var(--tap);
  padding: 0 16px;
  border-radius: var(--r-pill);
  background: var(--surface);
  border: 1px solid var(--hairline-strong);
  color: var(--ink);
  font-size: 16px;
}
.searchbar input:focus { outline: none; border-color: var(--accent); }

.list { display: grid; gap: 2px; }
.listitem {
  display: grid;
  grid-template-columns: 38px 1fr auto;
  gap: var(--s-3);
  align-items: center;
  padding: 11px var(--s-2);
  border-radius: var(--r-md);
  background: none; border: 0; color: inherit; font: inherit;
  text-align: left; cursor: pointer; text-decoration: none;
  transition: background var(--dur);
}
.listitem + .listitem { border-top: 1px solid var(--hairline); }
.listitem:hover, .listitem:focus-visible { background: var(--surface-2); }
.listitem__ico { display: grid; place-items: center; width: 38px; height: 38px; border-radius: var(--r-sm); background: var(--surface-2); font-size: 18px; }
.listitem__name { font-weight: 700; font-size: var(--t-sm); line-height: 1.3; }
.listitem__sub  { font-size: var(--t-xs); color: var(--ink-3); margin-top: 2px; line-height: 1.4; }

.landhead {
  position: sticky;
  top: calc(var(--top-total) + 4px);   /* see .searchbar — must clear the notch too */
  z-index: 4;
  padding: 8px 2px;
  background: var(--bg);
  font-size: var(--t-xs);
  font-weight: 900;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.factgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(112px, 1fr)); gap: var(--s-2); }
.fact { padding: var(--s-3); border-radius: var(--r-md); background: var(--surface-2); border: 1px solid var(--hairline); }
.fact__k { font-size: 10px; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3); font-weight: 800; }
.fact__v { font-size: var(--t-sm); font-weight: 700; margin-top: 4px; }

/* ============================================================
   7. PLAY — bingo & trivia
   ============================================================ */
.bingo {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 5px;
  container-type: inline-size;
}
.bcell {
  position: relative;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  padding: 4px 3px;
  border-radius: var(--r-sm);
  background: var(--surface);
  border: 1px solid var(--hairline);
  color: var(--ink-2);
  font-size: clamp(7px, 2.05cqw, 10px);
  font-weight: 600;
  line-height: 1.18;
  text-align: center;
  cursor: pointer;
  overflow: hidden;
  transition: transform var(--dur) var(--ease-spring), background var(--dur), color var(--dur);
}
.bcell:active { transform: scale(.9); }
.bcell.is-hit {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
  font-weight: 800;
}
.bcell.is-hit::after {
  content: '✦';
  position: absolute;
  inset: 0;
  display: grid; place-items: center;
  font-size: 2.4em;
  opacity: .22;
  pointer-events: none;
}
.bcell.is-free { background: var(--surface-2); border-style: dashed; }
.bcell.is-line { box-shadow: inset 0 0 0 2px var(--gold-400); }

.quiz__q { font-size: var(--t-lg); font-weight: 800; line-height: 1.3; }
.qopts { display: grid; gap: var(--s-2); }
.qopt {
  padding: 13px 15px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1.5px solid var(--hairline-strong);
  text-align: left;
  color: inherit;
  font: inherit;
  font-size: var(--t-sm);
  cursor: pointer;
  transition: transform var(--dur) var(--ease-spring), border-color var(--dur), background var(--dur);
}
.qopt:active { transform: scale(.985); }
.qopt:hover:not(:disabled) { border-color: var(--accent); }
.qopt.is-right { border-color: var(--ok); background: color-mix(in oklab, var(--ok) 15%, var(--surface)); font-weight: 700; }
.qopt.is-wrong { border-color: var(--bad); background: color-mix(in oklab, var(--bad) 14%, var(--surface)); }
.qopt:disabled { cursor: default; }

.streakbar { display: flex; gap: 4px; }
.streakbar i { width: 9px; height: 9px; border-radius: 50%; background: var(--hairline-strong); }
.streakbar i.on { background: var(--gold-400); }

/* ============================================================
   8. HISTORY — era rail
   ============================================================ */
.era {
  position: relative;
  padding-left: var(--s-5);
  padding-bottom: var(--s-5);
  border-left: 2px solid var(--hairline-strong);
}
.era:last-child { border-left-color: transparent; padding-bottom: 0; }
.era::before {
  content: '';
  position: absolute;
  left: -8px; top: 4px;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--era, var(--accent));
  box-shadow: 0 0 0 4px var(--bg);
}
.era__years {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-weight: 700;
  color: var(--era, var(--accent));
  letter-spacing: .04em;
}
.era__name { font-family: var(--font-display); font-size: var(--t-lg); font-weight: 900; line-height: 1.2; margin-top: 3px; letter-spacing: -.02em; }
.era__sum  { font-size: var(--t-sm); color: var(--ink-2); line-height: 1.65; margin-top: 8px; }

.milestone {
  display: grid;
  grid-template-columns: 62px 1fr;
  gap: var(--s-3);
  padding: 9px 0;
  font-size: var(--t-sm);
  line-height: 1.5;
}
.milestone + .milestone { border-top: 1px solid var(--hairline); }
.milestone__when { font-family: var(--font-mono); font-weight: 700; color: var(--ink-3); font-size: var(--t-xs); padding-top: 2px; }

/* ============================================================
   9. JOURNAL
   ============================================================ */
.jgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 6px; }
.jentry { display: grid; gap: 8px; }
.jentry__when { font-size: var(--t-xs); color: var(--ink-3); font-variant-numeric: tabular-nums; }
.jentry__text { font-size: var(--t-sm); line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; }

.moodrow { display: flex; gap: 6px; flex-wrap: wrap; }
.mood {
  width: 42px; height: 42px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1.5px solid var(--hairline-strong);
  background: var(--surface);
  font-size: 19px;
  cursor: pointer;
  transition: transform var(--dur) var(--ease-spring);
}
.mood:active { transform: scale(.88); }
.mood[aria-pressed="true"] { border-color: var(--accent); background: color-mix(in oklab, var(--accent) 20%, var(--surface)); transform: scale(1.06); }

/* ============================================================
   10. SETTINGS
   ============================================================ */
.setrow {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--s-3);
  align-items: center;
  padding: 13px 0;
}
.setrow + .setrow { border-top: 1px solid var(--hairline); }
.setrow__k { font-weight: 700; font-size: var(--t-sm); }
.setrow__d { font-size: var(--t-xs); color: var(--ink-3); margin-top: 3px; line-height: 1.5; }

.qr {
  display: grid;
  place-items: center;
  padding: var(--s-4);
  background: #fff;
  border-radius: var(--r-md);
}
.qr img, .qr svg { width: min(240px, 70vw); height: auto; image-rendering: pixelated; }

.codeblock {
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.65;
  padding: var(--s-3);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  overflow-x: auto;
  white-space: pre;
  -webkit-user-select: all; user-select: all;
}

.healthrow { display: flex; align-items: center; gap: 8px; font-size: var(--t-xs); padding: 5px 0; }
.healthrow__dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.healthrow__dot.ok  { background: var(--ok); }
.healthrow__dot.bad { background: var(--bad); }

/* ============================================================
   11. SHARED
   ============================================================ */
.row-wrap { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

.countdown {
  display: flex;
  gap: var(--s-2);
  font-variant-numeric: tabular-nums;
}
.countdown__unit {
  flex: 1;
  text-align: center;
  padding: var(--s-3) 4px;
  border-radius: var(--r-md);
  background: var(--surface-2);
  border: 1px solid var(--hairline);
}
.countdown__n { font-size: var(--t-xl); font-weight: 900; line-height: 1; font-family: var(--font-display); }
.countdown__l { font-size: 9.5px; text-transform: uppercase; letter-spacing: .12em; color: var(--ink-3); margin-top: 5px; font-weight: 700; }

.checkrow {
  display: grid;
  grid-template-columns: 26px 1fr;
  gap: var(--s-3);
  align-items: start;
  padding: 10px var(--s-2);
  border-radius: var(--r-sm);
  cursor: pointer;
  background: none; border: 0; color: inherit; font: inherit; text-align: left; width: 100%;
}
.checkrow + .checkrow { border-top: 1px solid var(--hairline); }
.checkrow:hover { background: var(--surface-2); }
.checkrow__box {
  width: 22px; height: 22px;
  margin-top: 1px;
  border-radius: 7px;
  border: 2px solid var(--hairline-strong);
  display: grid; place-items: center;
  font-size: 13px; font-weight: 900;
  color: transparent;
  transition: background var(--dur), border-color var(--dur), color var(--dur);
}
.checkrow.is-done .checkrow__box { background: var(--ok); border-color: var(--ok); color: #05230f; }
.checkrow.is-done .checkrow__label { text-decoration: line-through; opacity: .5; }
.checkrow__label { font-size: var(--t-sm); line-height: 1.45; }
.checkrow__note { font-size: var(--t-xs); color: var(--ink-3); margin-top: 3px; line-height: 1.45; }

.kbd {
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 2px 6px;
  border-radius: 5px;
  background: var(--surface-2);
  border: 1px solid var(--hairline-strong);
  border-bottom-width: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .hero__glow, .pulse-dot, .map__youping, .map__routeline, .caret::after { animation: none; }
  .map__world { transition: none; }
}
