:root {
  --sky: #f7dccb;
  --ink: #4a3d63;
  --ink-soft: rgba(74, 61, 99, 0.62);
  --panel: rgba(255, 249, 240, 0.62);
  --panel-strong: rgba(255, 250, 243, 0.86);
  --line: rgba(74, 61, 99, 0.16);
  --accent: #3a7a8d;
  --font: "Avenir Next", "Avenir", Futura, "Century Gothic", "Segoe UI", system-ui, sans-serif;
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
}

body.dark {
  --ink: #eef0ff;
  --ink-soft: rgba(238, 240, 255, 0.62);
  --panel: rgba(22, 27, 54, 0.5);
  --panel-strong: rgba(26, 31, 62, 0.86);
  --line: rgba(238, 240, 255, 0.16);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0; height: 100%; overflow: hidden;
  color: var(--ink);
  font-family: var(--font);
  -webkit-user-select: none; user-select: none;
  overscroll-behavior: none;
}

html { min-height: 100vh; min-height: 100lvh; background: #c6a3c4; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
html, body { overflow-x: hidden; }
body { background: transparent; }
/* full large viewport: as a home-screen app iOS reports a shorter height for
   100%/inset, which left a strip above the home indicator */
#scene { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; height: 100lvh; display: block; touch-action: none; }

button {
  font: inherit; color: inherit; cursor: pointer;
  border: 0; background: none;
}

svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- HUD ---------- */
.hud { position: fixed; left: 0; right: 0; display: flex; align-items: center; gap: 12px; padding: 12px 14px; pointer-events: none; z-index: 2; }
.hud > * { pointer-events: auto; }
.hud.top { top: 0; padding-top: calc(12px + var(--safe-t)); display: grid; grid-template-columns: 46px 1fr 46px; }
.hud-spacer { width: 46px; }
.hud.bottom { bottom: 0; padding-bottom: calc(14px + var(--safe-b)); flex-direction: column; align-items: stretch; gap: 10px; }

.icon-btn {
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--panel); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 6px 24px rgba(40, 20, 60, 0.08);
  transition: transform .25s cubic-bezier(.2,.9,.3,1.4), background .3s;
}
.icon-btn:active { transform: scale(.9); }

.title { flex: 1; display: flex; flex-direction: column; align-items: center; line-height: 1.15; }
#pz-name { font-size: 15px; letter-spacing: .32em; text-transform: uppercase; font-weight: 500; }
#pz-meta { font-size: 11px; letter-spacing: .2em; color: var(--ink-soft); text-transform: uppercase; }

.sub-line { display: flex; align-items: baseline; justify-content: center; gap: 0; margin-top: 3px; font-size: 11px; letter-spacing: .2em; color: var(--ink-soft); text-transform: uppercase; font-variant-numeric: tabular-nums; }
#pz-meta { font-size: inherit; }
#timer:not(:empty)::before { content: "·"; margin: 0 .55em 0 .35em; }
#strikes { color: #d4505a; letter-spacing: .25em; }
.slip { color: #d4505a; }
#strikes:not(:empty) { margin-left: .8em; }

.tools {
  /* the switch sits centred under the title */
  display: flex; justify-content: center; align-items: center;
  width: 100%;
}

.segmented {
  justify-self: center; display: flex; padding: 4px; border-radius: 999px; position: relative;
  width: 204px; height: 46px;
  background: var(--panel); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 6px 24px rgba(40, 20, 60, 0.08);
}
/* a soft highlight that slides between the two tools */
.segmented::before {
  content: ""; position: absolute; top: 4px; left: 4px; width: calc(50% - 4px); height: calc(100% - 8px);
  border-radius: 999px; background: var(--panel-strong);
  box-shadow: 0 2px 10px rgba(40, 20, 60, 0.1), inset 0 0 0 1px rgba(255, 255, 255, 0.5);
  transition: transform .45s var(--ease-out);
}
.segmented[data-tool="paint"]::before { transform: translateX(100%); }
body.dark .segmented::before { background: rgba(255, 255, 255, 0.14); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12); }
.tool {
  flex: 1; position: relative; z-index: 1; border-radius: 999px;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  font-size: 10.5px; letter-spacing: .24em; text-transform: uppercase; color: var(--ink-soft);
  transition: color .35s;
}
.tool svg { width: 17px; height: 17px; }
.tool.on { color: var(--ink); }
/* tutorial: the tool a hint asks for breathes, at the pace of the hinted cube */
.tool.cue { color: var(--ink); }
.tool.cue::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: 0 0 0 2px var(--ink); opacity: .5; animation: tool-cue 1.57s ease-in-out infinite;
}
@keyframes tool-cue { 0%, 100% { opacity: .15; } 50% { opacity: .6; } }
@media (prefers-reduced-motion: reduce) {
  .tool.cue::after { animation: none; opacity: .45; }
  #coach, #coach.show { transform: translate(-50%, 0); }
}

#press-ring {
  position: fixed; width: 64px; height: 64px; margin: -32px 0 0 -32px; border-radius: 50%;
  border: 2px solid var(--panel-strong); pointer-events: none; z-index: 3;
  opacity: 0; transform: scale(.4);
}
#press-ring.go { animation: ring .42s linear forwards; }
@keyframes ring { from { opacity: .0; transform: scale(1.3); } to { opacity: .9; transform: scale(.55); } }

/* ---------- overlays ---------- */
.overlay {
  position: fixed; inset: 0; z-index: 5; display: grid; place-items: center; padding: 20px;
  background: color-mix(in srgb, var(--sky) 40%, transparent);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  opacity: 0; pointer-events: none; transition: opacity .5s ease;
}
.overlay.show { opacity: 1; pointer-events: auto; }
.panel {
  width: min(640px, 100%); max-height: calc(100% - 20px); overflow: auto;
  padding: 34px 26px 26px; border-radius: 28px;
  background: var(--panel-strong);
  box-shadow: 0 30px 80px rgba(40, 20, 60, 0.18);
  transform: translateY(14px); transition: transform .6s var(--ease-out);
}
.overlay.show .panel { transform: none; }
.panel { scrollbar-width: none; }
.panel::-webkit-scrollbar { display: none; }
.panel.narrow { width: min(400px, 100%); }
.panel.center { text-align: center; }

h1, h2 { font-weight: 400; text-transform: uppercase; margin: 0; }
h1 { font-size: 30px; letter-spacing: .5em; text-align: center; padding-left: .5em; }
h2 { font-size: 22px; letter-spacing: .32em; margin-bottom: 14px; }
.sub { font-size: 11px; letter-spacing: .32em; text-transform: uppercase; color: var(--ink-soft); text-align: center; margin: 8px 0 22px; }
.panel p { font-size: 15px; line-height: 1.55; }

.row button {
  padding: 12px 18px; border-radius: 999px; font-size: 13px; letter-spacing: .2em; text-transform: uppercase;
  box-shadow: inset 0 0 0 1px var(--line);
}
.row { display: flex; gap: 10px; justify-content: center; margin-top: 10px; }
button.primary { background: var(--ink); color: var(--sky); box-shadow: none; padding: 12px 24px; border-radius: 999px; letter-spacing: .24em; text-transform: uppercase; font-size: 13px; }
#help .primary { display: block; margin: 20px auto 0; }
#help .panel { padding-top: 30px; }
#help h2 { text-align: center; padding-left: .32em; margin-bottom: 18px; }

/* How to play's three pages: Rules, Touch, Settings. A pill like the tools,
   its highlight sliding between them; the pages share one height so the panel
   never jumps as you switch */
.tabs { position: relative; display: flex; padding: 4px; border-radius: 999px; margin: 0 auto 20px; max-width: 320px;
  background: color-mix(in srgb, var(--ink) 6%, transparent); }
.tabs::before { content: ""; position: absolute; top: 4px; left: 4px; width: calc((100% - 8px) / 3); height: calc(100% - 8px);
  border-radius: 999px; background: var(--panel-strong); box-shadow: 0 2px 10px rgba(40, 20, 60, 0.1);
  transition: transform .45s var(--ease-out); }
.tabs[data-tab="1"]::before { transform: translateX(100%); }
.tabs[data-tab="2"]::before { transform: translateX(200%); }
.tabs button { flex: 1; position: relative; z-index: 1; padding: 10px 0; border-radius: 999px; background: none; box-shadow: none;
  font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase; color: var(--ink-soft); transition: color .3s; }
.tabs button[aria-selected="true"] { color: var(--ink); }
.help-pages { display: grid; }
.help-pages > .help-page { grid-area: 1 / 1; }
.help-pages > .help-page[hidden] { display: block; visibility: hidden; }
.help-page.in { animation: page-in .45s var(--ease-out) both; }
@keyframes page-in { from { opacity: 0; transform: translateY(6px); } }
@media (prefers-reduced-motion: reduce) { .help-page.in { animation: none; } .tabs::before { transition: none; } }

.help-page .lead { margin: 0 0 16px; font-size: 16px; line-height: 1.5; }
.help-page .aside { margin: 16px 0 0; font-size: 13.5px; line-height: 1.55; color: var(--ink-soft); }
.legend, .gestures { margin: 0; display: grid; }
.legend { grid-template-columns: 44px 1fr; gap: 12px 12px; align-items: center; }
.legend dt { display: grid; place-items: center; }
.legend dd, .gestures dd { margin: 0; font-size: 14px; line-height: 1.45; }
.glyph.plain { border-color: transparent; font-size: 15px; }
.glyph.slip { border-color: transparent; font-size: 15px; }
.gems { font-size: 10px; letter-spacing: .1em; color: var(--ink); white-space: nowrap; }
.gestures { grid-template-columns: minmax(0, 54%) 1fr; }
.gestures dt, .gestures dd { padding: 10px 0; border-top: 1px solid var(--line); }
.gestures dt:first-of-type, .gestures dt:first-of-type + dd { border-top: 0; padding-top: 2px; }
.gestures dt { font-weight: 700; font-size: 14px; padding-right: 12px; }
.gestures dd { color: var(--ink-soft); }
#help-more .toggles { margin-top: 4px; }
#help-more .home-tip { margin-top: 18px; }
#help-more .home-tip p { font-size: 13px; line-height: 1.55; }

.glyph { display: inline-grid; place-items: center; width: 24px; height: 24px; font-size: 13px; border: 1.5px solid currentColor; margin: 0 2px; }
.glyph.circle { border-radius: 50%; }
.glyph.square { border-radius: 4px; }

#loading { position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); font-size: 11px; letter-spacing: .4em; text-transform: uppercase; color: var(--ink-soft); pointer-events: none; z-index: 4; }

@media (min-width: 900px) {
  .tools { width: min(460px, 100%); margin: 0 auto; }
}
@media (prefers-reduced-motion: reduce) {
  .overlay, .panel, .icon-btn { transition: none; }
}

/* the solved shape stays in full view behind the result card */
#win { place-items: end center; background: none; backdrop-filter: none; -webkit-backdrop-filter: none; padding-bottom: calc(24px + var(--safe-b)); }
#win .panel { padding: 22px 24px 20px; }
#win h2 { margin-bottom: 4px; }
#win .sub { margin: 6px 0 14px; }

/* ---------- tutorial coach ---------- */
#coach {
  position: fixed; z-index: 2; left: 50%; top: calc(76px + var(--safe-t));
  width: min(440px, calc(100% - 28px)); transform: translate(-50%, -8px);
  padding: 14px 18px 12px; border-radius: 20px; text-align: center;
  background: var(--panel); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 10px 30px rgba(40, 20, 60, 0.08);
  opacity: 0; pointer-events: none;
  /* leaves with `in`, faster than it came (docs/motion.md) */
  transition: opacity var(--dur-base) var(--ease-in), transform var(--dur-base) var(--ease-in);
}
#coach.show {
  opacity: 1; transform: translate(-50%, 0); pointer-events: auto;
  transition: opacity var(--dur-slow) var(--ease-fade), transform var(--dur-slow) var(--ease-out);
}
/* between hints the card keeps only its dots and skip: the block is tried first */
#coach.quiet { padding: 8px 18px 4px; }
#coach.quiet #coach-text { display: none; }
#coach-skip[hidden] { display: none; }
#coach-text { margin: 6px 0 4px; font-size: 15px; line-height: 1.45; }
#coach-dots { display: flex; gap: 6px; justify-content: center; }
/* the rebuilt lessons (docs/tutorial-study.md): words large enough to read without glasses, in full ink */
.lessons-v2 #coach-text { font-size: 18px; line-height: 1.4; color: var(--ink); }
#timer[hidden] { display: none; }

/* the ghost finger: a soft fingertip showing a lesson's move on the stone */
#finger { position: fixed; left: 0; top: 0; width: 0; height: 0; z-index: 3; pointer-events: none; opacity: 0; transition: opacity .5s var(--ease-fade); }
#finger.show { opacity: 1; }
#finger span { position: absolute; left: -17px; top: -17px; width: 34px; height: 34px; border-radius: 50%; }
#finger .tip { background: rgba(255, 255, 255, .78); box-shadow: 0 3px 12px rgba(40, 20, 60, .28), inset 0 0 0 1.5px rgba(255, 255, 255, .95); animation: finger-tap 2s ease-in-out infinite; }
#finger .ring { border: 2px solid rgba(255, 255, 255, .95); opacity: 0; animation: finger-ring 2s ease-out infinite; }
#finger .ring.two { display: none; }
#finger.double .tip { animation-name: finger-double; }
#finger.double .ring.two { display: block; animation-delay: .34s; }
#finger.drag .tip { animation: finger-drag 2.6s ease-in-out infinite; }
#finger.drag .ring { display: none; }
#finger.slide .tip { animation: finger-slide 2.4s ease-in-out infinite; }
#finger.slide .ring { display: none; }
@keyframes finger-tap { 0%, 100% { transform: translate(14px, 22px) scale(1); opacity: 0; } 18% { opacity: 1; } 34% { transform: translate(0, 0) scale(1.05); } 44% { transform: scale(.82); } 58% { transform: scale(1); opacity: 1; } 80% { transform: translate(14px, 22px); opacity: 0; } }
@keyframes finger-double { 0%, 100% { transform: translate(14px, 22px) scale(1); opacity: 0; } 18% { opacity: 1; } 30% { transform: translate(0, 0) scale(1.05); } 38% { transform: scale(.82); } 46% { transform: scale(1.02); } 54% { transform: scale(.82); } 64% { transform: scale(1); opacity: 1; } 84% { transform: translate(14px, 22px); opacity: 0; } }
@keyframes finger-ring { 0%, 40% { transform: scale(.5); opacity: 0; } 45% { transform: scale(.6); opacity: .9; } 80%, 100% { transform: scale(1.7); opacity: 0; } }
@keyframes finger-drag { 0% { transform: translateX(-70px) scale(.9); opacity: 0; } 15% { transform: translateX(-70px) scale(.82); opacity: 1; } 70% { transform: translateX(70px) scale(.82); opacity: 1; } 85%, 100% { transform: translateX(70px) scale(.9); opacity: 0; } }
@keyframes finger-slide { 0% { transform: translate(0, 0) scale(.9); opacity: 0; } 15% { transform: translate(0, 0) scale(.82); opacity: 1; } 70% { transform: translate(var(--dx, 0), var(--dy, 40px)) scale(.82); opacity: 1; } 85%, 100% { transform: translate(var(--dx, 0), var(--dy, 40px)) scale(.9); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { #finger .tip, #finger .ring { animation: none; } #finger .tip { opacity: 1; } }
#coach-dots i { width: 6px; height: 6px; transform: rotate(45deg); background: var(--line); transition: background .4s; }
#coach-dots i.done { background: var(--ink-soft); }
#coach-dots i.now { background: var(--ink); }
#coach-skip { font-size: 10px; letter-spacing: .3em; text-transform: uppercase; color: var(--ink-soft); padding: 6px 10px; }

/* ---------- puzzle map ---------- */
#menu { display: block; padding: 0; background: none; backdrop-filter: none; -webkit-backdrop-filter: none; }
/* The map fades its parts, never itself: a parent with opacity < 1 stops the
   backdrop's blur from seeing the scene, so fading #menu as a whole showed the
   level sharp through it until the fade ended - then the blur snapped on. */
#menu, #menu.show { opacity: 1; }
#menu { visibility: hidden; transition: visibility 0s .5s; }
#menu.show { visibility: visible; transition: visibility 0s; }
#menu > * { opacity: 0; transition: opacity .5s ease; }
#menu.show > * { opacity: 1; }
#menu.instant, #menu.instant > *, #menu.pulling > * { transition: none; }
/* hidden, the map's loops (ripples, halos, the companion's lamp) still ran and
   restyled the page every frame under the level; they wait where they are */
#menu:not(.show) * { animation-play-state: paused; }
.map-scroll {
  position: absolute; inset: 0; overflow-y: auto; overflow-x: hidden;
  -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
  scrollbar-width: none; touch-action: pan-y;
}
.map-scroll::-webkit-scrollbar { display: none; }
/* the map's world (mapworld.js) is its own fixed layers behind the canvas: no veil, no blur */
.map-backdrop { position: fixed; inset: 0; background: none; pointer-events: none; }
/* the map keeps its own ink: names sit on each chapter's cloud, not on the level's sky */
#menu .map-scroll { --ink: #4a3d63; --ink-soft: rgba(74, 61, 99, .62); color: var(--ink); }
.map-head { text-align: center; padding: calc(78px + var(--safe-t)) 20px 6px; text-shadow: 0 0 14px rgba(255, 250, 244, .8); }   /* clear of the corner buttons */
.map-head .sub { margin: 10px 0 0; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
#map-progress { margin-top: 4px; letter-spacing: .26em; }

.map { position: relative; width: 100%; }
.map-svg { position: absolute; left: 0; top: 0; overflow: visible; pointer-events: none; stroke: none; }
.trail { fill: none; stroke-width: 2.4; stroke-linecap: round; stroke-dasharray: 0.1 9; stroke-opacity: .55; transition: opacity .9s var(--ease-fade); }
.trail.walked { stroke-dasharray: none; stroke-width: 2.2; stroke-opacity: .45; }
.trail.tail { stroke-opacity: .3; }
/* inside a chapter whose mist is lifting: created hidden, revealed by removing the class */
.trail.in-parting { opacity: 0; }

/* ---------- the map's world (mapworld.js) ----------
   The scene is inside the map's scroller, under the stones, so it scrolls with
   them on the compositor: no script runs while the map scrolls. The fixed
   #map-world behind the canvas holds only the title's sky, and once the map is
   up, the chapter's sea as the backdrop of dives and pull-backs. */
#map-world { position: fixed; left: 0; top: 0; width: 100vw; height: 100vh; height: 100lvh; z-index: -1; overflow: hidden; pointer-events: none; display: none; background: #121731; }
body.world-up #map-world { display: block; }
.mw-sky { position: absolute; left: 0; top: 0; width: 100%; will-change: transform; }
.mw-stars { position: absolute; left: 0; top: 0; width: 100%; overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 calc(100% - 24px - 35vh), transparent calc(100% - 24px));
  mask-image: linear-gradient(180deg, #000 calc(100% - 24px - 35vh), transparent calc(100% - 24px)); }
.mw-starsheet { position: absolute; left: 0; top: 0; will-change: transform; }
/* overflow: clip, not hidden: a hidden box would be a scroll container and
   capture the far layer's scroll timeline */
.mw-scene { position: absolute; left: 0; top: 0; width: 100%; overflow: clip; pointer-events: none; z-index: 0; }
.map-head, .map { position: relative; z-index: 1; }
.mw-strip { position: absolute; inset: 0; }
.mw-dawn { position: absolute; left: 0; top: 0; width: 100%; }
.mw-dusk { position: absolute; left: 0; width: 100%; }   /* over the mist layers, under the stones */
.mw-dusk-stars { position: absolute; left: 0; }
.mw-layer { position: absolute; left: 50%; top: 0; width: 0; height: 0; }
.map-scroll { scroll-timeline: --map-scroll block; }
/* the far layer falls behind the page (0.84 of its speed), driven by the scroll
   itself where the browser supports it (mapworld.js checks), never by script */
.mw-layer.mw-par { animation: mw-par linear both; animation-timeline: --map-scroll; }
@keyframes mw-par { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(0, var(--par, 0px), 0); } }
.mw-spr, .mw-wall { position: absolute; left: 0; top: 0; }
.mw-spr.peak { background-repeat: no-repeat; }
.mw-spr.ghost { opacity: .26; }
.mw-glow { border-radius: 50%; background: radial-gradient(closest-side, var(--g), transparent); }
/* the canvas steps aside while the map is up (the level isn't drawn under it) */
#scene { transition: opacity .5s ease; }
body.map-up #scene { opacity: 0; transition-duration: .28s; }   /* out fast: the level must not linger over the mist */
@media (prefers-reduced-motion: reduce) { #scene { transition: none; } }

.map-region {
  position: absolute; transform: translateY(-50%);
  display: flex; flex-direction: column; gap: 4px;
  color: var(--ink); pointer-events: none;
}
.map-region.at-left { left: var(--edge); align-items: flex-start; }
.map-region.at-right { right: var(--edge); align-items: flex-end; text-align: right; }
.map-region .r-name { font-size: 15px; letter-spacing: .42em; text-transform: uppercase; }
.map-region.at-right .r-name { margin-right: -.42em; }
.map-region .r-sub { font-size: 10px; letter-spacing: .3em; text-transform: uppercase; opacity: .62; }
.on-dark { color: #eef0ff; }

/* the map is filed into bands down the page (map.js): off screen, a band is
   neither painted nor re-layerized while something else on the map animates */
.map-band { position: absolute; left: 0; width: 100%; pointer-events: none; content-visibility: auto; }
.map-node {
  position: absolute; pointer-events: auto; width: 72px; height: 72px; margin: -36px 0 0 -36px;
  display: grid; place-items: center; color: var(--ink);
  transition: transform .35s cubic-bezier(.2,.9,.3,1.4);
}
.map-node.on-dark { color: #eef0ff; }
.map-node:active { transform: scale(.92); }
.map-node .cube { stroke: none; position: relative; filter: drop-shadow(0 6px 10px rgba(40, 20, 60, .16)); transition: transform .5s var(--ease-out); }
.map-node:hover .cube { transform: translateY(-3px); }
.map-node .halo {
  position: absolute; inset: -14px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, color-mix(in srgb, var(--glow) 90%, transparent) 0, transparent 66%);
  opacity: 0;
}
.map-node .label {
  position: absolute; top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; white-space: nowrap; line-height: 1.3;
}
/* labels sit beside the stone, away from the trail, like map annotations */
.map-node.lbl-right .label { left: 66px; align-items: flex-start; text-align: left; }
.map-node.lbl-left .label { right: 66px; align-items: flex-end; text-align: right; }
.map-node.drift .label { top: 58px; left: 50%; transform: translateX(-50%); align-items: center; }
.map-node .n { font-size: 10px; letter-spacing: .26em; opacity: .62; }
.map-node .nm { font-size: 12px; letter-spacing: .26em; text-transform: uppercase; }
.map-node.lbl-left .nm { margin-right: -.26em; }
.map-node .mt { font-size: 9.5px; letter-spacing: .2em; opacity: .62; font-variant-numeric: tabular-nums; }
.stars-mini { display: inline-flex; gap: 3px; margin-top: 3px; }
.stars-mini i { display: block; width: 9px; height: 9px; }
.stars-mini svg { width: 9px; height: 9px; display: block; fill: none; stroke: currentColor; stroke-width: 2; opacity: .55; }
.stars-mini i.on svg { fill: currentColor; opacity: 1; }
.map-node .nm:empty { display: none; }

.map-node .ring {
  position: absolute; inset: 4px; border-radius: 50%; pointer-events: none;
  border: 1.5px solid currentColor; opacity: 0;
}
/* the next stone to uncover breathes */
.map-node.current .ring { animation: ripple 3.2s ease-out infinite; }
@keyframes ripple { 0% { transform: scale(.6); opacity: .5; } 70%, 100% { transform: scale(1.35); opacity: 0; } }
.map-node.current .halo { opacity: 1; animation: breathe 3.2s ease-in-out infinite; }
.map-node.current .cube { animation: bob 3.2s ease-in-out infinite; }
/* the eclipse's edge on the stones you can play now; none on locked ones (or the solved, which show their objects) */
.map-node .cube .rim { display: none; }
.map-node.open .cube .rim, .map-node.current .cube .rim { display: inline; }
.map-node.current .nm { font-weight: 600; }
@keyframes breathe { 0%, 100% { transform: scale(.82); opacity: .55; } 50% { transform: scale(1.08); opacity: 1; } }
@keyframes bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }

/* solved: the uncovered colour, and a small diamond mark */
.map-node .mark {
  position: absolute; top: 12px; right: 12px; width: 9px; height: 9px; transform: rotate(45deg);
  background: currentColor; opacity: .7; box-shadow: 0 0 0 2px color-mix(in srgb, var(--glow) 70%, transparent);
}
.map-node.solved .halo { opacity: .35; }

/* locked: a faint outline of stone, still on the trail */
.map-node.locked { cursor: default; }
.map-node.locked .cube { opacity: .32; filter: grayscale(.7) blur(.3px); }
.map-node.locked .label { opacity: .5; }
.map-node.nudge .cube { animation: nudge .4s ease; }
@keyframes nudge { 20% { transform: translateX(-4px); } 50% { transform: translateX(4px); } 80% { transform: translateX(-2px); } }

.map-node.learn .cube { transform: scale(1.04); }

/* the map's controls, in the pause's voice (its rules): a ring of a hairline
   in the ink's own tint, the map behind it blurred within it rather than a
   tinted fill, a glyph, one word beneath; Resume, the pause's play ring, with
   the ink's full line */
.ring-btn { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 0; background: none; border: 0;
  color: #4a3d63; -webkit-tap-highlight-color: transparent; }
.ring-btn .ring { width: 48px; height: 48px; border-radius: 50%; display: grid; place-items: center;
  border: 1px solid rgba(74, 61, 99, .16);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  transition: transform .25s cubic-bezier(.2,.9,.3,1.4); }
.ring-btn .ring svg { width: 22px; height: 22px; }
.ring-btn:active .ring { transform: scale(.92); }
.ring-label { font-size: 9.5px; letter-spacing: .24em; padding-left: .24em; text-transform: uppercase; color: rgba(74, 61, 99, .62); white-space: nowrap; }
#map-close {
  position: absolute; left: 50%; bottom: calc(22px + var(--safe-b)); translate: -50% 0; z-index: 1;
  opacity: 0; pointer-events: none; transition: opacity .3s;
}
#map-close .ring { width: 66px; height: 66px; border: 1.5px solid #4a3d63; }
#map-close .ring svg { width: 30px; height: 30px; fill: currentColor; stroke-width: 1.2; }   /* the play triangle (M9 7v10l8-5z) is drawn so its optical centre - between its centroid and its box - sits on the ring's centre */
#menu.has-game #map-close { opacity: 1; pointer-events: auto; }
#map-help { position: absolute; top: calc(12px + var(--safe-t)); left: 16px; z-index: 1; }
#menu:not(.show) #map-close { pointer-events: none; }
/* (#menu.show > * would otherwise show it: it's only there with a level to go back to) */
#menu:not(.has-game) #map-close { opacity: 0; pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .map-node.current .halo, .map-node.current .cube, .map-node.current .ring, .map-node.nudge .cube { animation: none; }
  .map-node.current .ring { opacity: .35; }
}

/* ---------- the map as a living world ---------- */
/* solved stones become the objects they hid */
.map-node .obj {
  width: 64px; height: 64px; position: relative; pointer-events: none;
  filter: drop-shadow(0 6px 9px rgba(40, 20, 60, .2));
  transition: transform .5s var(--ease-out);
}
.map-node:hover .obj { transform: translateY(-3px); }
/* the eclipse's edge, as the playable stones wear it: its own layer, screen-blended, so it only adds light */
.obj-box { position: relative; display: inline-block; width: 64px; height: 64px; }
.map-node .obj-rim { position: absolute; inset: 0; width: 64px; height: 64px; pointer-events: none; mix-blend-mode: screen; transition: transform .5s var(--ease-out); }
.map-node:hover .obj-rim { transform: translateY(-3px); }
.map-node.fresh .obj-rim { animation: object-rise .9s .7s cubic-bezier(.2,1.5,.4,1) both; }
.map-node.bonus .obj-box, .map-node.bonus .obj-rim { width: 56px; height: 56px; }
.map-node.fresh .cube { position: absolute; left: 50%; top: 50%; margin: -23px 0 0 -23px; animation: stone-away .55s .45s cubic-bezier(.5,0,.7,.3) both; }
.map-node.fresh .obj { animation: object-rise .9s .7s cubic-bezier(.2,1.5,.4,1) both; }
.map-node.fresh .halo { animation: fresh-glow 1.6s .6s ease-out both; }
@keyframes stone-away { to { transform: scale(.2) translateY(10px); opacity: 0; } }
@keyframes object-rise { from { transform: translateY(14px) scale(.3); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes fresh-glow { 0% { opacity: 0; transform: scale(.6); } 30% { opacity: 1; transform: scale(1.3); } 100% { opacity: .35; transform: scale(1); } }

/* mist hangs over chapters until their stones are uncovered */
.map-svg .mist { transition: fill-opacity 1s ease; }
.map-svg .mist.clearing { animation: mist-clear 2.4s .5s ease-in both; }
@keyframes mist-clear { from { fill-opacity: .32; } to { fill-opacity: 0; } }
.map-air { position: absolute; left: 0; right: 0; overflow: hidden; pointer-events: none; }
.map-air .wisp {
  position: absolute; width: 60%; height: 34%; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 255, 255, .55), rgba(255, 255, 255, 0));
  opacity: var(--o); animation: wisp-drift var(--d) ease-in-out infinite alternate;
}
.map-air.on-dark .wisp { background: radial-gradient(closest-side, rgba(170, 180, 230, .28), rgba(170, 180, 230, 0)); }
@keyframes wisp-drift { from { transform: translateX(-12%); } to { transform: translateX(22%); } }
.map-air .mote {
  position: absolute; width: 4px; height: 4px; border-radius: 50%; background: var(--glow);
  box-shadow: 0 0 8px 2px color-mix(in srgb, var(--glow) 70%, transparent);
  opacity: 0; animation: mote-twinkle var(--d) ease-in-out var(--delay) infinite;
}
@keyframes mote-twinkle { 0%, 100% { opacity: 0; transform: translateY(0); } 50% { opacity: .85; transform: translateY(-8px); } }

/* a chapter wakes: the mist burns off, a band of light crosses, motes rise */
.map-air.awaken .wisp { animation: wisp-go 2.2s .5s ease-in both; }
@keyframes wisp-go { from { opacity: var(--o); } to { opacity: 0; transform: translateX(40%) scale(1.3); } }
.map-air.awaken .mote { animation: mote-rise 2.6s calc(.8s + var(--delay) * .2) ease-out both; }
@keyframes mote-rise { 0% { opacity: 0; transform: translateY(30px) scale(.6); } 30% { opacity: 1; } 100% { opacity: 0; transform: translateY(-70px) scale(1.2); } }
.map-air .sweep {
  position: absolute; top: 0; bottom: 0; width: 40%; left: -40%;
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--glow) 75%, transparent), transparent);
  animation: sweep 1.8s .6s cubic-bezier(.4,0,.2,1) both; mix-blend-mode: screen;
}
@keyframes sweep { to { left: 100%; } }
.map-region.awaken .r-name { animation: name-wake 1.6s 1s ease both; }
@keyframes name-wake { 40% { text-shadow: 0 0 18px var(--glow, #fff); letter-spacing: .5em; } }
.trail.draw { stroke-dasharray: var(--len); stroke-dashoffset: var(--len); animation: trail-draw var(--d, 1.4s) ease-in-out var(--delay, 1.5s) forwards; }
@keyframes trail-draw { to { stroke-dashoffset: 0; } }
.trail.spur { stroke-dasharray: 0.1 6; stroke-opacity: .35; stroke-width: 1.8; }
.trail.spur.walked { stroke-dasharray: none; stroke-opacity: .3; stroke-width: 1.6; }

/* the chapter shrine: optional, off the trail, opened by stars */
.map-node .shrine-gem { display: block; position: relative; }
.map-node .shrine-gem svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
/* only a shrine waiting to be entered floats its gem (an SVG animation repaints every frame) */
.map-node.bonus.open .shrine-gem .gem { animation: gem-float 4s ease-in-out infinite; }
@keyframes gem-float { 50% { translate: 0 -2.4px; } }
.map-node.bonus.locked .cube { opacity: .45; filter: grayscale(.6); }
.map-node.bonus.open .halo { opacity: .8; animation: breathe 3.2s ease-in-out infinite; }
.map-node.bonus .n { letter-spacing: 0; }

/* the companion */
.companion {
  position: absolute; left: -19px; top: -52px; width: 38px; height: 53px; pointer-events: none; z-index: 1;
  will-change: transform;
}
.companion svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; overflow: visible; stroke: none; }
.companion.flip svg { transform: scaleX(-1); }
.companion .head { animation: comp-bob 2.8s ease-in-out infinite; }
.companion.walking .head { animation: none; }
.companion .eye { transform-box: fill-box; transform-origin: center; animation: comp-blink 5s infinite; }
@keyframes comp-bob { 50% { translate: 0 -1.5px; } }
@keyframes comp-blink { 0%, 92%, 100% { transform: scaleY(1); } 95% { transform: scaleY(.1); } }

/* map -> level */
#menu .map-scroll { transition: transform .46s var(--ease-in), opacity .46s ease-in; }
/* the map only fades once the veil is opaque: until then it hides the old level behind it */
#menu.diving .map-scroll { transform-origin: var(--dive-x) var(--dive-y); transform: scale(1.6); opacity: 0;
  transition: transform .46s var(--ease-inOut), opacity .1s linear .36s; }
/* the tapped stone answers at once */
.map-node.tapped .cube, .map-node.tapped .obj { animation: tap-pop .32s var(--ease-pop) both; }
@keyframes tap-pop { 0% { scale: .9; } 55% { scale: 1.16; } 100% { scale: 1.1; } }
#menu.diving #map-close, #menu.diving #map-help, #menu.diving #map-journal { opacity: 0; transition: opacity .2s; }
/* the level's sky opens out of the tapped stone as nested diamonds (a cube's top face):
   the glow leads, the sky follows; then it fades as the block assembles */
#veil, #veil-glow { position: fixed; inset: 0; z-index: 6; pointer-events: none; opacity: 0; transition: opacity .45s ease-out;
  clip-path: polygon(var(--vx, 50%) var(--vy, 50%), var(--vx, 50%) var(--vy, 50%), var(--vx, 50%) var(--vy, 50%), var(--vx, 50%) var(--vy, 50%)); }
#veil.open, #veil-glow.open { clip-path: polygon(var(--vx, 50%) calc(var(--vy, 50%) - 160vmax), calc(var(--vx, 50%) + 270vmax) var(--vy, 50%), var(--vx, 50%) calc(var(--vy, 50%) + 160vmax), calc(var(--vx, 50%) - 270vmax) var(--vy, 50%)); }
#veil-glow.in { opacity: 1; transition: clip-path .42s var(--ease-inOut); }
#veil.in { opacity: 1; transition: clip-path .42s var(--ease-inOut) .07s; }
/* level -> next level: a plain wash of the next sky */
#veil.washing { opacity: 1; transition: opacity .26s var(--ease-fade); }

/* level -> map: it pulls back out of the stone you were on */
#menu.arriving .map-scroll { transform-origin: var(--dive-x) var(--dive-y); transform: scale(1.35); opacity: 0; transition: none; }
#menu.settling .map-scroll { transform-origin: var(--dive-x) var(--dive-y);
  transition: transform var(--dur-scene) var(--ease-glide), opacity .28s ease-out; }
#menu.arriving #map-close, #menu.arriving #map-help, #menu.arriving #map-journal { opacity: 0; transition: none; }
#menu.settling #map-close, #menu.settling #map-help, #menu.settling #map-journal { transition: opacity .4s ease-out .2s; }
/* map -> back to the level: a slight swell as it dissolves */
#menu.leaving .map-scroll { transform: scale(1.08); opacity: 0; transition: transform .4s cubic-bezier(.4,0,.6,1), opacity .3s ease-in; }

@media (prefers-reduced-motion: reduce) {
  .companion .head, .companion .eye, .map-air .wisp, .map-air .mote, .map-node.bonus .shrine-gem .gem, .map-node.bonus.open .shrine-gem .gem { animation: none; }
  .map-air .mote { opacity: .6; }
}

/* ---------- win celebration ---------- */
#flash {
  position: fixed; inset: 0; z-index: 1; pointer-events: none; opacity: 0;
  background: radial-gradient(circle at 50% 50%, rgba(255, 252, 240, 0.95), rgba(255, 245, 225, 0.35) 38%, rgba(255, 245, 225, 0) 70%);
  mix-blend-mode: screen;
}
#flash.go { animation: win-flash 1.3s cubic-bezier(.2,.7,.3,1) both; }
@keyframes win-flash { 0% { opacity: 0; } 26% { opacity: 0.85; } 100% { opacity: 0; } }

#win-title {
  position: fixed; z-index: 2; left: 0; right: 0; top: calc(86px + var(--safe-t));
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  pointer-events: none; text-align: center; color: var(--ink);
  opacity: 0; transition: opacity .6s ease;
}
#win-title.show { opacity: 1; }
#win-title .sub {
  font-size: 11px; letter-spacing: .42em; text-transform: uppercase; opacity: 0;
}
#win-title .name {
  font-size: clamp(28px, 8.5vw, 44px); font-weight: 500; letter-spacing: .28em; text-transform: uppercase;
  padding-left: .28em; white-space: nowrap;
  text-shadow: 0 0 24px rgba(255, 250, 235, 0.9), 0 0 2px rgba(255, 250, 235, 0.6);
}
#win-title .name span { display: inline-block; opacity: 0; }
#win-title.show .sub { animation: win-sub .9s ease .1s both; }
#win-title.show .name span { animation: win-letter .9s cubic-bezier(.2,.9,.25,1.15) both; animation-delay: calc(var(--k) * 55ms + .25s); }
@keyframes win-sub { from { opacity: 0; letter-spacing: .1em; } to { opacity: .75; letter-spacing: .42em; } }
@keyframes win-letter {
  0% { opacity: 0; transform: translateY(18px) scale(.7); filter: blur(6px); }
  60% { opacity: 1; filter: blur(0); }
  100% { opacity: 1; transform: none; filter: blur(0); }
}
/* ---------- result card: stars and the rolling score ---------- */
#win .result, #win.result-mode .plain, #win.result-mode #win-replay { display: none; }
#win.result-mode .result { display: block; }
#win.result-mode #win-replay { display: inline-block; }
#win .row { gap: 8px; }
.stars { display: flex; justify-content: center; gap: 22px; margin: 2px 0 8px; }
.star { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.star svg { width: 34px; height: 34px; fill: none; stroke: var(--ink); stroke-width: 1.2; opacity: .28; transition: opacity .2s; }
.star:nth-child(2) svg { width: 40px; height: 40px; margin-top: -6px; }
.star i { font-style: normal; font-size: 9px; letter-spacing: .22em; text-transform: uppercase; color: var(--ink-soft); white-space: nowrap; }
.star.on svg { fill: var(--ink); stroke: var(--ink); opacity: 1; animation: star-pop .42s cubic-bezier(.2,1.6,.4,1) both; }
.star.on i { color: var(--ink); }
.star.on { position: relative; }
.star.on::after {
  content: ""; position: absolute; left: 50%; top: 17px; width: 70px; height: 70px; margin: -35px 0 0 -35px; border-radius: 50%;
  border: 1.5px solid var(--ink); opacity: 0; animation: star-ring .7s ease-out both; pointer-events: none;
}
@keyframes star-pop { 0% { transform: scale(0) rotate(-40deg); } 70% { transform: scale(1.18) rotate(4deg); } 100% { transform: none; } }
@keyframes star-ring { 0% { transform: scale(.3); opacity: .5; } 100% { transform: scale(1.3); opacity: 0; } }
#win .score { font-size: 34px; font-weight: 500; letter-spacing: .08em; margin: 4px 0 2px; font-variant-numeric: tabular-nums; }
.score.tick { animation: score-tick .12s ease-out; }
@keyframes score-tick { 50% { transform: scale(1.05); } }
.lines { list-style: none; padding: 0; margin: 0 auto 6px; width: min(240px, 100%); }
.lines li {
  display: flex; justify-content: space-between; font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--ink-soft); padding: 3px 0; opacity: 0; transform: translateY(6px); transition: opacity .35s, transform .35s;
}
.lines li.in { opacity: 1; transform: none; }
.lines li b { font-weight: 500; color: var(--ink); letter-spacing: .08em; font-variant-numeric: tabular-nums; }
.best {
  display: inline-block; margin: 2px 0 10px; padding: 3px 10px; border: 1px solid var(--ink); border-radius: 999px;
  font-size: 10px; letter-spacing: .3em; text-transform: uppercase; opacity: 0; transform: scale(1.6);
}
.best.in { animation: best-stamp .38s cubic-bezier(.3,1.5,.5,1) both; }
@keyframes best-stamp { from { opacity: 0; transform: scale(1.6) rotate(-6deg); } to { opacity: 1; transform: rotate(-3deg); } }
#win.result-mode .row button { opacity: 0; transition: opacity .4s; }
#win.result-mode.done .row button { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  #flash.go { animation-duration: .01s; }
  #win-title.show .sub, #win-title.show .name span { animation: none; opacity: 1; }
}

/* after a solve the tools step aside for the result card */
.hud.bottom, .hud.top { transition: opacity .5s ease; }
body.solved .hud.bottom, body.solved .hud.top { opacity: 0; }
body.solved .hud.bottom *, body.solved .hud.top * { pointer-events: none !important; }
/* with the header gone, the title takes its place at the top */
body.solved #win-title { top: calc(54px + var(--safe-t)); }

/* sound toggles in How to play */
.toggles { display: flex; gap: 8px; justify-content: center; margin-top: 16px; }
.toggle { opacity: .45; }
.toggle::before { content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 8px; border-radius: 50%; border: 1px solid currentColor; vertical-align: 1px; }
.toggle.on { opacity: 1; }
.toggle.on::before { background: currentColor; }

/* after a solve: three quiet words, no panel; the result lives in the scene */
#actions {
  position: fixed; left: 0; right: 0; bottom: calc(26px + var(--safe-b)); z-index: 3;
  display: flex; justify-content: center; align-items: center; gap: 6px;
  opacity: 0; transform: translateY(8px); pointer-events: none;
  transition: opacity .6s ease, transform .6s var(--ease-out);
}
#actions.show { opacity: 1; transform: none; pointer-events: auto; }
#actions button {
  background: none; border: 0; box-shadow: none; color: var(--ink); padding: 12px 16px;
  font-size: 12px; letter-spacing: .3em; text-transform: uppercase; opacity: .7;
}
#actions button.primary { opacity: 1; border: 1px solid currentColor; border-radius: 999px; padding: 11px 22px; background: none; color: var(--ink); }

/* ---------- chapter title card ---------- */
#chapter-card {
  position: fixed; inset: 0; z-index: 4; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; padding: 24px; text-align: center; color: var(--ink);
  background: radial-gradient(ellipse at 50% 48%, color-mix(in srgb, var(--sky) 94%, transparent) 0%, color-mix(in srgb, var(--sky) 78%, transparent) 50%, color-mix(in srgb, var(--sky) 30%, transparent) 100%);
  backdrop-filter: blur(5px); -webkit-backdrop-filter: blur(5px);
  opacity: 0; pointer-events: none;
}
#chapter-card.show { animation: chapter-card 2.8s ease both; pointer-events: auto; }
#chapter-card .numeral { font-size: 13px; letter-spacing: .5em; padding-left: .5em; }
#chapter-card .cname { margin: 0; font-size: clamp(22px, 6.4vw, 38px); font-weight: 500; letter-spacing: .3em; padding-left: .3em; text-transform: uppercase; white-space: nowrap; }
#chapter-card .cline { margin: 4px 0 0; font-size: 14px; letter-spacing: .06em; max-width: 300px; line-height: 1.5; }
#chapter-card .numeral, #chapter-card .cname, #chapter-card .cline { opacity: 0; }
#chapter-card.show .numeral { animation: card-rise .9s ease .15s both; }
#chapter-card.show .cname { animation: card-rise 1s ease .35s both; }
#chapter-card.show .cline { animation: card-rise 1s ease .8s both; }
@keyframes chapter-card { 0% { opacity: 0; } 14% { opacity: 1; } 76% { opacity: 1; } 100% { opacity: 0; } }
@keyframes card-rise { from { opacity: 0; transform: translateY(8px); filter: blur(3px); } to { opacity: 1; transform: none; filter: none; } }
@media (prefers-reduced-motion: reduce) {
  #chapter-card.show .numeral, #chapter-card.show .cname, #chapter-card.show .cline { animation: none; opacity: 1; }
}

/* longer names (Paper Lantern, Crescent Moon) step down so they stay on one line */
#win-title .name.long { font-size: clamp(20px, 6vw, 34px); letter-spacing: .2em; padding-left: .2em; }

/* ---------- story line under the solved object's name ---------- */
#win-title .story {
  max-width: min(320px, calc(100% - 48px)); margin-top: 6px; font-size: 13px; line-height: 1.45; letter-spacing: .03em;
  opacity: 0; text-shadow: 0 0 18px rgba(255, 250, 235, 0.8);
}
#win-title.show .story { animation: win-story 1.2s ease both; animation-delay: var(--d, 1.2s); }
@keyframes win-story { from { opacity: 0; transform: translateY(6px); } to { opacity: .85; transform: none; } }
@media (prefers-reduced-motion: reduce) { #win-title.show .story { animation: none; opacity: .85; } }

/* ---------- journal ---------- */
#map-journal { position: absolute; top: calc(12px + var(--safe-t)); right: 16px; z-index: 1; }
#journal { display: block; padding: 0; }
.jr-scroll { position: absolute; inset: 0; overflow-y: auto; padding: 0 0 calc(30px + var(--safe-b)); scrollbar-width: none; }
.jr-scroll::-webkit-scrollbar { display: none; }
/* opaque: the journal is its own place, not a veil over the map */
#journal { background: #f7dccb; }
.jr-head { text-align: center; padding: calc(64px + var(--safe-t)) 20px 18px; background: linear-gradient(180deg, #f7dccb, #f3d7d0); }
.jr-head h2 { margin: 0; font-size: 22px; font-weight: 500; letter-spacing: .4em; padding-left: .4em; text-transform: uppercase; }
#journal-count { margin: 10px 0 0; display: flex; justify-content: center; align-items: center; gap: 14px; }
.jr-total { display: inline-flex; align-items: center; gap: 5px; letter-spacing: .14em; }
.jr-total svg { width: 9px; height: 12px; }
.jr-total .l, .jr-gems .on .l { fill: #fff2c2; }
.jr-total .r, .jr-gems .on .r { fill: #e9b949; }
#journal-close { position: absolute; top: calc(12px + var(--safe-t)); right: 14px; z-index: 2; }
#journal-grid { width: 100%; }
/* each chapter is a band of its own sky, as on the map */
.jr-chapter { color: var(--ink); background: linear-gradient(180deg, var(--sky-top), var(--sky-bottom)); padding: 26px 18px 30px; }
.jr-chapter header { width: min(560px, 100%); margin: 0 auto 18px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.jr-numeral { font-size: 11px; letter-spacing: .3em; opacity: .7; }
.jr-chapter h3 { margin: 0; font-size: 17px; font-weight: 500; letter-spacing: .34em; padding-left: .34em; text-transform: uppercase; }
.jr-progress { font-size: 10px; letter-spacing: .26em; text-transform: uppercase; opacity: .75; }
.jr-bar { display: block; width: 120px; height: 2px; border-radius: 2px; background: color-mix(in srgb, var(--ink) 18%, transparent); overflow: hidden; }
.jr-bar i { display: block; height: 100%; background: #e9b949; border-radius: 2px; }
.jr-chapter.complete .jr-progress { opacity: 1; color: #e9b949; text-shadow: 0 0 12px rgba(255, 220, 140, .8); }
.jr-chapter.complete .jr-bar i { box-shadow: 0 0 10px #ffd77a; }
.jr-tiles { width: min(560px, 100%); margin: 0 auto; display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 16px 8px; }
.jr-tile {
  display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 0; border: 0; background: none;
  color: inherit; font: inherit; cursor: pointer; transition: transform .25s cubic-bezier(.2,.9,.3,1.3);
}
.jr-tile:active { transform: scale(.94); }
/* found objects sit in a little pool of the chapter's light */
.jr-pic { width: 88px; height: 88px; display: grid; place-items: center; border-radius: 50%; }
.jr-tile.found .jr-pic { background: radial-gradient(circle at 50% 58%, color-mix(in srgb, var(--glow) 85%, transparent) 0%, transparent 68%); }
.jr-tile img { width: 80px; height: 80px; object-fit: contain; filter: drop-shadow(0 6px 8px rgba(40, 20, 60, .14)); }
.jr-pic > img { grid-area: 1 / 1; }
.jr-tile img.obj-rim { filter: none; mix-blend-mode: screen; pointer-events: none; }   /* only light: no shadow under it */
.jr-tile .nm { font-size: 9.5px; letter-spacing: .2em; text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.jr-tile:not(.found) { cursor: default; }
.jr-tile:not(.found) .nm { opacity: .45; letter-spacing: .14em; text-transform: none; font-style: italic; }
.jr-shadow { width: 64px; height: 64px; border-radius: 50%;
  /* a gaussian falloff: dark in the middle, no edge at all */
  background: radial-gradient(closest-side, rgba(20, 16, 40, .2) 0%, rgba(20, 16, 40, .15) 30%, rgba(20, 16, 40, .07) 60%, rgba(20, 16, 40, .02) 85%, transparent 100%); }
.jr-chapter.dark .jr-shadow { background: radial-gradient(closest-side, rgba(0, 0, 8, .42) 0%, rgba(0, 0, 8, .3) 30%, rgba(0, 0, 8, .14) 60%, rgba(0, 0, 8, .04) 85%, transparent 100%); }
.jr-tile.bonus .jr-pic { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 35%, transparent); }
.jr-tile.bonus.found .jr-pic { box-shadow: inset 0 0 0 1.5px #e9b949, 0 0 18px rgba(255, 215, 122, .45); }
.jr-gems { display: inline-flex; gap: 4px; }
.jr-gems i { display: block; width: 8px; height: 11px; }
.jr-gems svg { width: 100%; height: 100%; display: block; }
/* no icon stroke on gems: filled ones are pure gold, empty ones a single outline */
.jr-gems svg, .jr-total svg { stroke: none; }
.jr-gems .o, .jr-total .o { fill: none; stroke: none; }
.jr-gems i:not(.on) .l, .jr-gems i:not(.on) .r { display: none; }
.jr-gems i:not(.on) .o { stroke: currentColor; stroke-width: 1; opacity: .45; }
#journal-view {
  position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column; align-items: center;
  background: linear-gradient(180deg, var(--sky-top, var(--sky)), var(--sky-bottom, var(--sky)));
  opacity: 0; pointer-events: none; transition: opacity .45s ease;
}
#journal-view.show { opacity: 1; pointer-events: auto; }
#journal-view canvas { flex: 1; width: 100%; min-height: 0; touch-action: none; cursor: grab; }
#journal-view .jv-text { text-align: center; padding: 0 28px calc(40px + var(--safe-b)); }
#journal-view .jv-name { margin: 2px 0 8px; font-size: 26px; font-weight: 500; letter-spacing: .3em; padding-left: .3em; text-transform: uppercase; }
#journal-view .jv-story { margin: 0 auto 10px; max-width: 320px; font-size: 15px; line-height: 1.5; }
#journal-view .jv-hint { opacity: .55; }
#journal-back { position: absolute; top: calc(12px + var(--safe-t)); left: 14px; }

/* the build stamps this; it tells which version a phone is running */
.version { cursor: pointer; margin: 14px 0 0; text-align: center; font-size: 10px; letter-spacing: .3em; text-transform: uppercase; color: var(--ink-soft); opacity: .7; }
.legal { margin: 6px 0 0; text-align: center; font-size: 10px; letter-spacing: .3em; text-transform: uppercase; opacity: .7; }
.legal a { color: var(--ink-soft); text-decoration: none; }

/* ---------- add to home screen ---------- */
#install {
  position: fixed; z-index: 7; left: 50%; bottom: calc(18px + var(--safe-b));
  width: min(420px, calc(100% - 24px)); transform: translate(-50%, 24px);
  display: grid; grid-template-columns: 40px 1fr; gap: 6px 14px; align-items: center;
  padding: 16px 18px 14px; border-radius: 22px; color: var(--ink);
  background: var(--panel-strong); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 14px 40px rgba(40, 20, 60, 0.16);
  opacity: 0; pointer-events: none; transition: opacity .5s ease, transform .6s var(--ease-out);
}
#install.show { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
/* on iPhone Safari the share button sits in the bar below: point at it */
#install.ios::after {
  content: ""; position: absolute; left: 50%; bottom: -8px; width: 16px; height: 16px; margin-left: -8px;
  background: var(--panel-strong); transform: rotate(45deg); border-radius: 3px;
}
.install-cube { width: 36px; height: 36px; stroke: none; }
.install-cube path:nth-child(1) { fill: #fcf0de; }
.install-cube path:nth-child(2) { fill: #f1c4a6; }
.install-cube path:nth-child(3) { fill: #a98cb6; }
.install-text p { margin: 0; }
.install-title { font-size: 14px; letter-spacing: .06em; }
.install-why { margin-top: 3px !important; font-size: 10px; letter-spacing: .24em; text-transform: uppercase; color: var(--ink-soft); }
.install-how { margin-top: 8px !important; font-size: 13px; line-height: 1.5; }
.glyph-share svg { width: 17px; height: 17px; vertical-align: -3px; margin: 0 2px; }
.install-actions { grid-column: 1 / -1; display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }
/* one set of steps for the browser in hand; Install only when the browser offers it */
#install .install-how, #install-go { display: none; }
#install.ios .install-how.ios, #install.android .install-how.android, #install.samsung .install-how.samsung { display: block; }
#install.can-install #install-go { display: inline-block; }
#install.can-install .install-how { display: none !important; }
#install.android::after, #install.samsung::after { display: none; }
.glyph-menu { display: inline-block; min-width: 14px; text-align: center; font-weight: 700; font-size: 15px; line-height: 1; vertical-align: -1px; margin: 0 2px; }
/* the same steps in How to play, only in a browser tab */
.home-tip { margin-top: 16px; padding: 12px 14px; border-radius: 14px; background: var(--panel); font-size: 13.5px; }
.home-tip p { margin: 0; }
.home-tip p + p { margin-top: 8px; line-height: 1.6; }
.home-tip .glyph-share svg { width: 15px; height: 15px; }
body.standalone .home-tip { display: none; }

/* ---------- hidden developer panel (hold the version line) ---------- */
#dev h2 { margin-bottom: 14px; }
.dev-list { display: flex; flex-direction: column; gap: 6px; }
.dev-row {
  display: flex; justify-content: space-between; align-items: center; width: 100%;
  padding: 13px 16px; border-radius: 14px; border: 0; text-decoration: none;
  background: var(--panel); color: var(--ink); font: inherit; font-size: 14px; letter-spacing: .04em; text-align: left;
}
.dev-row span { color: var(--ink-soft); font-size: 12px; letter-spacing: .2em; text-transform: uppercase; }
.dev-row.danger { color: #c4485a; }
#dev .primary { display: block; margin: 18px auto 0; }
/* the install card steps aside while a panel is open (it would cover the version line) */
body:has(#title.show, #help.show, #dev.show, #journal.show, #win.show) #install, body.solved #install { opacity: 0; pointer-events: none; }

#journal-view .jv-gems .jr-gems { gap: 7px; margin: 0 0 12px; }
#journal-view .jv-gems .jr-gems i { width: 12px; height: 16px; }

/* ---------- motion (tokens and helpers in js/motion.js; rules in docs/motion.md) ---------- */
/* scroll reveal: in from a little below, a touch small, settling with a soft pop */
.rv { opacity: 0; translate: 0 16px; scale: .9;
  transition: opacity var(--dur-slow) var(--ease-out), translate var(--dur-slow) var(--ease-out), scale var(--dur-slow) var(--ease-pop); }
.rv.rv-in { opacity: 1; translate: 0 0; scale: 1; }
/* the motion log (developer panel): named steps with their times, readable on a phone */
#motion-log { position: fixed; left: 8px; bottom: calc(8px + var(--safe-b, 0px)); z-index: 50; margin: 0; padding: 6px 8px;
  list-style: none; pointer-events: none; background: rgba(20, 16, 40, .72); color: #e9e6ff; border-radius: 6px;
  font: 10px/1.45 ui-monospace, Menlo, monospace; max-width: 70vw; }
#motion-log li:first-child { color: #ffe08a; }

/* ---------- title: the first screen of a launch (literal curves: it shows before motion.js loads) ---------- */
#title { position: fixed; inset: 0; z-index: 7; display: flex; flex-direction: column; align-items: center;
  padding: calc(17vh + var(--safe-t)) 20px calc(9vh + var(--safe-b)); color: #eef0ff; text-shadow: 0 0 22px rgba(150, 170, 255, .3); cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none;
  opacity: 0; pointer-events: none; -webkit-tap-highlight-color: transparent;
  transition: opacity .42s cubic-bezier(.55,0,.75,.2), translate .42s cubic-bezier(.55,0,.75,.2); }
#title.show { opacity: 1; pointer-events: auto; }
#title.leaving { opacity: 0; translate: 0 -28px; pointer-events: none; }
#title h1 { animation: title-in 1.2s cubic-bezier(.2,.8,.2,1) .05s both; }
#title .sub { margin: 14px 0 0; animation: title-fade 1s ease-out .45s both; }
#title .tap { margin-top: auto; display: flex; flex-direction: column; align-items: center; gap: 6px;
  font-size: 10px; letter-spacing: .42em; padding-left: .42em; text-transform: uppercase;
  animation: title-fade .8s ease-out 1s both, title-breathe 2.6s ease-in-out 1.8s infinite; }
#title .tap svg { width: 18px; height: 18px; margin-left: -.42em; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round;
  animation: title-nudge 1.6s ease-in-out 1.8s infinite; }
#title .tap.nudge svg { animation: title-nudge .45s ease-in-out 2; }
#title:not(.show) .tap, #title:not(.show) .tap svg { animation: none; }   /* not ticking under the map */
@keyframes title-nudge { 50% { translate: 0 -6px; } }
@keyframes title-in { from { opacity: 0; letter-spacing: .9em; padding-left: .9em; } }
@keyframes title-fade { from { opacity: 0; } }
@keyframes title-breathe { 50% { opacity: .45; } }
#menu.pulling #map-help, #menu.pulling #map-journal, #menu.pulling #map-close { opacity: 0; transition: none; }
/* while the map comes up from the title, its sky has no edge: the backdrop reaches
   well above the sheet and fades in over that reach, so the title's sky melts into it */
/* the sheet's own top edge fades too; main.js slides the fade off the top as the map arrives */
#menu.pulling .map-scroll { -webkit-mask-image: linear-gradient(180deg, transparent 0, rgba(0,0,0,.2) 12vh, rgba(0,0,0,.6) 30vh, #000 50vh);
  mask-image: linear-gradient(180deg, transparent 0, rgba(0,0,0,.2) 12vh, rgba(0,0,0,.6) 30vh, #000 50vh);
  -webkit-mask-size: 100% calc(100% + 50vh); mask-size: 100% calc(100% + 50vh);
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; }
#menu.pulling .map-backdrop { top: -85vh;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, rgba(0,0,0,.18) 25vh, rgba(0,0,0,.5) 50vh, rgba(0,0,0,.82) 70vh, #000 85vh);
  mask-image: linear-gradient(180deg, transparent 0, rgba(0,0,0,.18) 25vh, rgba(0,0,0,.5) 50vh, rgba(0,0,0,.82) 70vh, #000 85vh); }
/* First light (js/firstlight/scene.js): the title is a wall at night with one
   glowing stone; its light writes the name in stars, so the lettered name is
   for screen readers only, and "swipe up" waits until the name is written */
#firstlight { position: absolute; inset: 0; width: 100%; height: 100%; display: block; pointer-events: none; z-index: -1; }
/* the night before the stone opens: black over the sky, behind the scene (First light fades it) */
#fl-night { position: absolute; inset: -40vh 0 0; background: #000; pointer-events: none; z-index: -2; }
#title.fl h1, #title.fl .sub { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
#title.fl .tap { opacity: 0; transition: opacity 1.2s ease; }
#title.fl.named .tap { opacity: 1; }
#title.fl:not(.named) .tap, #title.fl:not(.named) .tap svg { animation: none; }
/* the fingertip: where to touch, only after a long while of nothing */
#fl-hint { position: absolute; width: 54px; height: 54px; margin: -27px 0 0 -27px; border-radius: 50%; pointer-events: none;
  border: 1.5px solid rgba(255, 226, 180, .55); opacity: 0; transition: opacity 1.2s ease; }
#fl-hint.show { opacity: 1; animation: fl-touch 2.8s ease-in-out infinite; }
@keyframes fl-touch { 0% { transform: scale(1.35); opacity: 0; } 35% { transform: scale(.82); opacity: .85; } 55% { transform: scale(.78); opacity: .85; } 100% { transform: scale(1.5); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { #fl-hint.show { animation: none; } }
/* behind the title the block is only a backdrop */
body.title-up .hud { opacity: 0; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  #title h1, #title .sub, #title .tap, #title .tap svg { animation: none; }
}

/* ---------- the map over a sea of cloud (map.js, world.js; docs/map-study.md) ---------- */
/* the world is opaque, so the level's own UI steps out while the map is up
   (the old veil used to cover it) */
/* body classes set each frame by main.js frame(): a body:has(#menu.show) here
   re-styled the whole document on every frame of the title pan (5 fps at CPU x4) */
body.menu-open :is(.hud, #actions, #win-title, #win, #coach) { opacity: 0 !important; pointer-events: none !important; }
body.menu-open :is(.hud, #actions, #coach) * { pointer-events: none !important; }
/* names sit on the cloud: a soft halo of their own sky keeps them readable */
.map-region { text-shadow: 0 0 14px rgba(255, 250, 244, .75); }
.map-region.on-dark { text-shadow: 0 0 14px rgba(10, 12, 30, .55); }
.map-region .r-num { font-size: 10px; letter-spacing: .4em; opacity: .7; }
.map-region.at-right .r-num { margin-right: -.4em; }
.map-region.at-centre { left: 50%; transform: translate(-50%, -50%); align-items: center; text-align: center; }
.map-region.veiled .r-name { opacity: .85; }
.map-region.waking .r-name { animation: name-wake 1.8s ease both; }
.map-node { transition: transform .35s cubic-bezier(.2,.9,.3,1.4), opacity .9s var(--ease-fade); }
.map-node .label { text-shadow: 0 0 10px rgba(255, 250, 244, .85); }
.map-node.on-dark .label { text-shadow: 0 0 10px rgba(10, 12, 30, .6); }
/* each stone rests on a soft patch of light on the cloud */
.map-node::before { content: ""; position: absolute; left: 50%; top: 64%; width: 58px; height: 18px; margin-left: -29px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(closest-side, rgba(255, 255, 255, .5), rgba(255, 255, 255, 0)); }
.map-node.on-dark::before { background: radial-gradient(closest-side, rgba(190, 210, 255, .2), rgba(190, 210, 255, 0)); }
/* the next stone: one gold ring that breathes; nothing else about it moves */
.map-node.current .ring { border-color: #e9b949; }
.map-node.current .halo { animation: none; opacity: .6; }
.map-node.current .cube { animation: none; }
.stars-mini i.on svg { fill: #e9b949; stroke: #e9b949; }
/* a chapter whose cloud is parting: its stones appear as it clears */
.map-node.veiled-in { opacity: 0; pointer-events: none; }

/* shrines: a gem on a slim spire, with its own light. Open (its stars earned):
   a warm gold halo and a column of light, the only thing that breathes besides
   the next stone. Locked: pale. Solved: calm and cool. */
.map-node.bonus { width: 84px; height: 84px; margin: -42px 0 0 -42px; }
.map-node.bonus::before { display: none; }
.map-node.bonus .halo { inset: -30px; opacity: 1;
  background: radial-gradient(closest-side, rgba(255, 226, 150, .78), rgba(255, 215, 122, .3) 45%, rgba(255, 215, 122, 0)); animation: breathe 3.2s ease-in-out infinite; }
.map-node.bonus::after { content: ""; position: absolute; left: 50%; bottom: 52%; width: 46px; height: 220px; margin-left: -23px; pointer-events: none; z-index: -1;
  background: radial-gradient(ellipse 50% 100% at 50% 100%, rgba(255, 214, 120, .6), rgba(255, 214, 120, 0) 72%); }
.map-node.bonus.locked .halo { background: radial-gradient(closest-side, rgba(255, 255, 255, .5), rgba(255, 255, 255, 0)); animation: none; }
.map-node.bonus.locked::after { height: 150px; background: radial-gradient(ellipse 50% 100% at 50% 100%, rgba(255, 255, 255, .38), rgba(255, 255, 255, 0) 72%); }
.map-node.bonus.solved .halo { background: radial-gradient(closest-side, rgba(205, 225, 255, .55), rgba(205, 225, 255, 0)); animation: none; }
.map-node.bonus.solved::after { height: 120px; background: radial-gradient(ellipse 50% 100% at 50% 100%, rgba(215, 232, 255, .4), rgba(215, 232, 255, 0) 72%); }
.map-node.bonus .n { color: #e9b949; opacity: 1; font-size: 12px; }
.map-node.bonus.open .nm { font-weight: 600; letter-spacing: .3em; }
.map-node.bonus.open .mt { color: #a8741a; opacity: 1; }
.map-node.bonus.on-dark.open .mt { color: #ffe7a1; }
.map-node.bonus .cube { filter: drop-shadow(0 4px 8px rgba(120, 80, 20, .25)); }
.map-node.bonus.locked .cube { opacity: .7; filter: none; }
/* an open shrine's two svgs cast their shadows each: cast by their box, the
   shadow was redrawn on the main thread every frame the gem floated */
.map-node.bonus.open .shrine-gem { filter: none; }
.map-node.bonus.open .shrine-gem svg { filter: drop-shadow(0 4px 8px rgba(120, 80, 20, .25)); }
.map-node.bonus .obj { width: 56px; height: 56px; }
.map-node.bonus.far .label { opacity: .75; }

/* the companion carries a small gold light */
.companion { top: -54px; height: 57px; }
.companion .lamp { animation: lamp 3.6s ease-in-out infinite; }
.companion.walking .lamp { animation: none; }
@keyframes lamp { 50% { translate: 0 -2.4px; } }

/* a shrine's card: the chapter card, in gold */
#chapter-card.shrine { background: radial-gradient(ellipse at 50% 48%, color-mix(in srgb, #fff2d2 92%, transparent) 0%, color-mix(in srgb, var(--sky) 72%, transparent) 55%, color-mix(in srgb, var(--sky) 28%, transparent) 100%); }
#chapter-card.shrine .numeral { color: #a8741a; font-size: 12px; font-weight: 600; text-transform: uppercase; }
#chapter-card.shrine .cname { color: #3e3020; font-size: clamp(20px, 6vw, 34px); }
#chapter-card.shrine .cline { color: #5a4630; }
/* held longer than a chapter's card, and sharp sooner: it reads before the block comes */
#chapter-card.shrine.show { animation-duration: 3.4s; }
#chapter-card.shrine.show .numeral { animation: card-rise .6s ease .1s both; }
#chapter-card.shrine.show .cname { animation: card-rise .6s ease .25s both; }
#chapter-card.shrine.show .cline { animation: card-rise .6s ease .55s both; }

@media (prefers-reduced-motion: reduce) {
  .map-node.bonus .halo, .map-node.bonus.open .halo, .companion .lamp, .trail.draw { animation: none; }
  .trail.draw { stroke-dashoffset: 0; }
  .map-node, .trail { transition: none; }
}

/* ---------- ads, a slip taken back, Remove Ads (docs/ads-study.md; styleframes in proto/ads.html) ---------- */
/* a slip taken back: in the top-right HUD slot, only while there is a slip; it arrives softly */
#rewind { position: relative; }
#rewind[hidden] { display: none; }
#rewind .gem { fill: #e9b24e; stroke: #c98d2e; stroke-width: 1; }
#rewind.arrive { animation: rewind-arrive .5s var(--ease-out) both; }
@keyframes rewind-arrive { 0% { transform: scale(.6); opacity: 0; } 100% { transform: none; opacity: 1; } }
#rewind.glow { box-shadow: 0 6px 24px rgba(40, 20, 60, 0.08), 0 0 22px 4px rgba(255, 236, 170, .7); }
@media (prefers-reduced-motion: reduce) { #rewind.arrive { animation: none; } }

/* a small card that offers a gift: a slip taken back, a shrine short of stars */
#offer { position: fixed; z-index: 8; left: 50%; bottom: calc(96px + var(--safe-b)); width: min(330px, calc(100% - 40px));
  transform: translate(-50%, 10px); opacity: 0; pointer-events: none;
  transition: opacity var(--dur-base) var(--ease-in), transform var(--dur-base) var(--ease-in); }
#offer.show { opacity: 1; transform: translate(-50%, 0); pointer-events: auto;
  transition: opacity var(--dur-slow) var(--ease-fade), transform var(--dur-slow) var(--ease-out); }
#offer.on-map { --ink: #4a3d63; --ink-soft: rgba(74, 61, 99, .62); --line: rgba(74, 61, 99, .16); --sky: #f7dccb; --panel-strong: rgba(255, 250, 243, .9); color: var(--ink); }
.offer-card { padding: 16px 20px 14px; border-radius: 22px; text-align: center;
  background: var(--panel-strong); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 14px 40px rgba(40, 20, 60, 0.14); }
.offer-card p { margin: 0; font-size: 14px; line-height: 1.5; letter-spacing: .02em; }
.offer-card .small { margin-top: 4px; font-size: 10px; letter-spacing: .24em; text-transform: uppercase; color: var(--ink-soft); }
.offer-card .small:empty { display: none; }
.offer-card .row { margin-top: 12px; }
.offer-card .row button { font-size: 11px; padding: 10px 16px; }
.offer-card .row button.primary { font-size: 11px; padding: 10px 18px; }
.offer-card .row button[hidden] { display: none; }

/* the menu button in a level stills the world (docs/pause-study.md). No card:
   the stone stays where it is, behind a veil of its own sky that is thickest at
   the centre, where the words are. Where you are, a ring to resume, and Restart
   and Map beneath it, all on one centred axis. A tap anywhere else resumes. */
#pause { position: fixed; inset: 0; z-index: 8; pointer-events: none; opacity: 0;
  display: grid; place-items: center; padding: 24px 24px calc(24px + var(--safe-b));
  background:
    radial-gradient(ellipse 120% 70% at 50% 50%, color-mix(in srgb, var(--sky, #f7dccb) 74%, transparent) 0%,
      color-mix(in srgb, var(--sky, #f7dccb) 46%, transparent) 55%, color-mix(in srgb, var(--sky, #f7dccb) 26%, transparent) 100%);
  backdrop-filter: blur(3.5px); -webkit-backdrop-filter: blur(3.5px);
  transition: opacity .35s var(--ease-in, ease-in); }
#pause.show { opacity: 1; pointer-events: auto; transition: opacity .6s var(--ease-fade, ease-out); }
body:has(#pause.show) :is(.hud, #coach) { opacity: 0; pointer-events: none; }
body:has(#pause.show) :is(.hud, #coach) * { pointer-events: none !important; }
.pause-card { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 0; color: var(--ink); }
.pause-where { margin: 0 0 34px; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.pause-chapter { font-size: 11px; letter-spacing: .42em; padding-left: .42em; text-transform: uppercase; color: var(--ink-soft); }
.pause-name { font-size: clamp(24px, 7vw, 34px); font-weight: 500; letter-spacing: .3em; padding-left: .3em; text-transform: uppercase; }
.pause-name:empty, .pause-chapter:empty { display: none; }
/* a thin rule with a diamond, the axes' crystal, between the place and the choices */
.pause-where::after { content: ""; width: 7px; height: 7px; margin-top: 12px; transform: rotate(45deg);
  border: 1px solid var(--ink-soft); }
.pause-resume { width: 84px; height: 84px; border-radius: 50%; display: grid; place-items: center;
  border: 1.5px solid var(--ink); color: var(--ink); background: color-mix(in srgb, var(--sky, #f7dccb) 40%, transparent);
  transition: transform .25s cubic-bezier(.2,.9,.3,1.4), background .3s; }
.pause-resume svg { width: 34px; height: 34px; margin-left: 4px; fill: currentColor; stroke-width: 1.2; }
.pause-row { display: flex; justify-content: center; gap: 14px; margin-top: 30px; }
.pause-row button { display: flex; flex-direction: column; align-items: center; gap: 10px; width: 92px; padding: 4px 0;
  color: var(--ink); }
.pause-row svg { width: 52px; height: 52px; padding: 14px; border-radius: 50%; border: 1px solid var(--line);
  transition: background .3s, color .3s, border-color .3s, transform .25s cubic-bezier(.2,.9,.3,1.4); }
.lesson-list { list-style: none; margin: 6px 0 18px; padding: 0; columns: 2; column-gap: 18px; }
.lesson-list li { break-inside: avoid; }
.lessons-panel { text-align: center; }
.lessons-panel .primary { display: block; margin: 0 auto; }
.lesson-list button { display: flex; gap: 10px; align-items: baseline; width: 100%; padding: 9px 2px; text-align: left; color: var(--ink); border-bottom: 1px solid var(--line); }
.lesson-list .n { font-size: 10px; letter-spacing: .2em; color: var(--ink-soft); }
.lesson-list .nm { font-size: 13px; letter-spacing: .14em; text-transform: uppercase; }
.pause-label { font-size: 11px; letter-spacing: .24em; padding-left: .24em; text-transform: uppercase; color: var(--ink-soft); white-space: nowrap; transition: color .3s; }
.pause-resume:active, .pause-row button:active svg { transform: scale(.92); }
/* "Start over?" asks in the same quiet voice: the ring fills, nothing turns red */
.pause-row button.confirm svg { background: var(--ink); color: var(--sky); border-color: var(--ink); }
.pause-row button.confirm .pause-label { color: var(--ink); }
.pause-card button[hidden] { display: none; }
/* it settles in from a breath below, one line after another, as the chapter card does */
.pause-card > * { opacity: 0; transform: translateY(8px); transition: opacity .25s ease-in, transform .25s ease-in; }
#pause.show .pause-card > * { opacity: 1; transform: none; transition: opacity .7s ease, transform .9s cubic-bezier(.2,.8,.2,1); }
#pause.show .pause-card > :nth-child(2) { transition-delay: .08s; }
#pause.show .pause-card > :nth-child(3) { transition-delay: .16s; }
@media (prefers-reduced-motion: reduce) { .pause-card > *, #pause.show .pause-card > * { transform: none; transition: opacity .2s; } }

/* Remove Ads, under the sound toggles in How to play */
.support { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); text-align: center; }
.support p { margin: 0 0 12px; font-size: 14px; line-height: 1.5; }
.support .row { margin-top: 0; }
.support .perk { margin: 10px 0 0; font-size: 10px; letter-spacing: .2em; text-transform: uppercase; color: var(--ink-soft); line-height: 1.6; }
.support .restore { display: block; margin: 10px auto 0; font-size: 10px; letter-spacing: .3em; text-transform: uppercase; color: var(--ink-soft); padding: 4px 8px; }
.support-thanks { display: none; }
.support.owned .support-offer { display: none; }
.support.owned .support-thanks { display: block; }
.support.owned .support-thanks p:first-child { margin-bottom: 0; }

/* the breath before an interstitial: the stone's own sky, and plain words */
#breath { position: fixed; inset: 0; z-index: 55; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  text-align: center; opacity: 0; transition: opacity .45s var(--ease-fade); pointer-events: auto; }
#breath.in { opacity: 1; }
#breath .pause { margin: 0; font-size: 14px; line-height: 1.7; letter-spacing: .3em; padding-left: .3em; text-transform: uppercase; color: var(--ink-soft); }
#breath .dots { display: flex; gap: 6px; justify-content: center; margin-top: 10px; }
#breath .dots i { width: 5px; height: 5px; transform: rotate(45deg); background: var(--ink-soft); opacity: .3; animation: breath-dot 1.2s ease-in-out infinite; }
#breath .dots i:nth-child(2) { animation-delay: .2s; }
#breath .dots i:nth-child(3) { animation-delay: .4s; }
@keyframes breath-dot { 0%, 100% { opacity: .3; } 40% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { #breath { transition: none; } #breath .dots i { animation: none; } }

/* the web prototype's placeholder ad (ads-web.js): plainly not the game */
.sim-ad { position: fixed; inset: 0; z-index: 60; background: #17161c; color: #e9e6f2;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  font-family: system-ui, sans-serif; text-align: center; padding: 24px; opacity: 0; transition: opacity .25s ease; }
.sim-ad.in { opacity: 1; }
.sim-ad.leaving { opacity: 0; }
.sim-label { font-size: 12px; letter-spacing: .3em; text-transform: uppercase; padding: 6px 12px; border: 1px dashed #8a85a0; border-radius: 6px; color: #c9c4dc; font-family: system-ui, sans-serif; }
.sim-ad .sim-what { font-size: 13px; color: #8f8aa6; max-width: 270px; line-height: 1.5; margin: 0; }
.sim-ad .sim-slot { width: min(300px, 80vw); aspect-ratio: 1; border-radius: 14px; display: grid; place-items: center;
  background: repeating-linear-gradient(45deg, #201f27 0 12px, #1c1b22 12px 24px); color: #5d5874; font-size: 12px; letter-spacing: .2em; text-transform: uppercase; }
.sim-timer { position: absolute; top: calc(18px + var(--safe-t)); right: 18px; width: 34px; height: 34px; display: grid; place-items: center; font-size: 13px; color: #c9c4dc; }
.sim-timer[hidden] { display: none; }
.sim-timer svg { position: absolute; inset: 0; width: 34px; height: 34px; transform: rotate(-90deg); stroke: #6e6985; stroke-width: 1.5; }
.sim-timer b { font-weight: 400; }
.sim-close { position: absolute; top: calc(12px + var(--safe-t)); right: 12px; width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center;
  color: #e9e6f2; background: rgba(255, 255, 255, .08); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .25); }
.sim-close[hidden] { display: none; }
.sim-early { position: absolute; bottom: calc(28px + var(--safe-b)); left: 50%; transform: translateX(-50%); font-size: 11px; letter-spacing: .24em;
  text-transform: uppercase; color: #8f8aa6; padding: 10px 14px; white-space: nowrap; }
.sim-buy { position: fixed; inset: 0; z-index: 61; display: grid; place-items: center; padding: 20px;
  background: rgba(30, 26, 40, .28); opacity: 0; transition: opacity .25s ease;
  --ink: #4a3d63; --ink-soft: rgba(74, 61, 99, .62); --line: rgba(74, 61, 99, .16); --sky: #f7dccb; --panel-strong: rgba(255, 250, 243, .96); color: var(--ink); }
.sim-buy.in { opacity: 1; }
.sim-buy .offer-card { width: min(330px, 100%); }
.sim-buy .sim-label { display: inline-block; margin-bottom: 12px; color: var(--ink-soft); border-color: var(--line); font-size: 10px; }

/* the store app (js/native.js): no purchases in version 1, no web install prompt */
.native-app #support, .native-app #install { display: none !important; }
