/* The journey map — «نقشهٔ مسیر».
 *
 * Shared by two pages: the game (public/game/journey.js paints it into #stage)
 * and the panel (public/panel/panel.js paints the same board into its home
 * section, where clicking a station opens the game at that scene). It is its
 * own file for that reason: the panel must not load the whole game stylesheet
 * to draw one screen, and the game must not pay for the panel's.
 *
 * It only reads the tokens both pages define (--ink, --ink-2, --ink-3,
 * --surface, --surface-2, --line, --orange, --orange-deep, --orange-ink,
 * --green, --green-ink, --radius) and reads each with a fallback, because the
 * panel's login.css defines fewer of them than game.css does. */

/* ---------------------------------------------------------------- *
 * نقشهٔ مسیر — the whole arc on one screen, drawn as a map
 *
 * The «Masirino Home» board from the design canvas: aged parchment, a
 * winding trail from the harbour at the bottom to the summit at the top, one
 * brass medallion per scene, a compass on its own slow clock, and a column of
 * the four numbers the player already cares about beside it.
 *
 * Three states are drawn as three different *objects*, not three shades of
 * the same one: a sealed station is a brass coin with a green seal, the
 * current one is the only coin with a breathing halo and the one live action
 * on the screen, and a locked one is a desaturated coin with a lock that is
 * not a control at all.
 *
 * The board is 430 units wide (the design's phone width) and one row per
 * scene tall; every coordinate below is a percentage of that width or a pixel
 * of that height, set inline by journey.js. Container-query units size the
 * coins and labels so a 290px board on a small phone and a 480px board on a
 * desktop both fit their labels without overflow.
 *
 * Every animation here — needle, halo, trail, waves, sparkles — is inside
 * prefers-reduced-motion. Nothing means anything only while it moves.
 * ---------------------------------------------------------------- */

.scene-journey { max-width: 74rem; }

.journey-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  max-width: 30rem;
  margin: 0 auto 1.1rem;
}
.journey-head .lede { margin-bottom: 0; }
.journey-hello { margin: 0 0 .1rem; color: var(--ink-3, #6a5e57); font-size: .82rem; font-weight: 600; }
.journey-head-tools { display: flex; flex: 0 0 auto; align-items: center; gap: .55rem; margin-top: .25rem; }
.journey-pill {
  padding: .45rem .95rem;
  border-radius: 99px;
  border: 1.5px solid rgba(120, 84, 24, .45);
  background: linear-gradient(160deg, #f0d68d, #c79437);
  color: #4a3410;
  font-size: .78rem;
  font-weight: 800;
  white-space: nowrap;
  box-shadow: 0 6px 12px rgba(90, 60, 15, .2);
}
.jsound {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  padding: 0;
  border-radius: 50%;
  border: 2px solid rgba(150, 106, 32, .7);
  background: linear-gradient(160deg, #f4e6c0, #e0c890);
  color: #175e64;
  box-shadow: 0 6px 14px rgba(60, 40, 10, .25), inset 0 2px 3px rgba(255, 252, 238, .9);
}
.jsound:hover { filter: none; transform: translateY(-1px); }
.jsound[aria-pressed="true"] .jsound-off, .jsound[aria-pressed="false"] .jsound-on { display: none; }

/* One column, on both surfaces. The board used to share the row with a column
   of cards; those live in the summary sheet now, so the map is centred instead
   of hugging one edge of an empty track. */
.journey-layout {
  display: grid;
  gap: clamp(1.2rem, 4vw, 2.4rem);
  grid-template-columns: minmax(0, 30rem);
  justify-content: center;
  align-items: start;
}

/* ── the board ─────────────────────────────────────────────────── */

.journey-board {
  --coin: clamp(4.2rem, 26cqw, 6rem);
  --label: min(42cqw, 12rem);
  position: relative;
  width: 100%;
  max-width: 30rem;
  height: var(--board-h, 1200px);
  margin: 0 auto;
  border-radius: 22px;
  /* clip-path, not overflow: an overflow box would become the scroll root for
     the sticky atmosphere below, and it would stop sticking to the viewport. */
  clip-path: inset(0 round 22px);
  container-type: inline-size;
  background: radial-gradient(130% 55% at 50% 6%, #f0ddb0 0%, #e7d09e 45%, #ddc289 100%);
  box-shadow: 0 1rem 2.6rem rgba(48, 33, 25, .18), inset 0 0 0 1px rgba(165, 133, 79, .45);
  isolation: isolate;
}

/* The map itself, behind everything: the reference still, and the loop over it
   once it is actually playing. Sticky and viewport-tall, with a negative bottom
   margin so it takes no room in the board's height: the parchment holds still
   while the trail and the medallions scroll across it. */
.journey-atmos {
  --art: none;
  position: sticky;
  top: 0;
  z-index: 1;
  height: 100vh;
  height: 100dvh;
  margin-bottom: -100vh;
  margin-bottom: -100dvh;
  pointer-events: none;
}
.journey-atmos-still, .journey-atmos-loop {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
.journey-atmos-loop { opacity: 0; transition: opacity 1.2s ease; }
.has-atmos .journey-atmos-loop { opacity: 1; }
/* The reference map is the parchment; the drawn seas and trees would double
   it, so they appear only when the still could not load. The frame, vignette
   and grain always stay: they are what makes it read as one sheet. */
.jterrain-decor { display: none; }
.no-art .jterrain-decor { display: block; }

.journey-terrain, .journey-trail {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.journey-terrain { z-index: 2; }
.journey-trail { z-index: 3; }

.jtrail-bed { fill: none; stroke: rgba(246, 236, 206, .38); stroke-width: 11; stroke-linecap: round; }
.jtrail-dots { fill: none; stroke: #7a5a33; stroke-width: 5; stroke-linecap: round; stroke-dasharray: .5 16; opacity: .88; }
.jtrail-walked {
  fill: none;
  stroke: var(--orange-deep, #d7570e);
  stroke-width: 5;
  stroke-linecap: round;
  stroke-dasharray: 9 13;
  opacity: .92;
  animation: jtrail-flow 1.8s linear infinite;
}
@keyframes jtrail-flow { to { stroke-dashoffset: -22; } }
.jwave { animation: jwave 6s ease-in-out infinite; }
@keyframes jwave { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(6px); } }
.jsparks { transform-origin: 200px 150px; animation: jspark 3.2s ease-in-out infinite; }
@keyframes jspark { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }

/* ── the compass ───────────────────────────────────────────────── */

/* The reference compass, cut out by its own alpha (a transparent WebP still;
   the loops carry alpha in VP9 and HEVC). It is a compass rose in the sense a
   chart has one: modest, in the corner the summit leaves free, sitting *in*
   the paper — a soft pressed well under it — rather than floating over it.
   journey.js picks the side; the summit medallion takes the other. */
.jcompass {
  position: absolute;
  top: 34px;
  z-index: 4;
  width: 40%;
  aspect-ratio: 1;
  pointer-events: none;
  isolation: isolate;
  filter: drop-shadow(5px 10px 10px rgba(58, 38, 8, .24));
}
.jcompass--left { left: 6%; }
.jcompass--right { right: 6%; }
.jcompass::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -9%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 55%, rgba(84, 56, 14, .22), rgba(84, 56, 14, .08) 58%, rgba(84, 56, 14, 0) 72%);
}
.jcompass::after {
  /* A hairline of gold around the well, the way an engraved rose is framed. */
  content: "";
  position: absolute;
  inset: -3%;
  border-radius: 50%;
  border: 1px solid rgba(165, 133, 79, .45);
}
.jcompass-body {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
/* The needle: pivoted on the dial's centre (--px/--py, measured on the body
   render), aimed at the current medallion by journey.js (--aim), and swaying a
   few degrees around that aim — a needle settling, never a needle spinning. */
.jcompass {
  --px: 50.1%;
  --py: 51.2%;
  --aim: 0deg;
}
.jcompass-needle {
  position: absolute;
  left: calc(var(--px) - 34%);
  top: calc(var(--py) - 34%);
  width: 68%;
  height: 68%;
  object-fit: contain;
  transform-origin: 50% 50%;
  transform: rotate(var(--aim));
  animation: jneedle 9s ease-in-out infinite;
  filter: drop-shadow(1px 2px 2px rgba(20, 12, 4, .45));
}
@keyframes jneedle {
  0%   { transform: rotate(calc(var(--aim) - 4deg)); }
  38%  { transform: rotate(calc(var(--aim) + 5deg)); }
  64%  { transform: rotate(calc(var(--aim) - 1.5deg)); }
  82%  { transform: rotate(calc(var(--aim) + 2deg)); }
  100% { transform: rotate(calc(var(--aim) - 4deg)); }
}

/* ── stations ──────────────────────────────────────────────────── */

.journey-spine { position: absolute; inset: 0; z-index: 5; margin: 0; padding: 0; list-style: none; }

/* Each station is a zero-size anchor at its centre; the card hangs off it to
   whichever side the trail leaves free. */
.station { --x: 50%; --y: 0px; position: absolute; top: var(--y); left: var(--x); width: 0; height: 0; }

.station-card {
  position: absolute;
  top: calc(var(--coin) / -2);
  display: flex;
  align-items: center;
  gap: .5rem;
  width: max-content;
  max-width: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: #38290f;
  font: inherit;
  text-align: start;
  border-radius: 22px;
  transition: transform .18s;
}
/* The spine is RTL, so `row` puts the first child (the coin) on the right. */
.station[data-side="start"] .station-card { left: calc(var(--coin) / -2); flex-direction: row-reverse; }
.station[data-side="end"] .station-card { right: calc(var(--coin) / -2); flex-direction: row; }
button.station-card:hover { filter: none; transform: translateY(-2px); }
button.station-card:focus-visible { outline: 3px solid var(--orange, #ed6d1c); outline-offset: 4px; }
.station[data-state="locked"] .station-card { cursor: default; }

.jcoin {
  position: relative;
  flex: 0 0 auto;
  width: var(--coin);
  height: var(--coin);
  display: block;
}
.jcoin > * { position: absolute; }
.jcoin-pin {
  left: 50%; bottom: -9%;
  width: 27%; aspect-ratio: 1;
  transform: translateX(-50%) rotate(45deg);
  border-radius: 18%;
  background: linear-gradient(135deg, #d8ab52, #9a6f26);
  box-shadow: 0 8px 12px rgba(70, 45, 10, .3);
}
.jcoin-rim {
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(from 230deg, #9c7124, #ecd287 15%, #b98a2c 32%, #8a5f1c 50%, #e3c06a 68%, #c79437 84%, #9c7124);
  box-shadow: 0 16px 26px rgba(74, 49, 12, .35), inset 0 3px 6px rgba(255, 246, 214, .8), inset 0 -5px 10px rgba(90, 58, 12, .55);
}
.jcoin-face {
  inset: 8.6%;
  border-radius: 50%;
  background: radial-gradient(circle at 38% 30%, #f2e3ba, #dcc48c 60%, #c4a468);
  box-shadow: inset 0 -4px 9px rgba(255, 250, 225, .65), inset 0 5px 10px rgba(112, 78, 26, .35);
}
/* The medallion plate — brass rim, parchment face and the pin below — is the
   Higgsfield render, keyed off its green ground. It sits over the CSS rim and
   face, which stay underneath as the fallback if the picture never arrives.
   In the 512px image the disc spans x 40–470 and y 19–449, so the image is
   scaled until that disc is exactly the coin and offset by the margins. */
.jcoin-plate {
  left: -7.8%;
  top: -3.7%;
  width: 119.1%;
  height: 119.1%;
  max-width: none;
  object-fit: contain;
  filter: drop-shadow(0 10px 14px rgba(74, 49, 12, .3));
  transition: filter .3s ease;
}
.jcoin:has(.jcoin-plate) .jcoin-pin { display: none; }
.jcoin-glyph { inset: 22%; width: 56%; height: 56%; }
/* The rendered icon sits where the glyph sits; the glyph shows only when the
   picture failed (journey.js marks the coin `no-icon`). */
.jcoin-icon { inset: 17%; width: 66%; height: 66%; object-fit: contain; filter: drop-shadow(0 3px 3px rgba(74, 49, 12, .28)); }
.jcoin:has(.jcoin-icon:not([hidden])) .jcoin-glyph { display: none; }
.jcoin.no-icon .jcoin-glyph { display: block; }
.jcoin.no-icon .jcoin-icon { display: none; }
.station[data-state="locked"] .jcoin-icon,
.station[data-state="uncharted"] .jcoin-icon { filter: saturate(.4) brightness(.98) drop-shadow(0 3px 3px rgba(74, 49, 12, .2)); }
.jcoin-mark {
  top: -4%; left: -2%;
  min-width: 1.45rem; height: 1.45rem;
  padding-inline: .3rem;
  display: grid; place-items: center;
  border-radius: 99px;
  background: linear-gradient(160deg, #f3d98b, #d9a83f);
  border: 2px solid #f6ecd2;
  color: #4a3410;
  font-size: .72rem; font-weight: 800; line-height: 1;
  box-shadow: 0 4px 8px rgba(70, 45, 10, .3);
}
.station[data-state="done"] .jcoin-mark { display: none; }
.jseal {
  bottom: -5%; left: 50%;
  width: 1.65rem; height: 1.65rem;
  transform: translateX(-50%);
  display: grid; place-items: center;
  border-radius: 50%;
  border: 2px solid #f6ecd2;
}
.jseal--done { background: linear-gradient(160deg, #3fae62, #1f7a41); box-shadow: 0 4px 8px rgba(30, 80, 45, .4); }
.jseal--lock { background: linear-gradient(160deg, #8b8272, #6d6558); box-shadow: 0 4px 8px rgba(60, 50, 30, .35); }
.station[data-state="locked"] .jcoin-rim,
.station[data-state="locked"] .jcoin-face,
.station[data-state="locked"] .jcoin-glyph,
.station[data-state="locked"] .jcoin-pin { filter: saturate(.5) contrast(.96) brightness(.97); }
.station[data-state="locked"] .jcoin-plate { filter: saturate(.45) contrast(.96) brightness(.96) drop-shadow(0 8px 12px rgba(74, 49, 12, .22)); }
.station[data-state="here"] .jcoin-plate { filter: drop-shadow(0 14px 18px rgba(74, 49, 12, .36)); }
.station[data-state="here"] .jcoin { transform: scale(1.08); }
.station[data-state="here"] .jcoin-rim { box-shadow: 0 18px 30px rgba(74, 49, 12, .42), inset 0 3px 6px rgba(255, 246, 214, .8), inset 0 -5px 10px rgba(90, 58, 12, .55); }
.jhalo {
  inset: -14%;
  border-radius: 50%;
  border: 3px solid rgba(237, 109, 28, .6);
  animation: jhalo 2.6s ease-in-out infinite;
}
@keyframes jhalo { 0%, 100% { transform: scale(1); opacity: .9; } 50% { transform: scale(1.09); opacity: .35; } }

/* Medallion states as motion, each restrained enough to sit under a thumb:
   idle = the shadow breathes; current = a gold edge and a small lift;
   done = one soft confirmation glow on arrival, then still;
   locked = nothing moves, because nothing there can be done yet. */
.station[data-state="open"] .jcoin-plate,
.station[data-state="done"] .jcoin-plate { animation: jcoin-idle 5.5s ease-in-out infinite; }
@keyframes jcoin-idle {
  0%, 100% { filter: drop-shadow(0 10px 14px rgba(74, 49, 12, .3)); }
  50% { filter: drop-shadow(0 14px 18px rgba(74, 49, 12, .22)); }
}
.station[data-state="here"] .jcoin { animation: jcoin-lift 3.2s ease-in-out infinite; }
@keyframes jcoin-lift { 0%, 100% { transform: scale(1.08) translateY(0); } 50% { transform: scale(1.08) translateY(-3px); } }
.station[data-state="here"] .jcoin-rim::after {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  border: 2px solid rgba(240, 214, 141, .9);
  box-shadow: 0 0 0 1px rgba(154, 111, 38, .5), 0 0 14px rgba(240, 214, 141, .55);
}
.station[data-state="done"] .jseal--done { animation: jseal-glow 1.6s ease-out 1 backwards; }
@keyframes jseal-glow {
  0% { box-shadow: 0 4px 8px rgba(30, 80, 45, .4), 0 0 0 0 rgba(63, 174, 98, .55); }
  100% { box-shadow: 0 4px 8px rgba(30, 80, 45, .4), 0 0 0 14px rgba(63, 174, 98, 0); }
}

/* The counters: glass beads in a brass ring, in the reference's two colours.
   They scale in once when they appear and then hold still — a badge that keeps
   bouncing is a nag, and this product does not nag. */
.jcount {
  position: absolute;
  top: calc(var(--coin) * -.08);
  z-index: 2;
  display: grid;
  place-items: center;
  min-width: 1.7rem;
  height: 1.7rem;
  padding-inline: .35rem;
  border-radius: 99px;
  border: 2px solid #d9a83f;
  box-shadow: 0 0 0 1px rgba(120, 84, 24, .55), 0 4px 8px rgba(40, 30, 10, .35), inset 0 2px 3px rgba(255, 255, 255, .55), inset 0 -3px 5px rgba(0, 0, 0, .25);
  color: #fdf6e4;
  font-size: .78rem;
  font-weight: 800;
  line-height: 1;
  text-shadow: 0 1px 1px rgba(0, 0, 0, .35);
  animation: jcount-in .5s cubic-bezier(.22, 1, .36, 1) backwards, jcount-pulse 1.6s ease-in-out .5s 1;
}
.jcount--community { background: radial-gradient(circle at 35% 30%, #5fd487, #1f9a4b 55%, #146b34); }
.jcount--alert { background: radial-gradient(circle at 35% 30%, #ff8a7a, #e2453a 55%, #a92f28); }
/* Community on the trail side of the coin, alerts on the label side, so the
   two never stack on a narrow board. */
.station[data-side="start"] .jcount--community { left: calc(var(--coin) * -.6); }
.station[data-side="start"] .jcount--alert { left: calc(var(--coin) * .42); }
.station[data-side="end"] .jcount--community { right: calc(var(--coin) * -.6); }
.station[data-side="end"] .jcount--alert { right: calc(var(--coin) * .42); }
@keyframes jcount-in { from { transform: scale(.4); opacity: 0; } }
@keyframes jcount-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.12); } }

.jlabel {
  display: block;
  width: var(--label);
  padding: .6rem .75rem;
  border-radius: 16px;
  /* The same paper as the map, lifted a shade: a Higgsfield tile of the
     parchment under a light wash, so a label reads as a slip of the sheet
     rather than a UI card laid on top of it. The flat colour is the fallback. */
  background:
    linear-gradient(rgba(255, 250, 238, .62), rgba(255, 250, 238, .62)),
    url("/media/journey-board/paper-tile-v1.webp") center / 256px repeat,
    rgba(253, 247, 231, .94);
  border: 1.5px solid rgba(163, 127, 58, .55);
  box-shadow: 0 10px 20px rgba(84, 56, 14, .2);
  color: #38290f;
  font-weight: 450;
}
.station[data-state="here"] .jlabel {
  border-color: rgba(184, 138, 44, .85);
  background:
    linear-gradient(rgba(255, 252, 244, .72), rgba(255, 252, 244, .72)),
    url("/media/journey-board/paper-tile-v1.webp") center / 256px repeat,
    rgba(253, 247, 231, .97);
  box-shadow: 0 12px 24px rgba(84, 56, 14, .26);
}
.station[data-state="locked"] .jlabel { opacity: .92; }

.station-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .4rem;
}
.station-top em { font-style: normal; color: #7a6338; font-size: .66rem; font-weight: 800; letter-spacing: .03em; }
.station-badge {
  flex: 0 0 auto;
  padding: .12rem .5rem;
  border-radius: 99px;
  background: rgba(120, 108, 88, .22);
  color: #5f5644;
  font-size: .62rem;
  font-weight: 800;
  white-space: nowrap;
}
.station[data-state="done"] .station-badge { background: linear-gradient(160deg, #3fae62, #1f7a41); color: #fff; }
.station[data-state="here"] .station-badge { background: linear-gradient(160deg, #f3d98b, #d9a83f); color: #6b4207; }
.jlabel strong { display: block; margin-top: .2rem; font-size: .92rem; font-weight: 800; line-height: 1.55; }
.station-why { display: block; margin-top: .2rem; color: #6d5832; font-size: .72rem; line-height: 1.75; text-wrap: pretty; }
.station-go {
  display: inline-block;
  margin-top: .55rem;
  padding: .42rem 1rem;
  border-radius: 99px;
  background: var(--orange, #ed6d1c);
  color: #211c19;
  font-size: .76rem;
  font-weight: 800;
}

/* ── the side column ───────────────────────────────────────────── */

.journey-icon {
  display: block;
  flex: 0 0 auto;
  width: 10.5rem;
  height: auto;
  max-width: 34%;
}
.journey-card--figure { position: relative; padding-top: 1rem; }
.journey-card--figure .journey-icon {
  width: 6rem;
  max-width: 40%;
  margin: -.4rem 0 .2rem auto;
}

.journey-side { display: grid; gap: 1rem; align-content: start; }

.journey-card {
  padding: 1.1rem 1.2rem;
  background: var(--surface, #fff);
  border: 1px solid var(--line, rgba(61, 47, 40, .14));
  border-top: 3px solid var(--orange, #ed6d1c);
  border-radius: var(--radius, 16px);
}
.journey-card--crew { border-top-color: var(--green, #31805c); }
.journey-card-title { margin: 0 0 .4rem; color: var(--ink-3, #6a5e57); font-size: .74rem; font-weight: 700; }
.journey-big { margin: 0 0 .5rem; font-size: 1.6rem; font-weight: 850; letter-spacing: -.02em; line-height: 1.4; }
.journey-big .muted { font-size: .86rem; font-weight: 600; }
.journey-note { margin: .6rem 0 0; color: var(--ink-3, #6a5e57); font-size: .78rem; line-height: 1.85; }
.journey-card button { margin-top: .8rem; padding: .55rem 1rem; font-size: .78rem; }

.journey-bar { height: 8px; border-radius: 99px; background: var(--surface-2, #f7f1ea); overflow: hidden; }
.journey-bar::after {
  content: "";
  display: block;
  height: 100%;
  width: var(--progress, 0%);
  background: linear-gradient(90deg, var(--orange-deep, #d7570e), var(--orange, #ed6d1c));
  transition: width .5s cubic-bezier(.22, 1, .36, 1);
}

.journey-code {
  margin: .2rem 0 .4rem;
  font-size: clamp(1.5rem, 6vw, 2rem);
  font-weight: 900;
  letter-spacing: .22em;
  color: var(--orange-ink, #8f3a04);
}

.journey-crew { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.journey-crew li { display: flex; align-items: center; gap: .5rem; font-size: .88rem; }
.journey-crew .avatar { width: 2.45rem; height: 2.45rem; }
.journey-crew small { margin-inline-start: auto; color: var(--ink-3, #6a5e57); font-size: .72rem; }

@media (max-width: 52rem) {
  /* minmax(0, 1fr), not 1fr: a bare 1fr track has an `auto` minimum, which on a
   * 390px phone made the track 480px and pushed the board off the left edge. */
  .journey-layout { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 30rem) {
  .journey-head { flex-direction: column; }
  .journey-head-tools { margin-top: 0; }
  .jlabel { padding: .5rem .6rem; }
  .jlabel strong { font-size: .86rem; }
  .station-why { font-size: .68rem; }
}

/* ─── stage rows (docs/JOURNEY_MAP.md) ───────────────────────────────────── *
 * A stage medallion is the same coin, a size up, with a ribbon label. Locked
 * and uncharted stages are not buttons; a completed one unfolds its scenes.
 * Uncharted rows are fog: the map stops here, and nothing on them promises. */
.station--stage { --coin: clamp(5rem, 31cqw, 7rem); }
.station--stage .jlabel { border-width: 2px; }
.station--stage .jlabel strong { font-size: 1.02rem; }
.station--stage[data-state="here"] .jlabel { border-color: rgba(193, 79, 12, .8); }
.station--stage[data-state="here"] .station-badge { background: linear-gradient(160deg, #f6b26b, #ed6d1c); color: #4a2306; }
.station-tally { display: block; margin-top: .35rem; color: #5b4a2a; font-size: .72rem; font-weight: 800; }
.station-remaining {
  margin: .35rem 0 0;
  padding: 0 0 0 .2rem;
  list-style: none;
  color: #6d5832;
  font-size: .72rem;
  line-height: 1.75;
}
.station-remaining li { position: relative; padding-inline-start: 1rem; }
.station-remaining li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: .55em;
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  border: 1.5px solid #b98a2c;
}
.station[data-state="locked"] .station-remaining li::before { border-style: dashed; }
.jseal--fog { background: linear-gradient(160deg, #b5ad9e, #8f887a); box-shadow: 0 4px 8px rgba(60, 50, 30, .3); }
.station[data-state="uncharted"] .station-card { cursor: default; }
.station[data-state="uncharted"] .jcoin-rim,
.station[data-state="uncharted"] .jcoin-face,
.station[data-state="uncharted"] .jcoin-glyph,
.station[data-state="uncharted"] .jcoin-pin { filter: saturate(.15) contrast(.85) brightness(1.05); opacity: .8; }
.station[data-state="uncharted"] .jcoin-mark { display: none; }
.station[data-state="uncharted"] .jlabel { border-style: dashed; opacity: .82; background: rgba(250, 246, 236, .9); }
.station[data-state="uncharted"] .station-badge { background: #d9d3c5; color: #4f473b; }
.station-card[data-stage-toggle] .station-go { background: none; color: #7a6338; border: 1.5px solid rgba(122, 99, 56, .45); box-shadow: none; }

@media (prefers-reduced-motion: reduce) {
  .jtrail-walked, .jwave, .jsparks, .jhalo, .jcoin, .jcoin-rim, .jcoin-plate, .jseal--done, .jcount, .jcompass-needle { animation: none; }
  .jhalo { opacity: .7; }
  .station[data-state="here"] .jcoin { transform: scale(1.08); }
  /* journey.js never attaches a loop under reduced motion; this is the belt to
     that brace, for a preference that changes while the map is open. */
  .journey-atmos-loop { display: none; }
}


/* ── the panel's home ─────────────────────────────────────────── */

/* On the panel the board is the whole page: no side column, a one-line head,
   and labels that carry only the title and a bead with what is waiting. The
   medallion's seal says the state; the accessible name says it in words. */
.scene-journey--panel .journey-layout { grid-template-columns: minmax(0, 30rem); justify-content: center; }
.scene-journey--panel .journey-head {
  max-width: 30rem;
  margin: 0 auto .7rem;
  align-items: center;
}
.scene-journey--panel .journey-head h2 { margin: 0; font-size: 1.05rem; }
.scene-journey--panel .journey-head-tools { margin-top: 0; }
.scene-journey--panel .scene-actions { display: flex; justify-content: center; margin-top: 1rem; }

.jlabel--compact {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  width: max-content;
  max-width: var(--label);
  padding: .5rem .8rem;
  border-radius: 999px;
}
.jlabel--compact strong { margin: 0; font-size: .9rem; line-height: 1.4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.jcount--inline {
  position: static;
  flex: 0 0 auto;
  min-width: 1.5rem;
  height: 1.5rem;
  font-size: .72rem;
}
.station[data-state="uncharted"] .jlabel--compact { opacity: .78; }

/* The atlas, inside the cities stage: a small brass chip under its label. */
.jatlas {
  position: absolute;
  top: calc(var(--coin) / 2 + .35rem);
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  min-height: 2rem;
  padding: .25rem .7rem;
  border-radius: 999px;
  border: 1px solid rgba(154, 111, 38, .55);
  background: linear-gradient(160deg, #f3d98b, #d9a83f);
  color: #4a3410;
  font-size: .74rem;
  font-weight: 800;
  text-decoration: none;
  box-shadow: 0 4px 10px rgba(70, 45, 10, .25);
  white-space: nowrap;
}
.station[data-side="start"] .jatlas { left: calc(var(--coin) / 2 + .5rem); }
.station[data-side="end"] .jatlas { right: calc(var(--coin) / 2 + .5rem); }
.jatlas:hover, .jatlas:focus-visible { background: linear-gradient(160deg, #f7e2a4, #e2b453); outline: 2px solid var(--orange, #ed6d1c); outline-offset: 2px; }

/* ── behind a stage: the sheet ────────────────────────────────── */

/* The «بیشتر» chip on a game stage row, one step past the label; on the panel
   the whole compact card is the door and this chip is not drawn. */
.jmore {
  position: absolute;
  top: calc(var(--coin) / 2 + 3rem);
  left: 0;
  transform: translateX(-50%);
  min-height: 2.75rem;
  padding: .25rem .75rem;
  border-radius: 999px;
  border: 1px solid rgba(154, 111, 38, .55);
  background: rgba(253, 247, 231, .92);
  color: #4a3410;
  font: inherit;
  font-size: .74rem;
  font-weight: 800;
  cursor: pointer;
  box-shadow: 0 4px 10px rgba(70, 45, 10, .2);
  white-space: nowrap;
}
.jmore:hover, .jmore:focus-visible { background: linear-gradient(160deg, #f3d98b, #d9a83f); outline: 2px solid var(--orange, #ed6d1c); outline-offset: 2px; }

.jstage {
  width: min(30rem, calc(100vw - 1.5rem));
  max-height: calc(100dvh - 2rem);
  margin: auto;
  padding: 0;
  border: 1px solid rgba(154, 111, 38, .5);
  border-radius: 1.4rem;
  overflow: hidden;
  background:
    linear-gradient(rgba(255, 250, 238, .6), rgba(255, 250, 238, .6)),
    url("/media/journey-board/paper-tile-v1.webp") center / 256px repeat,
    #f3e6cf;
  color: #38290f;
  box-shadow: 0 1.6rem 4rem rgba(48, 33, 25, .32), inset 0 1px 0 rgba(255, 255, 255, .8);
  animation: jstage-in .28s cubic-bezier(.2, .9, .2, 1) both;
  display: flex;
  flex-direction: column;
}
.jstage[open] { display: flex; }
.jstage::backdrop { background: rgba(28, 18, 8, .55); backdrop-filter: blur(3px); }
@keyframes jstage-in { from { opacity: 0; transform: translateY(14px) scale(.985); } }
.jstage-hero {
  position: relative;
  flex: none;
  aspect-ratio: 16 / 10;
  background: linear-gradient(160deg, #e6cf9c, #d9c08a);
}
.jstage-hero > img { display: block; width: 100%; height: 100%; object-fit: cover; }
.jstage.no-art .jstage-hero { aspect-ratio: auto; height: 5.5rem; }
.jstage.no-art .jstage-hero > img { display: none; }
.jstage-hero::after {
  content: "";
  position: absolute; inset: auto 0 0 0; height: 40%;
  background: linear-gradient(rgba(243, 230, 207, 0), rgba(243, 230, 207, .95));
}
.jcoin--sheet {
  --coin: 4.6rem;
  position: absolute;
  z-index: 2;
  right: 1.1rem;
  bottom: -1.4rem;
  width: var(--coin);
  height: var(--coin);
  display: block;
}
.jcoin--sheet .jcoin-icon { inset: 17%; width: 66%; height: 66%; }
.jstage-close {
  position: absolute; z-index: 2; top: .7rem; left: .7rem;
  width: 2.5rem; height: 2.5rem;
  border-radius: 50%;
  border: 1px solid rgba(154, 111, 38, .5);
  background: rgba(253, 247, 231, .92);
  color: #4a3410; font: inherit; font-size: 1rem; font-weight: 800; cursor: pointer;
  box-shadow: 0 4px 10px rgba(70, 45, 10, .25);
}
.jstage-close:focus-visible { outline: 2px solid var(--orange, #ed6d1c); outline-offset: 2px; }
.jstage-body { padding: 1.4rem 1.2rem 1.2rem; overflow: auto; min-height: 0; }
.jstage-phase { display: flex; align-items: center; gap: .5rem; margin: 0 0 .3rem; }
.jstage-phase em { font-style: normal; color: #7a6338; font-size: .7rem; font-weight: 800; letter-spacing: .03em; }
.jstage h2 { margin: 0 0 .4rem; font-size: 1.3rem; line-height: 1.5; }
.jstage-why { margin: 0 0 .8rem; color: #6d5832; font-size: .86rem; line-height: 1.9; }
.jstage-tally { margin: 0 0 .3rem; color: #5b4a2a; font-size: .78rem; font-weight: 800; }
.jstage .station-remaining { margin-bottom: .8rem; }
.jstage-scenes { list-style: none; margin: .4rem 0 1rem; padding: 0; display: grid; gap: .35rem; }
.jstage-scene {
  display: grid;
  grid-template-columns: 1.7rem minmax(0, 1fr) auto;
  align-items: center;
  gap: .55rem;
  width: 100%;
  min-height: 2.6rem;
  padding: .4rem .6rem;
  border: 1px solid rgba(154, 111, 38, .35);
  border-radius: .8rem;
  background: rgba(255, 252, 244, .7);
  color: #38290f;
  font: inherit;
  text-align: start;
}
button.jstage-scene { cursor: pointer; }
button.jstage-scene:hover, button.jstage-scene:focus-visible { border-color: rgba(237, 109, 28, .6); outline: none; box-shadow: 0 0 0 3px rgba(237, 109, 28, .15); }
.jstage-scene b {
  display: grid; place-items: center;
  width: 1.7rem; height: 1.7rem;
  border-radius: 50%;
  background: linear-gradient(160deg, #f3d98b, #d9a83f);
  color: #4a3410; font-size: .72rem; font-weight: 800;
}
.jstage-scenes li[data-state="done"] .jstage-scene b { background: linear-gradient(160deg, #3fae62, #1f7a41); color: #fff; }
.jstage-scenes li[data-state="locked"] .jstage-scene { opacity: .6; }
.jstage-scene span { font-size: .88rem; font-weight: 700; }
.jstage-scene small { color: #7b6357; font-size: .66rem; font-weight: 700; white-space: nowrap; }
.jstage-actions { margin: .2rem 0 1rem; }
.jstage-primary {
  width: 100%;
  min-height: 3rem;
  border: 1px solid rgba(154, 111, 38, .55);
  border-radius: 999px;
  background: linear-gradient(160deg, #f3d98b, #d9a83f);
  color: #4a3410;
  font: inherit; font-size: .92rem; font-weight: 800; cursor: pointer;
  box-shadow: inset 0 1px 0 #fff8e0, 0 .5rem 1.2rem rgba(70, 45, 10, .25);
}
.jstage-primary:focus-visible { outline: 3px solid var(--orange, #ed6d1c); outline-offset: 3px; }
/* ── the stage hub ──────────────────────────────────────────────────────
   One paper sheet per stage, and the only place a stage's own surfaces live.
   Sections are named blocks rather than one long run, because the hub answers
   four separate questions — what is this, what is left, what are the steps,
   what else is in here — and a phone reading them as one column answers none. */
.jstage--hub { width: min(32rem, calc(100vw - 1.5rem)); }
.jstage-block { margin: 0 0 1.1rem; }
.jstage-block:last-child { margin-bottom: .2rem; }
.jstage-block-title {
  margin: 0 0 .45rem;
  color: #9a6f26;
  font-size: .68rem;
  font-weight: 800;
  letter-spacing: .04em;
}
.jstage-block .station-remaining, .jstage-block .jstage-scenes { margin-bottom: 0; }
/* The two honest one-liners: what the map cannot chart, and what is waiting
   inside. Both are absent unless they are true. */
.jstage-fog {
  margin: 0 0 .8rem;
  padding: .6rem .8rem;
  border-radius: .8rem;
  background: rgba(122, 99, 56, .1);
  color: #6d5832;
  font-size: .8rem;
}
.jstage-alert {
  margin: 0 0 .8rem;
  padding: .6rem .8rem;
  border: 1px solid rgba(226, 69, 58, .35);
  border-radius: .8rem;
  background: rgba(255, 240, 236, .9);
  color: #9b2f26;
  font-size: .82rem;
  font-weight: 700;
}
.jstage-doors { display: grid; gap: .45rem; }
.jstage-doors-title { margin: 0 0 .1rem; color: #9a6f26; font-size: .68rem; font-weight: 800; letter-spacing: .04em; }
.jstage-door {
  display: flex;
  align-items: center;
  gap: .65rem;
  width: 100%;
  min-height: 3.2rem;
  padding: .6rem .8rem;
  border: 1px solid rgba(154, 111, 38, .4);
  border-radius: .9rem;
  background: rgba(255, 252, 244, .72);
  color: #38290f;
  text-align: start;
  text-decoration: none;
  font: inherit;
  cursor: pointer;
}
/* The glyph inherits the row's ink, so it is right in every state without a
   second asset — and it sits on its own tinted disc so the row still scans as
   a list of doors rather than a list of sentences. */
.jdoor-glyph {
  flex: 0 0 auto;
  width: 2.15rem;
  height: 2.15rem;
  padding: .42rem;
  border-radius: .7rem;
  background: rgba(154, 111, 38, .12);
  color: #9a6f26;
}
.jstage-door:hover .jdoor-glyph,
.jstage-door:focus-visible .jdoor-glyph { background: rgba(237, 109, 28, .16); color: #b34a06; }
.jstage-door-text { display: grid; gap: .12rem; min-width: 0; flex: 1 1 auto; }
.jstage-door strong { font-size: .88rem; }
.jstage-door small { color: #7b6357; font-size: .7rem; line-height: 1.6; }
.jstage-door i { flex: 0 0 auto; font-style: normal; color: #b34a06; font-weight: 800; }
.jstage-door:hover, .jstage-door:focus-visible { border-color: rgba(237, 109, 28, .6); outline: none; box-shadow: 0 0 0 3px rgba(237, 109, 28, .15); }
/* A locked or uncharted stage's hub is a reading screen: it keeps the same
   paper, and simply has no primary control on it to press. */
.jstage--hub[data-state="locked"] .jstage-hero > img,
.jstage--hub[data-state="uncharted"] .jstage-hero > img { filter: saturate(.35) brightness(.92); }

@media (max-width: 30rem) {
  .jstage { width: 100vw; max-width: none; max-height: 92dvh; margin: auto 0 0; border-radius: 1.4rem 1.4rem 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .jstage { animation: none; }
}

/* ── the dock, and the summary behind it ──────────────────────── */

/* The map screen is the map: one bar rides the bottom of the viewport with
   the way back and the way to the numbers, and it fades out under the sheet
   it opened rather than floating on top of it. */
.journey-dock {
  position: sticky;
  bottom: max(.85rem, env(safe-area-inset-bottom));
  z-index: 6;
  display: flex;
  flex-wrap: nowrap;
  gap: .5rem;
  width: min(30rem, 100%);
  margin: 1.2rem auto 0;
  padding: .45rem;
  border-radius: 999px;
  border: 1px solid rgba(154, 111, 38, .38);
  background: rgba(253, 247, 231, .86);
  backdrop-filter: blur(12px);
  box-shadow: 0 .9rem 2rem rgba(70, 45, 10, .22), inset 0 1px 0 rgba(255, 255, 255, .8);
  transition: opacity .26s ease, transform .26s ease;
}
.journey-dock > button {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 3rem;
  padding-inline: 1rem;
  border-radius: 999px;
  font-size: .88rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.journey-dock .jdock-more {
  flex: 0 1 auto;
  border: 1px solid rgba(154, 111, 38, .5);
  background: linear-gradient(160deg, #fdf7e7, #f0e2c4);
  color: #4a3410;
}
.journey-dock .jdock-more:hover { background: linear-gradient(160deg, #f7ecd3, #e8d4ac); filter: none; }
.journey-dock .jdock-arc {
  flex: 0 1 auto;
  border: 1px solid rgba(193, 79, 12, .55);
  background: linear-gradient(160deg, #f6b26b, #ed6d1c);
  color: #3a1c04;
}
.journey-dock .jdock-arc:hover { filter: brightness(1.04); }
.journey-dock.is-away { opacity: 0; transform: translateY(.5rem); pointer-events: none; }

.jstage--summary { width: min(34rem, calc(100vw - 1.5rem)); }
.jstage--arc { width: min(30rem, calc(100vw - 1.5rem)); }
.jstage-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: .6rem;
  flex: none;
  padding: 1.1rem 1.2rem .4rem;
}
.jstage--summary .jstage-close { position: static; flex: none; }
.jstage--summary .jstage-body { padding-top: .6rem; }
.jstage--summary .journey-side { grid-template-columns: minmax(0, 1fr); }
.jstage--summary .journey-card { background: rgba(255, 253, 248, .92); }

@media (prefers-reduced-motion: reduce) {
  .journey-dock { transition: none; }
}

/* ── the stage bead ─────────────────────────────────────────────────────
   What is waiting inside a stage, on the stage's own row. It sits in the top
   line beside the badge — the medallion is already carrying a seal, and two
   discs on one coin read as damage rather than as information. */
.jcount--stage {
  position: static;
  flex: 0 0 auto;
  min-width: 1.35rem;
  height: 1.35rem;
  margin-inline-start: auto;
  font-size: .7rem;
}
.station--stage .station-top { display: flex; align-items: center; gap: .4rem; }

/* A count that is a quantity, not an alarm. «۳ شهر نگه داشتی» is a fact about
   your own list; painting it the same red as an unanswered question would make
   every screen look like it needed something from you. */
.jcount--quiet {
  background: rgba(154, 111, 38, .16);
  color: #6d5832;
  border-color: rgba(154, 111, 38, .35);
  box-shadow: none;
  text-shadow: none;
}
