/* ============================================================
   Geopals - shared styles for the ordinary pages.

   The card showcase (index.html) is one self-contained file with every image
   embedded, because it is a link people send to each other: it cannot 404 and
   it works offline. That is the right answer for a shareable artefact and the
   WRONG answer for a website, so these pages are built the ordinary way -
   normal HTML, a normal stylesheet, normal image tags.

   Aidan, 2026-08-23: the preview becomes the real site once the content is
   developed. Building these as ordinary pages now means that move is a copy
   rather than a rewrite.

   Palette is lifted from the share page so the two do not drift. Royal blue and
   royal yellow off the wordmark; the eight region colours stay as data.
   ============================================================ */
:root{
  --royal:#123a8c; --royal-2:#1e5bc6; --royal-3:#0c2a68;
  --gold:#f5b324;  --gold-2:#ffd470;  --xred:#d8332f;
  /* The site already had a green at #3f9e5a for the "good" rule card border.
     That is fine on a 4px edge and too light for text on white, so the token is
     a darker member of the same family. Aidan, 2026-08-24. */
  --xgreen:#2f7a46;
  --sky:#eef2fa;   --paper:#fff;      --mist:#e3eaf7;  --rule:#ced9ec;
  --ink:#13233f;   --ink-dim:#51617f; --ink-faint:#8593ad;
  --shadow-2:0 18px 44px rgba(19,35,63,.18);
  --display:"Trebuchet MS","Segoe UI",system-ui,sans-serif;
  --body:system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,sans-serif;
  --maxw:1180px;
  --topnav-h:56px;
  /* The same hand-drawn X the share page uses. An upright even-weight X reads
     as a no-entry sign; the tapered uneven strokes make it a map mark. */
  --xmask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath d='M14 10 C34 32 62 66 88 90 C84 95 78 97 73 94 C50 70 26 38 10 16 Z' fill='%23000'/%3E%3Cpath d='M88 12 C70 34 40 64 15 92 C11 88 9 82 12 77 C36 54 62 26 82 6 Z' fill='%23000'/%3E%3C/svg%3E");
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--sky);color:var(--ink);font-family:var(--body);
  font-size:17px;line-height:1.55}
img{max-width:100%;height:auto}

/* ---- the bar, identical in behaviour to the share page's ---- */
.topnav{position:sticky;top:0;z-index:60;height:var(--topnav-h);
  background:var(--royal);color:#fff;border-bottom:1px solid rgba(255,255,255,.14)}
.topnav-in{max-width:var(--maxw);margin:0 auto;padding:0 1.4rem;height:100%;
  display:flex;align-items:center;gap:1.4rem}
.topnav .brand{font-family:var(--display);font-weight:800;letter-spacing:.02em;
  color:#fff;text-decoration:none;font-size:1.05rem;display:flex;align-items:center;gap:.5rem}
.topnav .brand::before{content:"";width:16px;height:22px;flex:none;border-radius:2px;
  background:url(assets/cardback.jpg) center/cover;box-shadow:0 1px 3px rgba(0,0,0,.4)}
.topnav .links{display:flex;gap:1.5rem;margin-left:auto;align-items:center}
/* ⚠ nowrap. The bar is a fixed height, so a wrapping label does not make the
   bar taller, it spills out of it. "Learn to Play", "Geopals Cards" and
   "Treasure Hunts" are all two words and all wrapped at tablet widths. */
.topnav .links a{color:#cfe0ff;text-decoration:none;font-family:var(--display);
  font-weight:650;font-size:.95rem;padding:.2rem 0;border-bottom:2px solid transparent;
  white-space:nowrap}
.topnav .links a:hover{color:#fff;border-bottom-color:var(--gold)}
.topnav .links a[aria-current="page"]{color:#fff;border-bottom-color:var(--gold)}
.topnav .links a.buy{background:none;border:1.5px solid var(--gold);color:var(--gold);
  border-radius:999px;padding:.3rem .9rem;font-weight:700;font-size:.9rem;border-bottom-width:1.5px}
.topnav .links a.buy:hover{background:var(--gold);color:var(--royal-3);border-bottom-color:var(--gold)}
/* The account door: an outline pill so it reads as an action without
   competing with Buy, which stays the only solid gold thing in the bar. */
.topnav .links a.acct{border:1px solid rgba(255,255,255,.45);border-radius:999px;
  padding:.3rem .85rem;max-width:14ch;overflow:hidden;text-overflow:ellipsis}
.topnav .links a.acct:hover{border-color:var(--gold);color:#fff;border-bottom-color:transparent}

/* Shown at every width, not just mobile. Aidan, 2026-08-23: the tabs were being
   missed, so the menu is a persistent affordance rather than a fallback. */
.burger{margin-left:.4rem;width:42px;height:42px;flex:none;display:grid;place-items:center;
  background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.22);border-radius:11px;
  cursor:pointer;color:#fff}
.burger:hover{background:rgba(255,255,255,.18)}
.burger span{display:block;width:18px;height:2px;background:currentColor;border-radius:2px;
  box-shadow:0 -6px 0 currentColor, 0 6px 0 currentColor}
.drawer{position:fixed;inset:var(--topnav-h) 0 auto 0;z-index:55;background:var(--royal);
  border-bottom:1px solid rgba(255,255,255,.14);box-shadow:var(--shadow-2);display:none}
.drawer[open]{display:block}
.drawer ul{list-style:none;margin:0 auto;padding:.5rem 1.4rem 1.1rem;max-width:var(--maxw)}
.drawer li{border-top:1px solid rgba(255,255,255,.12)}
.drawer li:first-child{border-top:0}
.drawer a{display:block;padding:.95rem .2rem;color:#e7eefc;text-decoration:none;
  font-family:var(--display);font-weight:700;font-size:1.05rem}
.drawer a:hover{color:var(--gold-2)}
/* The two rows Aidan wants prioritised (2026-08-28): gold, kept at the bottom. */
.drawer a.hot{color:var(--gold-2);font-weight:700}
/* ---- the banner menus ----
   Aidan, 2026-08-26: "the drop down should be on the top banner only not
   duplicated under the top banner". The three parents that own more than one
   destination drop their children from the banner. The old second bar under
   the banner is gone; see _nav.html for why it had to go rather than stay.

   The parent is a real link and the chevron is its own button, so clicking the
   word gets you the page and clicking the arrow gets you the menu. */
.topnav .links .navitem{position:relative;display:flex;align-items:center;gap:.15rem}
.navtog{width:22px;height:22px;padding:0;background:none;border:0;cursor:pointer;
  color:#cfe0ff;display:grid;place-items:center;flex:none;border-radius:5px}
.navtog:hover{color:#fff;background:rgba(255,255,255,.16)}
.navtog::before{content:"";width:7px;height:7px;
  border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  transform:translateY(-2px) rotate(45deg);transition:transform .18s ease}
.navtog[aria-expanded="true"]::before{transform:translateY(1px) rotate(-135deg)}
/* Sits under the bar, which is why the bar cannot clip its overflow. */
.dropdown{position:absolute;top:calc(100% + .7rem);left:-.8rem;min-width:212px;
  background:var(--royal);border:1px solid rgba(255,255,255,.18);border-radius:12px;
  box-shadow:var(--shadow-2);padding:.35rem;z-index:70}
/* ⚠ Bridge the gap. Aidan, 2026-08-26: "when I go to click the dropdown
   disappears it doesn't hold as I hover down". The menu is a DOM child of
   .navitem, so hovering the menu itself keeps the item hovered, but the .7rem
   of air between the bar and the menu belongs to neither box. Crossing it fired
   mouseleave and the menu closed on the way to being clicked. This is an
   invisible strip filling that gap, and because it is part of the menu the
   pointer never leaves the item. */
.dropdown::before{content:"";position:absolute;left:0;right:0;top:-.8rem;height:.8rem}
.dropdown[hidden]{display:none}
.topnav .links .dropdown a{display:block;padding:.6rem .75rem;border-radius:8px;
  color:#e7eefc;font-size:.92rem;font-weight:650;white-space:nowrap;border-bottom:0}
.topnav .links .dropdown a:hover{background:rgba(255,255,255,.12);color:#fff;border-bottom:0}
.topnav .links .dropdown a[aria-current="page"]{color:var(--gold-2);border-bottom:0}

/* ⚠ 900, not 760. Aidan, 2026-08-26, asked for "Learn to Play" written out in
   full rather than "Learn". Measured: the five items plus the brand, the Buy
   pill and the burger need about 960px, and they fit cleanly from 1000px up.
   At the old 760px cut-off the band from 760 to 900 wrapped every two-word
   label onto a second line and spilled out of a fixed-height bar. The burger
   now takes over before that can happen, which is why the full label works at
   every width rather than needing a desktop-only variant. */
@media (max-width:900px){
  /* The burger carries all of this below 900, so the banner keeps only Buy. */
  .topnav .links a:not(.buy){display:none}
  .topnav .links .navitem{display:none}
  .topnav-in{gap:.7rem}
}

/* ---- page body ---- */
.page{max-width:var(--maxw);margin:0 auto;padding:clamp(2.2rem,5vw,4rem) 1.4rem 6rem}
.page h1{font-family:var(--display);font-size:clamp(1.8rem,4vw,2.6rem);line-height:1.08;
  letter-spacing:-.015em;margin:0 0 .6rem;display:flex;align-items:center;gap:.7rem}
/* A little card back rather than the map X. Aidan, 2026-08-24: the red X in
   front of a page title read as a cross, as in wrong, rather than as the
   treasure mark it is. A card says "trading card game" without any ambiguity.
   The X still fronts the brand in the top bar, where it belongs.
   26 wide over the 0.734 card ratio gives 35 tall. */
.page h1::before{content:"";width:26px;height:35px;flex:none;
  background:url("assets/cardback.jpg") center/cover;
  border-radius:3px;transform:rotate(-7deg);
  box-shadow:0 2px 6px rgba(19,35,63,.35),0 0 0 1px rgba(255,255,255,.55)}
.page .lede{color:var(--ink-dim);font-size:1.08rem;max-width:62ch;margin:0 0 2rem}

/* A stated gap, not a blank screen. A page that looks empty reads as broken;
   one that says what is coming reads as unfinished, which is the truth. */
.soon{background:var(--paper);border:1px solid var(--rule);border-radius:16px;
  padding:clamp(1.6rem,4vw,2.6rem);max-width:62ch}
.soon h2{font-family:var(--display);font-size:1.15rem;margin:0 0 .5rem}
.soon p{color:var(--ink-dim);margin:0 0 .8rem}
.soon p:last-child{margin-bottom:0}
.soon a{color:var(--royal-2)}

footer{border-top:1px solid var(--rule);background:var(--paper)}
footer .in{max-width:var(--maxw);margin:0 auto;padding:1.6rem 1.4rem 2.4rem;
  color:var(--ink-faint);font-size:.9rem}
footer p{margin:.2rem 0}

/* ---- the shop ----
   Our markup, our stylesheet. Shopify's Buy Button SDK would have rendered its
   own and needed a token in a public repo; the catalogue is public without one,
   so the products are baked in at build time and the button hands off to
   Shopify's checkout. See build-buy-page.ps1 for the reasoning. */
.shop{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,300px),1fr));
  gap:1.4rem;margin:0 0 2rem}
.prod{background:var(--paper);border:1px solid var(--rule);border-radius:16px;
  overflow:hidden;display:flex;flex-direction:column;box-shadow:0 1px 2px rgba(19,35,63,.06)}
.prod-img{background:var(--mist);aspect-ratio:4/3;display:grid;place-items:center;overflow:hidden}
.prod-img img{width:100%;height:100%;object-fit:cover;display:block}
.prod-body{padding:1.1rem 1.15rem 1.25rem;display:flex;flex-direction:column;gap:.45rem;flex:1}
.prod h2{font-family:var(--display);font-size:1.12rem;margin:0;line-height:1.2}
.prod .price{font-family:var(--display);font-weight:800;font-size:1.25rem;color:var(--royal);margin:0}
.prod .desc{color:var(--ink-dim);font-size:.94rem;margin:0}
.prod .vlabel{font-size:.8rem;color:var(--ink-faint);text-transform:uppercase;
  letter-spacing:.08em;margin-top:.35rem}
.prod .vpick{font:inherit;font-size:.95rem;padding:.55rem .7rem;border:1px solid var(--rule);
  border-radius:10px;background:var(--paper);color:var(--ink);width:100%}
.buybtn{margin-top:auto;display:block;text-align:center;background:var(--gold);
  color:var(--royal-3);font-family:var(--display);font-weight:800;font-size:1rem;
  text-decoration:none;padding:.75rem 1rem;border-radius:999px}
.buybtn:hover{background:var(--gold-2)}
/* Sold out is stated, not hidden. A product that vanishes looks like a fault. */
.prod.out{opacity:.72}
.prod .sold{margin-top:auto;text-align:center;font-family:var(--display);font-weight:800;
  color:var(--ink-faint);border:1px dashed var(--rule);border-radius:999px;padding:.75rem 1rem}
.shopnote{color:var(--ink-faint);font-size:.9rem;max-width:62ch}
/* ---- video ----
   16:9 without a wrapper hack: aspect-ratio is supported everywhere that
   matters now. The iframe is lazy so the page paints before YouTube answers. */
.video{position:relative;aspect-ratio:16/9;background:#000;border-radius:16px;
  overflow:hidden;border:1px solid var(--rule);box-shadow:var(--shadow-2);
  max-width:900px;margin:0 0 .7rem}
.video iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
.vcap{color:var(--ink-faint);font-size:.9rem;margin:0 0 2.2rem;max-width:900px}
.vcap a{color:var(--royal-2)}



/* ---- rules, laid out for someone who has never played ----
   Order matters more than wording here. A newcomer needs the shape of the game,
   then the loop they repeat, then the detail. The card catalogue comes late on
   purpose: knowing what a Terraform card is means nothing before you know what
   a turn is. */

/* The game in three lines. Sits directly under the video so the shape of the
   thing lands before any rule does. */
.nutshell{background:var(--royal);color:#fff;border-radius:18px;
  padding:clamp(1.4rem,3.5vw,2rem);margin:0 0 1.6rem}
.nutshell h2{font-family:var(--display);font-size:1.1rem;margin:0 0 1rem;
  color:var(--gold);letter-spacing:.02em}
.three{list-style:none;margin:0;padding:0;display:grid;gap:.9rem;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr))}
.three li{display:flex;gap:.75rem;align-items:flex-start;color:#e7eefc;line-height:1.45}
.three .num{flex:none;width:28px;height:28px;border-radius:50%;background:var(--gold);
  color:var(--royal-3);font-family:var(--display);font-weight:800;
  display:grid;place-items:center;font-size:.95rem}

/* Jump list. A rules page is read out of order: people come back mid-game for
   the one thing they forgot. */
.jump{display:flex;flex-wrap:wrap;gap:.5rem;margin:0 0 2.4rem}
.jump a{background:var(--paper);border:1px solid var(--rule);border-radius:999px;
  padding:.4rem .9rem;color:var(--royal);text-decoration:none;font-size:.92rem;
  font-family:var(--display);font-weight:650}
.jump a:hover{border-color:var(--royal-2);color:var(--royal-3)}

.rules{max-width:64ch;margin:0 0 2.8rem;scroll-margin-top:calc(var(--topnav-h) + 12px)}
.rules.wide{max-width:none}
.rules h2{font-family:var(--display);font-size:1.4rem;margin:0 0 .5rem}
.rules h3{font-family:var(--display);font-size:1.05rem;margin:1.6rem 0 .5rem;color:var(--royal)}
.rules .sub{color:var(--ink-faint);margin:-.2rem 0 1.1rem}
.rules p{color:var(--ink-dim);margin:0 0 .8rem}
.rules li{color:var(--ink-dim);margin:0 0 .45rem}
.rules b{color:var(--ink);font-weight:650}
.rules .note{font-size:.94rem;color:var(--ink-faint)}

.need{background:var(--paper);border:1px solid var(--rule);border-radius:14px;
  padding:1.1rem 1.2rem;margin:0 0 1.4rem}
.need h3{margin:0 0 .5rem}
.ticks{list-style:none;padding:0;margin:0 0 .6rem}
.ticks li{position:relative;padding-left:1.5rem}
.ticks li::before{content:"";position:absolute;left:0;top:.55em;width:9px;height:9px;
  border-radius:2px;background:var(--gold)}

/* Numbered setup steps. The number is the anchor the eye returns to. */
.steps{list-style:none;counter-reset:s;padding:0;margin:0 0 1rem}
.steps li{counter-increment:s;position:relative;padding-left:2.4rem;margin-bottom:.8rem}
.steps li::before{content:counter(s);position:absolute;left:0;top:-.1em;
  width:26px;height:26px;border-radius:50%;background:var(--royal);color:#fff;
  font-family:var(--display);font-weight:800;font-size:.9rem;display:grid;place-items:center}

/* The table, drawn. Two sentences cannot say "a line of terrain with you at one
   end and the treasure at the other" as fast as a picture of it. */
.tablefig{margin:0 0 1.6rem}
.tablefig svg{width:100%;height:auto;background:var(--paper);border:1px solid var(--rule);
  border-radius:14px;padding:.6rem}
.tablefig .lbl{font:650 13px var(--display);fill:var(--ink-dim);text-anchor:middle}
.tablefig .cap{font:400 12px var(--body);fill:var(--ink-faint);text-anchor:middle}
.tablefig .zone{fill:var(--mist);stroke:var(--rule)}
.tablefig .terr rect{fill:#fff;stroke:var(--royal-2);stroke-width:2;stroke-dasharray:5 4}
.tablefig .tok{fill:var(--royal-2)}
.tablefig .tok.b{fill:var(--royal)}
.tablefig .tre{fill:var(--ink-faint)}
.tablefig .tre.orb{fill:var(--gold);stroke:var(--xred);stroke-width:2}
.tablefig .arrow{stroke:var(--ink-faint);stroke-width:2;stroke-dasharray:6 6;fill:none}
.tablefig .arrowhead{fill:var(--ink-faint)}

/* The turn, as three numbered cards. It is a loop, so it should read as a
   sequence rather than three headings in a column. */
.phases{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,250px),1fr));
  margin:0 0 1.2rem}
.phase{background:var(--paper);border:1px solid var(--rule);border-radius:16px;
  padding:1.15rem 1.2rem;position:relative}
.phase .pnum{position:absolute;top:-14px;left:1.2rem;width:30px;height:30px;border-radius:50%;
  background:var(--gold);color:var(--royal-3);font-family:var(--display);font-weight:800;
  display:grid;place-items:center;box-shadow:0 2px 6px rgba(19,35,63,.18)}
.phase h3{margin:.55rem 0 .6rem;color:var(--ink)}
.phase ul{padding-left:1.1rem;margin:0}
.phase li{font-size:.95rem}

/* The rule people get wrong most. Given its own weight, once. */
.warn{background:rgba(245,179,36,.16);border-left:4px solid var(--gold);
  padding:.9rem 1.05rem;border-radius:0 12px 12px 0;color:var(--ink);margin:0 0 .8rem}
.warn b{color:var(--royal-3)}

/* Movement: three outcomes, colour-coded, because that is how they feel in
   play - neutral, good, bad. */
.rulecards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,230px),1fr))}
.rc{background:var(--paper);border:1px solid var(--rule);border-radius:14px;
  padding:1rem 1.1rem;border-top:4px solid var(--ink-faint)}
.rc.good{border-top-color:#3f9e5a}
.rc.bad{border-top-color:var(--xred)}
.rc h3{margin:0 0 .4rem;font-size:1rem;color:var(--ink)}
.rc p{margin:0;font-size:.94rem}

.games{display:grid;gap:.7rem;margin:0 0 1.2rem}
.game{background:var(--paper);border:1px solid var(--rule);border-radius:12px;
  padding:.8rem 1rem;display:flex;gap:.9rem;align-items:baseline;color:var(--ink-dim)}
.game .gn{font-family:var(--display);font-weight:800;color:var(--royal);flex:none;min-width:5.5rem}
.game b{color:var(--ink)}

.cardtypes{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,215px),1fr));
  gap:1.5rem;margin:0 0 1.2rem}
.cardtypes figure{margin:0}
.cardtypes img{width:100%;border-radius:10px;display:block;box-shadow:var(--shadow-2)}
.cardtypes figcaption{color:var(--ink-dim);font-size:.92rem;margin-top:.65rem;line-height:1.45}
.cardtypes figcaption b{color:var(--ink);font-weight:750;display:block;font-family:var(--display);
  font-size:1rem;margin-bottom:.15rem}

.terms{margin:0}
.terms dt{font-family:var(--display);font-weight:800;color:var(--ink);margin-top:.75rem}
.terms dd{margin:.1rem 0 0;color:var(--ink-dim)}
/* Awakening: two equal routes, so two equal cards rather than a sentence with
   an "or" buried in it. */
.rulecards.two{grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr));margin:0 0 1rem}
.tablefig .zone.finish{fill:rgba(245,179,36,.16);stroke:var(--gold)}
.tablefig .flag path{fill:none;stroke:var(--xred);stroke-width:5;stroke-linecap:round;stroke-linejoin:round}
.tablefig .flag path:last-child{fill:var(--xred)}
/* ---- progressive tutorial ----
   One screen, one idea. Completed steps collapse to a line and reopen on tap;
   nothing is permanently hidden. The point is to make the page look SHORT. */
.progress{position:sticky;top:var(--topnav-h);z-index:50;background:rgba(238,242,250,.96);
  backdrop-filter:blur(8px);border-bottom:1px solid var(--rule);padding:.55rem 1.4rem;
  display:flex;align-items:center;gap:.8rem}
.progress .ptext{font-family:var(--display);font-weight:700;font-size:.88rem;color:var(--ink-dim);flex:none}
.progress .ptext b{color:var(--royal)}
.progress .pbar{flex:1;height:7px;background:var(--mist);border-radius:99px;overflow:hidden;max-width:520px}
.progress .pbar i{display:block;height:100%;width:25%;background:var(--gold);
  border-radius:99px;transition:width .45s cubic-bezier(.4,0,.2,1)}

.learn h1{margin-bottom:.4rem}
.steps-wrap{margin-top:2rem}
.step{margin:0 0 1rem;scroll-margin-top:calc(var(--topnav-h) + 56px)}
.stepbody{background:var(--paper);border:1px solid var(--rule);border-radius:18px;
  padding:clamp(1.2rem,3.5vw,2rem)}
.eyebrow{font-family:var(--display);font-weight:800;font-size:.78rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--gold);margin:0 0 .3rem}
.step h2{font-family:var(--display);font-size:clamp(1.4rem,3.4vw,1.9rem);margin:0 0 .9rem}
.step .sub{color:var(--ink-dim);margin:-.4rem 0 1.2rem}

/* A finished step: one line, tappable, obviously complete. */
.stepdone{width:100%;display:flex;align-items:center;gap:.7rem;text-align:left;
  background:var(--paper);border:1px solid var(--rule);border-radius:14px;
  padding:.85rem 1.05rem;cursor:pointer;font:inherit;color:var(--ink)}
.stepdone:hover{border-color:var(--royal-2)}
.stepdone .tick{flex:none;width:24px;height:24px;border-radius:50%;background:#3f9e5a;color:#fff;
  display:grid;place-items:center;font-size:.85rem;font-weight:800}
.stepdone b{font-family:var(--display)}
.stepdone .sum{color:var(--ink-faint);font-size:.8rem;margin-left:0;text-align:left}
@media (max-width:620px){ .stepdone .sum{display:none} }

.nextbtn{display:block;width:100%;margin-top:1.6rem;background:var(--royal);color:#fff;
  border:0;border-radius:999px;padding:.95rem 1.2rem;font-family:var(--display);
  font-weight:800;font-size:1.02rem;cursor:pointer}
.nextbtn:hover{background:var(--royal-2)}
.nextbtn.done{background:var(--gold);color:var(--royal-3)}
.nextbtn.done:hover{background:var(--gold-2)}

/* Detail on request. The whole point: complexity is asked for, not served. */
.more{margin-top:1.1rem;border-top:1px solid var(--rule);padding-top:.9rem}
.more summary{cursor:pointer;font-family:var(--display);font-weight:700;color:var(--royal);
  font-size:.95rem;list-style:none}
.more summary::-webkit-details-marker{display:none}
.more summary::before{content:"+ ";font-weight:800}
.more[open] summary::before{content:"\2212 "}
.more > *:not(summary){margin-top:.8rem}
.more ul,.more ol{padding-left:1.2rem;color:var(--ink-dim)}
.more li{margin-bottom:.4rem}
.more p{color:var(--ink-dim)}

.twocol{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));
  margin:0 0 .4rem}

/* Act, Move, Draw. The line people should remember. */
.loop{display:grid;gap:.5rem;justify-items:center;margin:0 0 1.2rem}
.loopstep{background:var(--mist);border-radius:14px;padding:.9rem 1.2rem;text-align:center;
  width:100%;max-width:420px}
.loopstep .ls{display:block;font-family:var(--display);font-weight:800;font-size:1.15rem;
  color:var(--royal);letter-spacing:.06em;text-transform:uppercase}
.loopstep p{margin:.15rem 0 0;color:var(--ink-dim);font-size:.95rem}
.loopar{color:var(--gold);font-size:1.3rem;line-height:1}
.bigline{font-family:var(--display);font-weight:800;font-size:clamp(1.3rem,4.5vw,1.9rem);
  color:var(--royal);text-align:center;margin:.4rem 0 .2rem;letter-spacing:.02em}
.centred{text-align:center;color:var(--ink-dim)}

.walker{fill:var(--royal-2);stroke:#fff;stroke-width:3}
@media (prefers-reduced-motion:reduce){ .walker animate{display:none} }

/* The payoff. Worth a moment of celebration. */
.finished{background:var(--royal);color:#fff;border-radius:20px;text-align:center;
  padding:clamp(1.8rem,5vw,3rem);margin-top:1.4rem}
.bigtick{width:58px;height:58px;margin:0 auto .8rem;border-radius:50%;background:var(--gold);
  color:var(--royal-3);display:grid;place-items:center;font-size:1.7rem;font-weight:800}
.finished h2{font-family:var(--display);font-size:clamp(1.5rem,4vw,2.1rem);margin:0 0 .4rem;color:#fff}
.finished > p{color:#cfe0ff;margin:0 0 1.4rem}
.finishbtns{display:flex;gap:.7rem;justify-content:center;flex-wrap:wrap;margin-bottom:2rem}
.finishbtns .primary{background:var(--gold);color:var(--royal-3);border-radius:999px;
  padding:.8rem 1.6rem;font-family:var(--display);font-weight:800;text-decoration:none}
.finishbtns .secondary{color:#cfe0ff;text-decoration:none;padding:.8rem 1rem;
  font-family:var(--display);font-weight:700}
.finishbtns .secondary:hover{color:#fff}

.deeper{border-top:1px solid rgba(255,255,255,.16);padding-top:1.4rem}
.deeper h3{font-family:var(--display);color:var(--gold);font-size:1rem;margin:0 0 .9rem}
.deepcards{display:grid;gap:.8rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,230px),1fr))}
.deep{display:block;text-align:left;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.18);
  border-radius:14px;padding:1rem 1.1rem;text-decoration:none;color:#fff}
a.deep:hover{background:rgba(255,255,255,.14);border-color:var(--gold)}
.deep .di{font-size:1.3rem;display:block;margin-bottom:.3rem;color:var(--gold)}
.deep b{font-family:var(--display);display:block;margin-bottom:.2rem}
.deep span:last-child{color:#b9cdf2;font-size:.9rem;display:block}
.deep.off{opacity:.55}
/* ---- strategy: pick one, and only that one opens ----
   Someone reading about Rush should never scroll past Control. */
.archetypes{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,250px),1fr));margin:0 0 2rem}
.arch{text-align:left;background:var(--paper);border:1px solid var(--rule);border-radius:16px;
  padding:1.2rem 1.25rem;cursor:pointer;font:inherit;color:var(--ink)}
.arch:hover{border-color:var(--royal-2);box-shadow:var(--shadow-2)}
.arch .ai{font-size:1.6rem;display:block;margin-bottom:.35rem;color:var(--gold)}
.arch b{font-family:var(--display);font-size:1.15rem;display:block;margin-bottom:.25rem}
.arch span:last-child{color:var(--ink-dim);font-size:.94rem;display:block;line-height:1.45}
.archpanel h2{font-family:var(--display);font-size:clamp(1.5rem,4vw,2.1rem);margin:0 0 .3rem}
.archpanel .sub{color:var(--ink-dim);margin:0 0 1.4rem;max-width:60ch}
.archback{background:none;border:0;color:var(--royal-2);font:inherit;font-family:var(--display);
  font-weight:700;cursor:pointer;padding:0;margin:0 0 1rem}
.archback:hover{color:var(--royal-3)}
/* Card types inside step 1. A compact strip, not the full catalogue - names and
   pictures so the cards are recognisable, detail behind the toggle. Aidan,
   2026-08-23: this is essential context for setting up, not an epilogue. */
.stepsub{font-family:var(--display);font-size:1.02rem;color:var(--royal);
  margin:1.8rem 0 .35rem;padding-top:1.1rem;border-top:1px solid var(--rule)}
.stepbody > .stepsub:first-of-type{margin-top:.6rem;padding-top:0;border-top:0}
.ctstrip{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(46%,132px),1fr));
  gap:.9rem;margin:0 0 .8rem}
.ctstrip figure{margin:0}
.ctstrip img{width:100%;border-radius:8px;display:block;box-shadow:0 3px 10px rgba(19,35,63,.16)}
.ctstrip figcaption{margin-top:.4rem;font-size:.84rem;color:var(--ink-faint);line-height:1.35}
.ctstrip figcaption b{display:block;font-family:var(--display);font-size:.95rem;color:var(--ink)}
/* Annotated card and playmat. Numbered pins over the image, list beneath -
   leader lines break at every width, numbers do not. Percentages because the
   card template is identical on every Geopal, so these hold for all of them. */
.anatomy{display:grid;gap:1.4rem;grid-template-columns:minmax(0,300px) minmax(0,1fr);
  align-items:start;margin:0 0 1rem}
@media (max-width:640px){ .anatomy{grid-template-columns:1fr} }
.anafig{position:relative;line-height:0}
.anafig img{width:100%;border-radius:10px;box-shadow:var(--shadow-2)}
.pin,.mpin{position:absolute;transform:translate(-50%,-50%);width:26px;height:26px;
  border-radius:50%;background:var(--xred);color:#fff;font-family:var(--display);
  font-weight:800;font-size:.82rem;display:grid;place-items:center;line-height:1;
  box-shadow:0 0 0 2px #fff, 0 2px 6px rgba(19,35,63,.4)}
.analist{counter-reset:a;list-style:none;padding:0;margin:0}
.analist li{counter-increment:a;position:relative;padding-left:2.2rem;margin-bottom:.7rem;
  color:var(--ink-dim);font-size:.95rem;line-height:1.45}
.analist li::before{content:counter(a);position:absolute;left:0;top:0;width:24px;height:24px;
  border-radius:50%;background:var(--xred);color:#fff;font-family:var(--display);
  font-weight:800;font-size:.78rem;display:grid;place-items:center}
.analist li b{display:block;color:var(--ink);font-family:var(--display)}
.analist.wide{margin-top:1rem}

.matfig{position:relative;line-height:0;margin:0 0 .4rem}
.matfig img{width:100%;border-radius:12px;box-shadow:var(--shadow-2)}

/* The line that makes movement make sense. Not on the printed sheet at all. */
.keyline{background:rgba(30,91,198,.10);border-left:4px solid var(--royal-2);
  padding:.85rem 1rem;border-radius:0 12px 12px 0;color:var(--ink);margin:0 0 1rem}

.terrainex{display:grid;gap:1.1rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr));
  margin:0 0 .8rem}
.terrainex figure{margin:0}
.terrainex img{width:100%;border-radius:10px;display:block;box-shadow:var(--shadow-2)}
.terrainex figcaption{margin-top:.5rem;color:var(--ink-dim);font-size:.93rem;line-height:1.45}
.terrainex figcaption b{display:block;font-family:var(--display);color:var(--royal);font-size:1.05rem}
/* Berries versus Max Stamina. Three states side by side, because the rule only
   lands when you see "2 berries against a cap of 3" next to "no berries". */
.berryex{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr));
  margin:0 0 .8rem}
.be{background:var(--paper);border:1px solid var(--rule);border-radius:14px;
  padding:1rem 1.1rem;text-align:center;border-top:4px solid var(--ink-faint)}
.be.full{border-top-color:#3f9e5a}
.be.none{border-top-color:var(--xred)}
.be .bn{display:block;font-size:.78rem;letter-spacing:.09em;text-transform:uppercase;
  color:var(--ink-faint);font-family:var(--display);font-weight:700}
.be .berries{display:block;font-size:1.7rem;line-height:1.5;letter-spacing:.1em}
.be .berries.dim{color:var(--ink-faint);font-size:1.3rem}
.be b{display:block;font-family:var(--display);color:var(--ink);margin-bottom:.2rem}
.be p{margin:0;color:var(--ink-dim);font-size:.93rem}
/* ---- strategy panels ---- */
.objective{font-family:var(--display);font-weight:700;font-size:1.08rem;color:var(--royal);
  border-left:4px solid var(--gold);padding-left:.9rem;margin:0 0 1.6rem;max-width:60ch}
.archbody{max-width:64ch;margin:0 0 2rem}
.archbody h3{font-family:var(--display);font-size:1.05rem;color:var(--royal);margin:1.5rem 0 .45rem}
.archbody p{color:var(--ink-dim);margin:0 0 .6rem}
.archbody ul{padding-left:1.2rem;margin:0}
.archbody li{color:var(--ink-dim);margin-bottom:.45rem}

/* ---- FAQ ---- */
.faqsearch{display:flex;align-items:center;gap:.8rem;margin:0 0 1.6rem;max-width:640px}
.faqsearch input{flex:1;font:inherit;font-size:1rem;padding:.8rem 1rem;border:1px solid var(--rule);
  border-radius:999px;background:var(--paper);color:var(--ink)}
.faqsearch input:focus{outline:2px solid var(--royal-2);outline-offset:1px}
.fcount{color:var(--ink-faint);font-size:.9rem;font-family:var(--data);flex:none}
.faqlist{max-width:70ch}
.faqgroup{font-family:var(--display);font-size:.82rem;letter-spacing:.12em;text-transform:uppercase;
  color:var(--gold);margin:2rem 0 .7rem}
.faqgroup:first-child{margin-top:0}
.qa{background:var(--paper);border:1px solid var(--rule);border-radius:12px;
  margin-bottom:.6rem;padding:.9rem 1.1rem}
.qa summary{cursor:pointer;font-family:var(--display);font-weight:700;color:var(--ink);
  list-style:none;font-size:1rem;line-height:1.4}
.qa summary::-webkit-details-marker{display:none}
.qa summary::before{content:"+";color:var(--royal-2);font-weight:800;margin-right:.55rem}
.qa[open] summary::before{content:"\2212"}
.qa[open] summary{margin-bottom:.55rem}
.qa p{margin:0;color:var(--ink-dim);padding-left:1.5rem}
.empty{color:var(--ink-faint);max-width:60ch}
/* Pins moved into the margins with a small arrow, because a number sitting on
   top of the thing it annotates hides it. Aidan, 2026-08-23. */
.pin,.mpin{position:absolute;transform:translate(-50%,-50%);width:19px;height:19px;
  border-radius:50%;background:var(--xred);color:#fff;font-family:var(--display);
  font-weight:800;font-size:.66rem;display:grid;place-items:center;line-height:1;
  box-shadow:0 0 0 2px #fff, 0 1px 4px rgba(19,35,63,.45);z-index:2}
.pin::after,.mpin::after{content:"";position:absolute;width:0;height:0;border:4px solid transparent}
.pin.l::after,.mpin.l::after{left:100%;top:50%;transform:translateY(-50%);border-left-color:var(--xred)}
.pin.r::after,.mpin.r::after{right:100%;top:50%;transform:translateY(-50%);border-right-color:var(--xred)}
.pin.t::after,.mpin.t::after{top:100%;left:50%;transform:translateX(-50%);border-top-color:var(--xred)}
.pin.b::after,.mpin.b::after{bottom:100%;left:50%;transform:translateX(-50%);border-bottom-color:var(--xred)}
.analist li::before{width:19px;height:19px;font-size:.66rem}
.analist li{padding-left:1.9rem}

/* Setup is the thing you are doing at the table, so it reads bigger than a
   normal list. */
.steps.big li{margin-bottom:1rem;color:var(--ink-dim)}
.steps.big li b{color:var(--ink)}
/* A tactical hint, distinct from a rule. Rules are what you must do; this is
   what a good player does. */
.tip{background:rgba(63,158,90,.10);border:1px solid rgba(63,158,90,.35);
  border-radius:14px;padding:1rem 1.15rem;margin:0 0 1rem}
.tip h4{font-family:var(--display);font-size:1rem;margin:0 0 .45rem;color:#2f7a45}
.tip p{margin:0 0 .6rem;color:var(--ink-dim)}
.tip p:last-child{margin-bottom:0}
/* Berry count without emoji. The strawberry glyph is not a Geopals berry and
   looked like a placeholder, which it was. */
.be .bcount{display:block;font-family:var(--display);font-weight:800;
  font-size:2.4rem;line-height:1.1;color:var(--royal)}
.be .bcount.zero{color:var(--xred)}
.be b{display:block;font-family:var(--display);color:var(--ink);
  font-size:.95rem;margin-bottom:.3rem}

.berrytypes{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(46%,140px),1fr));
  gap:1rem;margin:0 0 1.2rem}
.berrytypes figure{margin:0}
.berrytypes img{width:100%;border-radius:8px;display:block;box-shadow:0 3px 10px rgba(19,35,63,.16)}
.berrytypes figcaption{margin-top:.4rem;font-size:.85rem;color:var(--ink-faint);line-height:1.35}
.berrytypes figcaption b{display:block;font-family:var(--display);font-size:1rem;color:var(--ink)}

.splitrule{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,250px),1fr));
  margin:0 0 1.4rem}
.sr{border-radius:14px;padding:1rem 1.15rem;border:1px solid var(--rule);background:var(--paper)}
.sr.any{border-top:4px solid #3f9e5a}
.sr.match{border-top:4px solid var(--gold)}
.sr h4{font-family:var(--display);font-size:1rem;margin:0 0 .4rem;color:var(--ink)}
.sr p{margin:0;color:var(--ink-dim);font-size:.95rem}

.order{display:grid;gap:.7rem;grid-template-columns:1fr auto 1fr;align-items:center;margin:0 0 1rem}
@media (max-width:600px){ .order{grid-template-columns:1fr} .order .oar{transform:rotate(90deg)} }
.ostep{background:var(--paper);border:1px solid var(--rule);border-radius:14px;padding:1rem 1.1rem;position:relative}
.ostep .on{position:absolute;top:-12px;left:1.1rem;width:26px;height:26px;border-radius:50%;
  background:var(--royal);color:#fff;font-family:var(--display);font-weight:800;font-size:.8rem;
  display:grid;place-items:center}
.ostep b{display:block;font-family:var(--display);margin:.5rem 0 .3rem;color:var(--ink)}
.ostep p{margin:0;color:var(--ink-dim);font-size:.93rem}
.oar{color:var(--gold);font-size:1.5rem;text-align:center}

/* Game rows: one line each. They were wrapping into three ragged columns. */
.game{display:flex;gap:.7rem;align-items:baseline;flex-wrap:nowrap}
.game .gn{flex:0 0 auto;min-width:4.6rem}
.game b{flex:0 0 auto;white-space:nowrap}
.game .gt{color:var(--ink-dim)}
@media (max-width:420px){ .game{font-size:.94rem} .game .gn{min-width:4rem} }
/* The escape hatch at the top of Learn to Play. Deliberately lopsided: the
   tutorial is the recommendation and gets the weight, the full rules are a quiet
   line underneath. Someone who has played before will hunt for the rules
   anyway, so hiding them just makes the page annoying. */
.pathpick{background:var(--paper);border:1px solid var(--rule);border-radius:16px;
  padding:1.1rem 1.25rem;margin:0 0 1.6rem}
.pp-main b{font-family:var(--display);font-size:1.05rem;color:var(--ink);display:block;
  margin-bottom:.25rem}
.pp-main p{margin:0 0 .9rem;color:var(--ink-dim);font-size:.96rem}
.pp-alt{display:block;border-top:1px solid var(--rule);padding-top:.85rem;
  text-decoration:none;color:var(--ink-faint);font-size:.92rem}
.pp-alt span{display:block;font-family:var(--display);font-weight:700;
  color:var(--royal-2);font-size:1rem;margin-top:.1rem}
.pp-alt:hover span{color:var(--royal-3)}
/* ============================================================================
   REAL-CARD ILLUSTRATIONS
   Added 2026-08-24. These replace the dashed-rectangle SVG diagrams, which
   Aidan rightly called lazy: they showed empty boxes for a game whose whole
   point is the art on the cards. Everything below composites the ACTUAL
   artwork off Drive, sized by scripts/build-learn-assets.ps1.

   ⚠ GEOMETRY IS MEASURED, NOT GUESSED. Two sets of numbers matter:

   1. Terrain tile centres, as a percentage of the card image:
        5-tile card : x 13.9  30.9  48.9  68.3  87.8   y 51
        3-tile card : x 21.5  50.0  78.5              y 51
      Remeasure if Jenny redraws a terrain card.

   2. Playmat zones, as a percentage of playmat.jpg (1400x782):
        Trap Zone  left  1.8  top  4.0  w 96.4  h 32.5
        Play Zone  left 27.0  top 41.4  w 46.6
        Discard    left  8.0  top 68.0  w 11.4
        Deck       left 80.4  top 68.0  w 11.5

   A card is 900x1226 (ratio .734) and the mat is 1.79 wide, so a card placed
   at W% of the mat's width is W * 2.44 % of its height. That constant is why
   the card widths below look arbitrary. They are not.
   ============================================================================ */

/* ---- shared: a card sitting on something ---- */
.onboard{position:absolute;line-height:0}
.onboard img{width:100%;border-radius:4px;display:block;
  box-shadow:0 3px 10px rgba(19,35,63,.45)}

/* ---- shared: a real token, cut round ---- */
/* The token PNGs are square with transparency. The white disc and ring are
   drawn here rather than baked in, so one file serves every size. */
.token{display:inline-grid;place-items:center;border-radius:50%;
  background:radial-gradient(circle at 50% 38%,#fff,#e8eef8);
  box-shadow:0 0 0 2px #fff,0 0 0 4px var(--royal),0 4px 10px rgba(19,35,63,.4);
  overflow:hidden}
.token img{width:96%;height:96%;object-fit:contain;display:block}

/* ============================ THE BOARD ============================
   The full setup, recreated from the real components. Reads top to bottom the
   way it sits on a table: the map between the players, then your own mat. */
.board{margin:0 0 1.2rem}
.blabel{display:block;font-family:var(--display);font-weight:700;
  color:var(--royal);font-size:.95rem;margin:0 0 .45rem}
.blabel span{font-family:var(--body);font-weight:400;color:var(--ink-dim)}

/* the terrain zone: four cards end to end */
.maprow{display:grid;grid-template-columns:repeat(4,1fr);gap:.3rem;margin:0 0 .3rem}
.mapcard{position:relative;margin:0;line-height:0}
.mapcard img{width:100%;display:block;border-radius:5px;
  box-shadow:0 3px 10px rgba(19,35,63,.3)}
.mapcard figcaption{position:absolute;left:0;right:0;bottom:0;
  font-family:var(--display);font-size:.62rem;font-weight:700;color:#fff;
  background:linear-gradient(transparent,rgba(12,42,104,.85));
  padding:.9rem .3rem .22rem;border-radius:0 0 5px 5px;text-align:center;
  letter-spacing:.02em}
/* A token standing on a specific tile. Kept small enough to sit INSIDE a slab
   rather than covering it. At 26% it spilled over the tile edges and three of
   them on one card looked like a pile-up. Aidan, 2026-08-24. */
.mapcard .token{position:absolute;width:17%;aspect-ratio:1;
  transform:translate(-50%,-50%);z-index:3;
  box-shadow:0 0 0 1.5px #fff,0 0 0 3px var(--royal),0 2px 6px rgba(19,35,63,.4)}
/* the marker that shows WHICH tile a face-down trap is assigned to. The rule is
   that your opponent can see the tile but not the card, so the map needs a
   visible marker even though the trap itself stays face down. */
.trapmark{position:absolute;transform:translate(-50%,-50%);width:15%;aspect-ratio:1;
  border-radius:50%;background:rgba(216,51,47,.92);border:2px solid #fff;
  display:grid;place-items:center;color:#fff;font-family:var(--display);
  font-weight:800;font-size:.7rem;z-index:3;
  box-shadow:0 2px 8px rgba(19,35,63,.5)}
.startflag{position:absolute;left:-2px;top:0;bottom:0;width:5px;
  background:var(--gold);border-radius:5px 0 0 5px;z-index:2}
.endflag{position:absolute;right:-2px;top:0;bottom:0;width:5px;
  background:var(--xred);border-radius:0 5px 5px 0;z-index:2}
.maprow + .mapends{display:flex;justify-content:space-between;
  font-size:.72rem;color:var(--ink-dim);margin:0 0 1rem}
.mapends b{font-family:var(--display);color:var(--ink)}

/* awakened forms, face up above the deck, off the mat */
.awakerow{display:flex;justify-content:flex-end;align-items:flex-end;gap:.25rem;
  margin:0 0 .35rem;padding-right:2%}
.awakerow .aw{width:8%;min-width:44px;line-height:0}
.awakerow .aw img{width:100%;border-radius:3px;display:block;
  box-shadow:0 2px 7px rgba(19,35,63,.4)}
.awakerow .awlbl{font-family:var(--display);font-size:.7rem;font-weight:700;
  color:var(--royal);align-self:center;text-align:right;margin-right:.3rem;
  line-height:1.25;max-width:11rem}

/* the mat itself */
.mat{position:relative;line-height:0;border-radius:12px;overflow:hidden;
  box-shadow:var(--shadow-2)}
.mat > img.matimg{width:100%;display:block}
/* zone outlines, so the reader can see the boxes the cards are sitting in */
.zbox{position:absolute;border:2px solid rgba(255,255,255,.9);border-radius:8px;
  box-shadow:0 0 0 1px rgba(19,35,63,.25);z-index:1}
.zname{position:absolute;font-family:var(--display);font-weight:800;
  font-size:.72rem;color:#fff;background:rgba(12,42,104,.86);
  padding:.16rem .45rem;border-radius:5px;white-space:nowrap;z-index:4;
  transform:translate(-50%,-50%);letter-spacing:.02em}

.boardnote{font-size:.85rem;color:var(--ink-dim);margin:.6rem 0 0;line-height:1.5}

/* Phones cannot show a 1.79 landscape mat with legible 0.72rem labels. Below
   680px the mat scrolls sideways at a fixed width instead of shrinking into
   illegibility, which is better than a diagram nobody can read. */
@media (max-width:680px){
  .boardscroll{overflow-x:auto;-webkit-overflow-scrolling:touch;
    padding-bottom:.5rem}
  .boardscroll > .boardinner{width:660px}
  .scrollhint{font-size:.8rem;color:var(--ink-faint);margin:.3rem 0 0}
}
@media (min-width:681px){ .scrollhint{display:none} }

/* ==================== STAGE 1 / STAGE 2 ====================
   Aidan: "put a red circle around the evolution box ... any Geopal with that
   needs to go in the awakened pile not in the deck". The box is the small
   thumbnail of the previous form at the bottom left of the artwork. Measured
   off Card_14 at 620x845: left 10.5%, top 50%, w 9.5%, h 10%. Padded a little
   so the ring sits outside the art rather than on it. */
.evorow{display:grid;gap:1rem;margin:0 0 .9rem;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,210px),1fr))}
.evocard{position:relative;margin:0;line-height:0}
.evoshot > img{width:100%;border-radius:8px;display:block;box-shadow:var(--shadow-2)}
/* ⚠ MEASURED off Card_14 at 620x845. The stage box is the small thumbnail plus
   its STAGE label bar, occupying x 68-122 and y 430-495, so it is 8.7% wide and
   7.7% tall with its centre at 16.0% / 54.7%. The ring is that box plus a little
   padding. The first attempt used 15.5% x 17% and Aidan called it "some weird
   oval thing", correctly: it was more than twice the height of the thing it was
   supposed to be pointing at and it swallowed the ABILITY banner.
   Every Geopal card uses the same template, so these numbers hold for all of
   them. Verify any change by compositing the ring in PowerShell and looking. */
.evoring{position:absolute;left:9.3%;top:49.3%;width:13.4%;height:10.8%;
  border:3px solid var(--xred);border-radius:50%;z-index:2;
  box-shadow:0 0 0 2px rgba(255,255,255,.75),0 0 12px rgba(216,51,47,.45);
  animation:evopulse 2.4s ease-in-out infinite}
@keyframes evopulse{
  0%,100%{transform:scale(1);opacity:1}
  50%    {transform:scale(1.08);opacity:.82}
}
@media (prefers-reduced-motion:reduce){ .evoring{animation:none} }
.evocard figcaption{margin-top:.5rem;font-family:var(--display);
  color:var(--royal);font-size:.95rem;line-height:1.3}
.evocard figcaption span{display:block;font-family:var(--body);font-weight:400;
  color:var(--ink-dim);font-size:.85rem}
.evocard.plain .evoring{display:none}
.evocard.plain figcaption{color:var(--ink-dim)}

/* ==================== WALKING THE TILES ====================
   A real terrain card with a real token stepping tile to tile. The old version
   was four dashed rectangles and a blue dot, which taught nothing. */
.walkfig{position:relative;line-height:0;margin:0 0 .5rem}
.walkfig img.terr{width:100%;display:block;border-radius:10px;
  box-shadow:var(--shadow-2)}
.walkfig .token{position:absolute;top:51%;width:15%;aspect-ratio:1;
  transform:translate(-50%,-50%);
  animation:walk5 7.2s steps(1,end) infinite}
/* steps(1,end) because a Geopal does not glide between tiles, it lands on one.
   The keyframe percentages hold each tile for an equal share of the loop. */
@keyframes walk5{
  0%,18%  {left:13.9%}
  20%,38% {left:30.9%}
  40%,58% {left:48.9%}
  60%,78% {left:68.3%}
  80%,98% {left:87.8%}
  100%    {left:13.9%}
}
@media (prefers-reduced-motion:reduce){
  .walkfig .token{animation:none;left:48.9%}
}
.tilenums{display:grid;grid-template-columns:repeat(5,1fr);margin:.35rem 0 0}
.tilenums span{text-align:center;font-family:var(--display);font-weight:700;
  font-size:.78rem;color:var(--ink-dim)}

/* ==================== THE ZIPPO SCENE ====================
   One Geopal, three kinds of ground, annotated on the map itself instead of in
   three cards beside it. Zippo is Volcanic and is weak to Ocean and Ice, which
   is printed on the card and confirmed by Jenny's terrain weakness chart. Do
   not change the regions here without rechecking both. */
.zscene{background:var(--paper);border:1px solid var(--rule);border-radius:16px;
  padding:1.1rem;margin:0 0 1.1rem;box-shadow:0 2px 10px rgba(19,35,63,.07)}
.zhead{display:grid;grid-template-columns:118px 1fr;gap:1rem;align-items:center;
  margin:0 0 1rem}
.zhead img{width:100%;border-radius:8px;display:block;box-shadow:var(--shadow-2)}
.zhead h4{font-family:var(--display);margin:0 0 .3rem;color:var(--royal);
  font-size:1.05rem}
.zhead p{margin:0 0 .4rem;color:var(--ink-dim);font-size:.9rem;line-height:1.45}
.zhead p:last-child{margin-bottom:0}
.ztag{display:inline-block;font-family:var(--display);font-weight:700;
  font-size:.72rem;padding:.15rem .5rem;border-radius:20px;margin-right:.3rem}
.ztag.home{background:rgba(63,158,90,.16);color:#2f7a45}
.ztag.weak{background:rgba(216,51,47,.14);color:var(--xred)}

.zmap{display:grid;grid-template-columns:repeat(3,1fr);gap:.5rem}
.zpanel{margin:0;position:relative;line-height:0}
.zshot > img{width:100%;display:block;border-radius:8px}
.zpanel.home .zshot > img{box-shadow:0 0 0 3px #3f9e5a,0 4px 12px rgba(19,35,63,.28)}
.zpanel.norm .zshot > img{box-shadow:0 0 0 3px var(--ink-faint),0 4px 12px rgba(19,35,63,.28)}
.zpanel.stop .zshot > img{box-shadow:0 0 0 3px var(--xred),0 4px 12px rgba(19,35,63,.28)}
.zpanel .token{position:absolute;top:51%;width:22%;aspect-ratio:1;
  transform:translate(-50%,-50%);z-index:3}
/* the barrier drawn across ground Zippo cannot enter */
.zbar{position:absolute;inset:0;border-radius:8px;z-index:2;
  background:repeating-linear-gradient(135deg,rgba(216,51,47,.30) 0 10px,
             rgba(216,51,47,.06) 10px 20px)}
.zcap{margin:.5rem 0 0;line-height:1.4}
.zcap b{display:block;font-family:var(--display);font-size:.9rem}
.zpanel.home .zcap b{color:#2f7a45}
.zpanel.norm .zcap b{color:var(--ink)}
.zpanel.stop .zcap b{color:var(--xred)}
.zcap span{font-size:.83rem;color:var(--ink-dim)}
@media (max-width:620px){ .zmap{grid-template-columns:1fr} .zhead{grid-template-columns:92px 1fr} }

/* ==================== THE FOUR CLASSES ====================
   Aidan, 2026-08-24: Supporters are slow but carry the team, and that was not
   explained anywhere. Max Stamina averages come from cards.json and are real:
   Runner 3.0, All Rounder 2.2, Supporter 1.0, Chaser 5.0. */
.classlist{display:grid;gap:1rem;margin:0 0 1rem}
.classrow{display:grid;grid-template-columns:104px 1fr;gap:1rem;
  background:var(--paper);border:1px solid var(--rule);border-left:4px solid var(--royal-2);
  border-radius:14px;padding:1rem;align-items:start}
.classrow.sup{border-left-color:#3f9e5a}
.classrow.all{border-left-color:var(--gold)}
.classrow.cha{border-left-color:#8b5cd6}
.classrow > img{width:100%;border-radius:7px;display:block;box-shadow:var(--shadow-2)}
.classrow h4{font-family:var(--display);margin:0 0 .1rem;font-size:1.05rem;color:var(--ink)}
.classrow .sta{font-family:var(--display);font-size:.74rem;font-weight:700;
  color:var(--ink-faint);display:block;margin-bottom:.45rem}
.classrow p{margin:0 0 .55rem;color:var(--ink-dim);font-size:.92rem;line-height:1.5}
.classrow p:last-child{margin-bottom:0}
.classrow .quote{background:var(--sky);border-radius:9px;padding:.55rem .7rem;
  font-size:.86rem;color:var(--ink);line-height:1.45}
.classrow .quote b{font-family:var(--display);color:var(--royal)}
@media (max-width:560px){ .classrow{grid-template-columns:76px 1fr;gap:.7rem} }

/* ==================== WEAKNESS CHART ====================
   Straight out of Jenny's _TERRAIN WEAKNESS CHART.png. It was only ever on
   Drive, so nobody who bought a deck could see it. */
.weaktab{width:100%;border-collapse:collapse;font-size:.9rem;margin:0 0 1rem}
.weaktab th,.weaktab td{padding:.5rem .6rem;text-align:left;
  border-bottom:1px solid var(--rule)}
.weaktab th{font-family:var(--display);color:var(--royal);font-size:.82rem;
  text-transform:uppercase;letter-spacing:.04em}
.weaktab td:first-child{font-family:var(--display);font-weight:700;color:var(--ink)}
.weaktab td:not(:first-child){color:var(--xred)}
.weaktab tr:last-child td{border-bottom:0}
/* ==================== THE HOST ====================
   Aidan, 2026-08-24: Nilgie fronts the tutorial. Second pass, same day, after
   "this is clunky ... the mascot isn't well integrated it should be transparent
   and larger less boxed in with the text".

   So: no card, no border, no speech bubble. He sits on the page background at
   a size that reads as a character rather than an avatar, and the copy runs
   beside him. The image is the SAME feathered cutout the home page uses, reused
   rather than cut out again; see the host section of build-learn-assets.ps1. It
   has a real alpha channel, which is what lets the panel disappear. */
.host{display:grid;grid-template-columns:200px 1fr;gap:.4rem;align-items:center;
  margin:.4rem 0 1.6rem}
.host > img{width:100%;display:block;
  /* A soft ground shadow instead of a container. Keeps him from floating. */
  filter:drop-shadow(0 14px 18px rgba(19,35,63,.20))}
.hostsay p{margin:0 0 .6rem;color:var(--ink-dim);line-height:1.6}
.hostsay p:last-child{margin-bottom:0}
.hostsay .hi{font-family:var(--display);font-size:1.32rem;line-height:1.35;
  color:var(--ink);font-weight:700}
@media (max-width:620px){
  /* Below this the two columns squeeze the text to a ribbon, so he goes above
     it at a size that still reads. */
  .host{grid-template-columns:1fr;gap:0;justify-items:center;text-align:center;
    margin-bottom:1.3rem}
  .host > img{width:180px}
  .hostsay .hi{font-size:1.2rem}
}
/* ---- the opponent's side of the table ----
   Rotated 180 degrees because that is how a mat faces you across a real table,
   and their cards really are upside down from where you sit. Dimmed and
   slightly shrunk so the eye lands on your own mat, which is the one being
   taught. Aidan, 2026-08-24: both current mat designs, laid out the way
   Tabletop Simulator shows a table. */
.mat.opp{transform:rotate(180deg);opacity:.62;width:88%;margin:0 auto .9rem;
  filter:saturate(.85)}
.blabel.opp{color:var(--ink-faint)}
.blabel.opp span{color:var(--ink-faint)}
/* The rotation would flip the zone labels too, so the opponent's mat carries
   none. It is scenery. */
.mat.opp .zname{display:none}
/* Awakened forms sit ON the mat, directly above the Deck. Aidan, 2026-08-24:
   "these should be on your playmat directly above your deck", and then
   "not in open space above the playmat". A slight fan so three cards read as a
   waiting pile rather than one card with odd edges. */
.onboard.awake img{box-shadow:0 2px 8px rgba(19,35,63,.5)}
.onboard.awake:nth-of-type(1){transform:rotate(-4deg)}
.onboard.awake:nth-of-type(3){transform:rotate(4deg)}
/* Superseded by the above. The row that floated above the mat was wrong: there
   is clear space on the mat itself between the Trap Zone and the Deck. */
.awakerow{display:none}
/* ---- tokens weighted to their owner's side of the map ----
   Aidan, 2026-08-24. On a real table your tokens sit toward your edge of the
   terrain strip and your opponent's toward theirs. Without this they pile into
   one line and you cannot tell whose is whose. */
.mapcard .token.you{top:68%}
.mapcard .token.opp{top:32%;box-shadow:0 0 0 1.5px #fff,0 0 0 3px var(--xred),
  0 2px 6px rgba(19,35,63,.4)}

/* ---- the Trap marker, and the arrow tying it to the card in the Trap Zone ----
   One Trap per Terrain card is the rule, so the board shows exactly one. */
.trapmark{position:absolute;top:51%;transform:translate(-50%,-50%);
  z-index:4;display:grid;justify-items:center;gap:2px;width:0}
.trapmark .tm-dot{width:18px;height:18px;border-radius:50%;
  background:rgba(216,51,47,.95);border:2px solid #fff;display:grid;
  place-items:center;color:#fff;font-family:var(--display);font-weight:800;
  font-size:.72rem;box-shadow:0 2px 8px rgba(19,35,63,.5)}
/* points down, toward the Trap Zone on the mat below */
.trapmark .tm-arrow{width:0;height:0;border:6px solid transparent;
  border-top-color:var(--xred);margin-top:1px}
.trapmark .tm-lbl{font-family:var(--display);font-weight:700;font-size:.6rem;
  color:#fff;background:rgba(216,51,47,.95);padding:.1rem .35rem;
  border-radius:4px;white-space:nowrap}
/* the matching card on the mat, ringed so the pair reads as a pair */
.onboard.traphere img{box-shadow:0 0 0 3px var(--xred),0 3px 10px rgba(19,35,63,.45)}
.mat .zname{font-size:.66rem}

/* ==================== THE TRAP ANIMATION ====================
   Aidan, 2026-08-24: "show the token move onto a tile aligned with a trap, the
   trap then flips around and the token is stuck".

   One container, so all the geometry is exact. Tile centres are the measured
   5-tile values. The token walks tiles 1, 2, 3, stops on 3, the card under
   tile 3 flips face up, and the token turns red and stays put.
   Whole loop is 9s; the phases below must stay in step with each other. */
.trapdemo{position:relative;margin:0 0 .6rem}
.trapdemo .terr{width:100%;display:block;border-radius:10px;
  box-shadow:var(--shadow-2)}
.trapdemo .token{position:absolute;top:51%;width:15%;aspect-ratio:1;
  transform:translate(-50%,-50%);z-index:3;
  animation:tdwalk 9s linear infinite}
@keyframes tdwalk{
  0%,10%   {left:13.9%;box-shadow:0 0 0 2px #fff,0 0 0 4px var(--royal),0 4px 10px rgba(19,35,63,.4)}
  11%,21%  {left:30.9%;box-shadow:0 0 0 2px #fff,0 0 0 4px var(--royal),0 4px 10px rgba(19,35,63,.4)}
  22%,33%  {left:48.9%;box-shadow:0 0 0 2px #fff,0 0 0 4px var(--royal),0 4px 10px rgba(19,35,63,.4)}
  /* trapped from here on: ringed red, and it does not move again */
  34%,95%  {left:48.9%;box-shadow:0 0 0 2px #fff,0 0 0 5px var(--xred),0 0 16px rgba(216,51,47,.7)}
  100%     {left:13.9%;box-shadow:0 0 0 2px #fff,0 0 0 4px var(--royal),0 4px 10px rgba(19,35,63,.4)}
}
/* the card sitting under the trapped tile */
.trapdemo .flip{position:absolute;left:48.9%;top:100%;width:20%;
  margin-top:1.6rem;transform:translateX(-50%);perspective:800px;z-index:2}
/* ⚠ display:block is load-bearing. These are spans, and aspect-ratio does not
   apply to an inline box, so without it the card has no height and never
   appears at all. That is exactly what happened first time round. */
.trapdemo .flipin{position:relative;display:block;width:100%;
  aspect-ratio:900/1226;
  transform-style:preserve-3d;animation:tdflip 9s ease-in-out infinite}
@keyframes tdflip{
  0%,33%  {transform:rotateY(0deg)}
  44%,95% {transform:rotateY(180deg)}
  100%    {transform:rotateY(0deg)}
}
.trapdemo .face{position:absolute;inset:0;display:block;
  backface-visibility:hidden;-webkit-backface-visibility:hidden;
  border-radius:5px;overflow:hidden;box-shadow:0 4px 12px rgba(19,35,63,.45)}
.trapdemo .face img{width:100%;display:block}
.trapdemo .face.back{transform:rotateY(180deg)}
/* the dashed line joining the tile to its card */
.trapdemo .join{position:absolute;left:48.9%;top:51%;height:calc(49% + 1.6rem);width:0;
  border-left:2px dashed var(--xred);z-index:1}
.trapdemo .say{position:absolute;left:50%;top:-14%;transform:translateX(-50%);
  font-family:var(--display);font-weight:700;font-size:.8rem;color:#fff;
  background:var(--xred);padding:.2rem .6rem;border-radius:20px;
  white-space:nowrap;opacity:0;animation:tdsay 9s ease-in-out infinite}
@keyframes tdsay{
  0%,36%  {opacity:0;transform:translateX(-50%) translateY(6px)}
  46%,92% {opacity:1;transform:translateX(-50%) translateY(0)}
  100%    {opacity:0;transform:translateX(-50%) translateY(6px)}
}
/* room for the card hanging below, and for the caption above */
.trapdemo-wrap{padding:2.4rem 0 10.5rem}
@media (prefers-reduced-motion:reduce){
  .trapdemo .token{animation:none;left:48.9%;
    box-shadow:0 0 0 2px #fff,0 0 0 5px var(--xred)}
  .trapdemo .flipin{animation:none;transform:rotateY(180deg)}
  .trapdemo .say{animation:none;opacity:1}
}
/* ---- region symbols ----
   The eight region orbs off Drive, at Aidan's suggestion, 2026-08-24. They were
   only ever on Drive, so nobody who bought a deck had seen the set together.
   Source PNGs are 3000x4000 with the orb centred, hence object-fit. */
.rsym{display:inline-flex;align-items:center;gap:.4rem;white-space:nowrap}
.rsym img{width:26px;height:26px;object-fit:contain;flex:none}
.weaktab td:not(:first-child) .rsym{color:var(--xred)}
.ztag{display:inline-flex;align-items:center;gap:.3rem}
.ztag img{width:18px;height:18px;object-fit:contain}
@media (max-width:520px){
  .weaktab{font-size:.82rem}
  .weaktab th,.weaktab td{padding:.4rem .3rem}
  .rsym img{width:20px;height:20px}
}

/* ---- weak region: onto the first tile, not into limbo ----
   Aidan, 2026-08-24: "if a Geopal is weak in a region it goes to the first tile
   and is stuck there, it doesn't land in limbo". The barrier therefore starts
   AFTER the first tile of the 3-tile card, so the panel shows ground the Geopal
   can stand on and ground it cannot reach. */
.zbar{left:35%;right:0;top:0;bottom:0;inset:auto;
  border-radius:0 8px 8px 0}
/* ==================== STEP NAVIGATION ====================
   Rewritten 2026-08-24. The tutorial used to reveal steps one at a time with no
   way back, and opening a finished step hid the header you would have clicked
   to close it again. Aidan asked for a toggle and for free movement between
   phases, so every step is now reachable and every header is a real toggle. */

/* the jump bar */
.stepchips{display:flex;flex-wrap:wrap;gap:.4rem;margin:0 0 1.1rem}
.chip{display:inline-flex;align-items:center;gap:.4rem;cursor:pointer;
  font-family:var(--display);font-size:.84rem;font-weight:700;
  color:var(--ink-dim);background:var(--paper);border:1px solid var(--rule);
  border-radius:22px;padding:.42rem .8rem;line-height:1;
  transition:background .15s,color .15s,border-color .15s}
.chip b{display:grid;place-items:center;width:19px;height:19px;border-radius:50%;
  background:var(--mist);color:var(--ink-dim);font-size:.72rem}
.chip:hover{border-color:var(--royal-2);color:var(--royal)}
.chip.seen b{background:#3f9e5a;color:#fff}
.chip.now{background:var(--royal);border-color:var(--royal);color:#fff}
.chip.now b{background:var(--gold);color:var(--royal-3)}
@media (max-width:560px){
  .chip{font-size:.76rem;padding:.36rem .6rem}
}

/* the header of each step, always present, always clickable */
.stepdone{cursor:pointer;width:100%;text-align:left;display:grid;
  grid-template-columns:auto 1fr auto;align-items:center;gap:.6rem;
  background:var(--paper);border:1px solid var(--rule);border-radius:14px;
  padding:.85rem 1rem;margin:0 0 .5rem;font-family:var(--body);
  transition:border-color .15s,box-shadow .15s}
.stepdone:hover{border-color:var(--royal-2)}
.stepdone b{font-family:var(--display);font-size:1.02rem;color:var(--ink)}
.stepdone .sum{grid-column:2;grid-row:2;font-size:.8rem;color:var(--ink-dim);margin-left:0;text-align:left;justify-self:start}
.stepdone .tick{display:grid;place-items:center;width:26px;height:26px;
  grid-row:1 / span 2;border-radius:50%;background:var(--mist);
  color:var(--ink-faint);font-size:.85rem;font-weight:800}
.step.is-done .stepdone .tick{background:#3f9e5a;color:#fff}
.step.is-open > .stepdone{border-color:var(--royal);
  box-shadow:0 0 0 1px var(--royal)}
/* the chevron is the affordance that says this thing opens and closes */
.stepdone .chev{grid-row:1 / span 2;width:11px;height:11px;
  border-right:2px solid var(--ink-faint);border-bottom:2px solid var(--ink-faint);
  transform:rotate(45deg);margin-right:4px;transition:transform .2s}
.step.is-open > .stepdone .chev{transform:rotate(-135deg);
  border-color:var(--royal)}

/* Back and Next */
.stepnav{display:flex;flex-wrap:wrap;gap:.6rem;align-items:center;
  margin-top:1.4rem}
.backbtn{cursor:pointer;font-family:var(--display);font-weight:700;
  font-size:.95rem;color:var(--ink-dim);background:transparent;
  border:1px solid var(--rule);border-radius:26px;padding:.7rem 1.2rem}
.backbtn:hover{border-color:var(--royal-2);color:var(--royal)}
.stepnav .nextbtn{margin-top:0}
@media (prefers-reduced-motion:reduce){
  .stepdone .chev{transition:none}
}
/* ---- overlays must measure against the IMAGE, not the figure ----
   A <figure> here is image PLUS caption, so a percentage top inside it lands
   lower than intended by however tall the caption is. The evolution ring was
   sitting on the ABILITY banner instead of the stage box for exactly this
   reason, and the Zippo panels had the same fault: the token sat low and the
   red barrier ran over the caption text. Aidan, 2026-08-24, twice.
   These wrappers are the fix. Any new overlay goes inside one of them. */
.evoshot,.zshot{position:relative;display:block;line-height:0}
.evocard{position:static}
.zpanel{position:static}
.evoshot > img,.zshot > img{width:100%;display:block}
/* ---- the sum row: card + berries = tiles ----
   Aidan, 2026-08-24: relate the card to the rule being written. Zippo's own
   numbers do the explaining rather than an abstract example. */
.sumrow{display:flex;flex-wrap:wrap;align-items:center;gap:.7rem;
  background:var(--paper);border:1px solid var(--rule);border-radius:16px;
  padding:1rem;margin:0 0 .9rem}
.su{margin:0;width:104px;line-height:0;flex:none}
.su.small{width:68px}
.su img{width:100%;display:block;border-radius:6px;box-shadow:var(--shadow-2)}
.su figcaption{margin-top:.4rem;font-family:var(--display);font-size:.78rem;
  color:var(--ink);line-height:1.3}
.su figcaption span{display:block;font-family:var(--body);font-weight:400;
  color:var(--ink-dim);font-size:.72rem}
.sumrow .op{font-family:var(--display);font-size:1.5rem;font-weight:800;
  color:var(--ink-faint);flex:none}
.sures{flex:1 1 170px;min-width:150px}
.sures b{display:block;font-family:var(--display);font-size:1.6rem;
  color:var(--royal);line-height:1.1}
.sures span{display:block;margin-top:.3rem;color:var(--ink-dim);
  font-size:.87rem;line-height:1.45}
@media (max-width:560px){
  .su{width:82px} .su.small{width:56px}
  .sumrow{gap:.5rem;padding:.8rem}
  .sures b{font-size:1.35rem}
}
/* ==================== THE BOARD, BEHIND A TOGGLE ====================
   Aidan, 2026-08-24: the full table appearing unannounced was "a bit
   overwhelming". It is the densest thing on the page, so it now opens on
   request. The summary says what is inside, so nobody has to guess whether it
   is worth a tap. */
.boardbox{border:1px solid var(--rule);border-radius:16px;background:var(--paper);
  margin:0 0 1.2rem;overflow:hidden}
.boardbox > summary{cursor:pointer;list-style:none;display:flex;
  align-items:center;gap:.8rem;padding:1rem 1.1rem}
.boardbox > summary::-webkit-details-marker{display:none}
.bb-txt{flex:1 1 auto;min-width:0}
.bb-txt b{display:block;font-family:var(--display);font-size:1.02rem;
  color:var(--ink)}
.bb-txt span{display:block;font-size:.86rem;color:var(--ink-dim);
  line-height:1.4;margin-top:.15rem}
.bb-more{flex:none;display:inline-flex;align-items:center;gap:.4rem;
  font-family:var(--display);font-weight:700;font-size:.82rem;color:var(--royal);
  background:var(--sky);border-radius:20px;padding:.35rem .75rem}
/* a chevron that turns over when the panel opens */
.bb-more::after{content:"";width:7px;height:7px;
  border-right:2px solid var(--royal);border-bottom:2px solid var(--royal);
  transform:rotate(45deg) translateY(-1px);transition:transform .2s}
.boardbox[open] > summary{border-bottom:1px solid var(--rule)}
.boardbox[open] .bb-more::after{transform:rotate(-135deg) translateY(-1px)}
.boardbox[open] .bb-more{background:var(--royal);color:#fff}
.boardbox[open] .bb-more::after{border-color:#fff}
.boardbox > summary:hover .bb-more{background:var(--mist)}
.boardbox[open] > summary:hover .bb-more{background:var(--royal-2)}
.bb-body{padding:1.1rem}
/* The board already scrolls sideways on a phone, so it must not also stretch
   the panel. */
.bb-body > .boardscroll{max-width:100%}
@media (max-width:560px){
  .boardbox > summary{padding:.85rem .9rem;gap:.5rem}
  .bb-txt b{font-size:.95rem}
  .bb-txt span{font-size:.8rem}
  .bb-body{padding:.8rem}
}
@media (prefers-reduced-motion:reduce){ .bb-more::after{transition:none} }
/* ==================== THE TURN WALKTHROUGH ====================
   Aidan's design, 2026-08-24. One click-through carrying Act, Move and Draw,
   because two separate steps made movement read like a different phase of the
   game rather than the thing that ends your turn.
   The JS reparents cards between the hand, Play Zone, attachments and discard;
   everything below is just how those four places look. */
.turnwalk{border:1px solid var(--rule);border-radius:18px;background:var(--paper);
  padding:1.1rem;margin:0 0 1.2rem;box-shadow:0 2px 12px rgba(19,35,63,.07)}

/* the Act / Move / Draw indicator */
.tw-phases{display:flex;align-items:center;justify-content:center;gap:.5rem;
  margin:0 0 1rem}
.tw-ph{font-family:var(--display);font-weight:800;font-size:.8rem;
  text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint);
  background:var(--sky);border-radius:20px;padding:.32rem .8rem;
  transition:background .2s,color .2s}
.tw-arrow{width:0;height:0;border:5px solid transparent;
  border-left-color:var(--rule)}
.turnwalk[data-phase="act"]  .tw-ph[data-ph="act"],
.turnwalk[data-phase="move"] .tw-ph[data-ph="move"],
.turnwalk[data-phase="draw"] .tw-ph[data-ph="draw"]{
  background:var(--royal);color:#fff}

.tw-zlbl{display:block;font-family:var(--display);font-weight:700;
  font-size:.72rem;text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-faint);margin:0 0 .35rem}

/* the map */
.tw-map{margin:0 0 .9rem}
.tw-terr{position:relative;display:block;line-height:0;max-width:330px}
.tw-terr img{width:100%;display:block;border-radius:8px;
  box-shadow:0 3px 10px rgba(19,35,63,.28)}
.tw-tok{position:absolute;top:51%;width:17%;aspect-ratio:1;
  transform:translate(-50%,-50%);border-radius:50%;overflow:hidden;
  display:grid;place-items:center;
  background:radial-gradient(circle at 50% 38%,#fff,#e8eef8);
  box-shadow:0 0 0 1.5px #fff,0 0 0 3px var(--royal),0 2px 6px rgba(19,35,63,.4);
  transition:left .55s cubic-bezier(.5,0,.4,1)}
.tw-tok img{width:96%;height:96%;object-fit:contain}

/* play zone and discard */
.tw-zones{display:flex;gap:1rem;align-items:flex-start;margin:0 0 .9rem;
  flex-wrap:wrap}
.tw-play{flex:1 1 240px;min-width:0}
.tw-disc{flex:none}
.tw-playin{display:flex;gap:.5rem;align-items:flex-start}
.tw-slot{min-width:74px;min-height:100px;border:2px dashed var(--rule);
  border-radius:10px;display:flex;gap:.3rem;padding:.3rem;align-items:flex-start}
.tw-slot.small{min-width:60px;min-height:82px}
.tw-slot.has{border-style:solid;border-color:var(--mist)}
.tw-empty{font-size:.7rem;color:var(--ink-faint);align-self:center;
  margin:0 auto;font-style:italic}
.tw-slot.has .tw-empty{display:none}
.tw-att{display:flex;gap:.3rem;flex-wrap:wrap;padding-top:.3rem}

/* the hand */
.tw-handwrap{margin:0 0 .9rem}
.tw-hand{display:flex;gap:.35rem;flex-wrap:wrap;min-height:96px;
  transition:opacity .3s,filter .3s}
.turnwalk.is-locked .tw-hand{opacity:.4;filter:grayscale(.8)}
.tw-lock{display:inline-flex;align-items:center;gap:.4rem;margin-top:.5rem;
  font-family:var(--display);font-weight:700;font-size:.78rem;color:var(--xred);
  background:rgba(216,51,47,.10);border-radius:20px;padding:.3rem .7rem}
.tw-lock::before{content:"";width:9px;height:11px;border-radius:2px;
  background:var(--xred);box-shadow:0 -4px 0 -1px transparent,
  inset 0 0 0 99px var(--xred)}

/* a card, wherever it happens to be */
.tw-card{display:block;width:68px;line-height:0;flex:none}
.tw-slot > .tw-card{width:70px}
.tw-att > .tw-card{width:44px}
.tw-card img{width:100%;display:block;border-radius:5px;
  box-shadow:0 2px 7px rgba(19,35,63,.32)}
.tw-card.just{animation:twjust .85s ease-out}
@keyframes twjust{
  0%   {transform:scale(1.14);box-shadow:0 0 0 4px var(--gold)}
  60%  {transform:scale(1);box-shadow:0 0 0 4px rgba(245,179,36,.55)}
  100% {transform:scale(1);box-shadow:0 0 0 0 rgba(245,179,36,0)}
}


/* the caption and the rule it teaches */
.tw-say{background:var(--sky);border-radius:12px;padding:.9rem 1rem;
  margin:0 0 .9rem}
.tw-say b{display:block;font-family:var(--display);font-size:1.05rem;
  color:var(--ink);margin-bottom:.3rem}
.tw-say p{margin:0;color:var(--ink-dim);line-height:1.55;font-size:.94rem}
.tw-rule{margin-top:.6rem !important;padding-top:.6rem;
  border-top:1px solid var(--rule);color:var(--royal) !important;
  font-weight:600}

/* controls */
.tw-nav{display:flex;align-items:center;gap:.7rem;flex-wrap:wrap}
.tw-btn{cursor:pointer;font-family:var(--display);font-weight:700;
  font-size:.95rem;color:#fff;background:var(--royal);border:0;
  border-radius:26px;padding:.68rem 1.4rem}
.tw-btn:hover{background:var(--royal-2)}
.tw-btn.ghost{background:transparent;color:var(--ink-dim);
  border:1px solid var(--rule)}
.tw-btn.ghost:hover{background:var(--sky);color:var(--royal)}
.tw-btn:disabled{opacity:.35;cursor:default}
.tw-btn:disabled:hover{background:transparent}
.tw-count{font-family:var(--display);font-size:.82rem;color:var(--ink-faint);
  margin-left:auto}
.turnwalk.is-done{border-color:#3f9e5a;box-shadow:0 0 0 1px #3f9e5a}

@media (max-width:560px){
  .turnwalk{padding:.85rem}
  .tw-card{width:54px}
  .tw-slot > .tw-card{width:58px}
  .tw-att > .tw-card{width:38px}
  .tw-hand{min-height:78px}
  .tw-ph{font-size:.7rem;padding:.28rem .6rem}
  .tw-btn{padding:.6rem 1rem;font-size:.88rem}
  .tw-count{width:100%;margin-left:0;text-align:right}
}
@media (prefers-reduced-motion:reduce){
  .tw-tok{transition:none}
  .tw-card.just{animation:none}
  .turnwalk.show-ability .tw-slot .tw-card::after{animation:none}
}
/* ==================== [hidden] MUST WIN ====================
   Added 2026-08-24 after eleven cards showed in a six card hand.

   The walkthrough hides cards with the `hidden` attribute, which the browser
   implements as a LOW PRIORITY display:none in its own stylesheet. Any author
   rule that sets display, such as .tw-card{display:block}, beats it, so the
   element stays on screen no matter what the JS does. The undrawn cards never
   disappeared and the "hand locked" badge showed from the first stage.

   This makes the attribute mean what everyone assumes it means. Keep it near
   the end of the file, and never set display on an element you also hide with
   the attribute without checking this rule still applies. */
[hidden]{display:none !important}

/* The one line summary under each step title. An older .stepdone block set
   .sum to display:none and the newer block never turned it back on, so the
   headers were showing a title with no description. */
.stepdone .sum{display:block}
/* ---- the magnifier ----
   A 68px card in a hand is unreadable, so when a stage turns on a card's text
   this shows that strip of the card at full panel width. Aidan, 2026-08-24:
   "magnify so we can read what the ability / action cards say".

   --zt and --zb are the top and bottom of the strip as a percentage of CARD
   HEIGHT. 1.362 is the card ratio, 1226/900. Both padding-top and margin-top
   percentages resolve against the container WIDTH, which is what lets the strip
   keep its proportions at any size. Do not swap margin-top for top: that one
   resolves against height and the strip lands in the wrong place.

   Measured strips:
     Geopal passive ability  58 to 72
     Geopal active ability   74 to 88
     Geopal Max Stamina       3 to 16
     Action and Item EFFECT  66 to 89 */
.tw-focus{background:var(--sky);border:1px solid var(--rule);border-radius:12px;
  padding:.7rem;margin:0 0 .9rem}
.tw-zoom{position:relative;display:block;overflow:hidden;width:100%;
  border-radius:8px;background:var(--mist);
  padding-top:calc(1.362% * (var(--zb) - var(--zt)));
  box-shadow:inset 0 0 0 2px var(--gold)}
.tw-zoom img{position:absolute;left:0;top:0;width:100%;display:block;
  margin-top:calc(-1.362% * var(--zt))}
.tw-focuscap{display:block;margin-top:.55rem;font-size:.88rem;
  color:var(--ink-dim);line-height:1.5}
@media (max-width:560px){
  .tw-focus{padding:.55rem}
  .tw-focuscap{font-size:.82rem}
}
/* ---- the walkthrough map: two grounds and a Trap ----
   Magma Burst turns the Forest card Volcanic, so both images are stacked and
   the Volcanic one is revealed. Both are 5-tile cards, so the measured tile
   centres hold either way.
   The Trap sits on tile 3, which is where Overburn lands Zippo. That is what
   makes equipping Sense earlier in the same turn worth doing. */
.tw-terr{position:relative;display:block;line-height:0;max-width:360px}
.tw-t{width:100%;display:block;border-radius:8px;
  box-shadow:0 3px 10px rgba(19,35,63,.28)}
.tw-t.volc{position:absolute;left:0;top:0}
.tw-trap{position:absolute;left:68.3%;top:51%;transform:translate(-50%,-50%);
  width:20px;height:20px;border-radius:50%;display:grid;place-items:center;
  color:#fff;font-family:var(--display);font-weight:800;font-size:.72rem;
  border:2px solid #fff;z-index:4;box-shadow:0 2px 8px rgba(19,35,63,.5);
  transition:background .3s,transform .3s}
.tw-trap.is-set{background:rgba(216,51,47,.92)}
.tw-trap.is-sprung{background:var(--xred);transform:translate(-50%,-50%) scale(1.35);
  box-shadow:0 0 0 5px rgba(216,51,47,.35),0 2px 8px rgba(19,35,63,.5)}
.tw-trap.is-saved{background:#3f9e5a}
@media (prefers-reduced-motion:reduce){ .tw-trap{transition:none} }
/* ---- no orphan words ----
   Aidan, 2026-08-24: "remove overhanging words like 'of it'". Rather than
   hand-tuning every sentence, this asks the browser not to leave a single word
   stranded on the last line, and to balance headings across their lines.
   Browsers without support simply wrap as before, so it costs nothing. */
h1,h2,h3,h4,.tw-say b,.bb-txt b{text-wrap:balance}
p,li,figcaption,.sub,.lede,.tw-say p,.tw-focuscap,.zcap span{text-wrap:pretty}
/* ---- step headers: explicit grid placement ----
   The title and the one line summary were auto-placing and drifting right.
   Pinning every child to a cell fixes the ragged look. */
.stepdone{grid-template-columns:auto 1fr auto;column-gap:.75rem;row-gap:.15rem}
.stepdone .tick{grid-column:1;grid-row:1 / span 2}
.stepdone b{grid-column:2;grid-row:1;text-align:left}
.stepdone .sum{grid-column:2;grid-row:2;text-align:left;display:block}
.stepdone .chev{grid-column:3;grid-row:1 / span 2;justify-self:end}

/* ---- the trap, drawn as the face-down card it actually is ---- */
.tw-terr{display:flex;gap:1%;position:relative}
.tw-card2{position:relative;display:block;flex:1 1 0;line-height:0}
.tw-trap{position:absolute;left:33.81%;top:26%;transform:translate(-50%,-50%);
  width:11%;z-index:4;display:grid;justify-items:center;gap:3px}
.tw-trapcard{position:relative;display:block;width:100%;aspect-ratio:900/1226;
  transform-style:preserve-3d;transition:transform .55s ease-in-out}
.tw-trap.is-sprung .tw-trapcard,
.tw-trap.is-saved  .tw-trapcard{transform:rotateY(180deg)}
.tw-trapcard .tf{position:absolute;inset:0;display:block;border-radius:3px;
  overflow:hidden;backface-visibility:hidden;-webkit-backface-visibility:hidden;
  box-shadow:0 2px 7px rgba(19,35,63,.5)}
.tw-trapcard .tf img{width:100%;display:block}
.tw-trapcard .tf.back{transform:rotateY(180deg)}
.tw-traplbl{font-family:var(--display);font-weight:800;font-size:.52rem;
  letter-spacing:.02em;color:#fff;background:var(--xred);padding:.1rem .3rem;
  border-radius:4px;white-space:nowrap;line-height:1.3}
.tw-trap.is-saved .tw-traplbl{background:#3f9e5a}
/* the token sits low on the tile so it never covers the Trap above it */
.tw-tok{top:70%}
@media (prefers-reduced-motion:reduce){ .tw-trapcard{transition:none} }
@media (max-width:560px){ .tw-traplbl{font-size:.46rem} }
/* ---- the Trap sits BELOW its tile, not on top of it ----
   Aidan, 2026-08-24: "the trap is supposed to be placed below region tile not
   on it". It is a card on the table, lined up under the tile it is assigned to,
   with a short dashed tether so the link is obvious. That also frees the tile
   itself for the token, which no longer has to dodge anything. */
.tw-map{position:relative;padding-bottom:5.6rem}
.tw-trap{position:absolute;left:33.81%;top:100%;width:8%;min-width:34px;
  margin-top:.55rem;transform:translateX(-50%);z-index:4;
  display:grid;justify-items:center;gap:3px}
.tw-trap::before{content:"";position:absolute;bottom:100%;left:50%;
  height:.55rem;border-left:2px dashed var(--xred);transform:translateX(-50%)}
/* the token no longer competes with the Trap for the tile */
.tw-tok{width:12%;top:51%}
@media (max-width:560px){
  .tw-map{padding-bottom:4.6rem}
  .tw-tok{width:14%}
}
/* ==================== THE MID-GAME RULES ASSISTANT ====================
   Aidan asked for a chatbot for mid-game questions, 2026-08-24. This is the
   version that can exist today: the whole register searched in the browser.
   Big touch targets and high contrast, because it is used at a table with a
   phone in one hand. */
.askbox{position:relative;margin:0 0 .9rem}
.askbox input{width:100%;font:inherit;font-size:1.1rem;padding:1rem 1.1rem;
  border:2px solid var(--rule);border-radius:14px;background:var(--paper);
  color:var(--ink)}
.askbox input:focus{outline:none;border-color:var(--royal);
  box-shadow:0 0 0 3px rgba(30,91,198,.15)}
.askcount{position:absolute;right:1rem;top:50%;transform:translateY(-50%);
  font-family:var(--display);font-size:.8rem;color:var(--ink-faint);
  pointer-events:none;background:var(--paper);padding-left:.5rem}

.chips{display:flex;flex-wrap:wrap;gap:.4rem;margin:0 0 1.6rem}
.chips button{cursor:pointer;font-family:var(--display);font-weight:700;
  font-size:.82rem;color:var(--ink-dim);background:var(--paper);
  border:1px solid var(--rule);border-radius:20px;padding:.4rem .8rem}
.chips button:hover{border-color:var(--royal-2);color:var(--royal)}

.rhead{font-family:var(--display);font-size:.78rem;text-transform:uppercase;
  letter-spacing:.07em;color:var(--ink-faint);margin:1.6rem 0 .7rem;
  display:flex;align-items:baseline;gap:.6rem}
.rhead:first-child{margin-top:0}
.rhead span{font-family:var(--body);font-weight:400;text-transform:none;
  letter-spacing:0;font-size:.8rem}

.rulecard{background:var(--paper);border:1px solid var(--rule);
  border-left:4px solid var(--royal-2);border-radius:14px;padding:1rem 1.1rem;
  margin:0 0 .7rem}
/* A principle looks different on purpose. It is a different kind of answer:
   not "here is the rule" but "here is how to decide when there is no rule". */
.rulecard.principle{border-left-color:var(--gold);background:rgba(245,179,36,.06)}
.rulecard.open{border-left-color:var(--xred);background:rgba(216,51,47,.05)}
.rmeta{display:block;font-family:var(--display);font-weight:700;font-size:.72rem;
  text-transform:uppercase;letter-spacing:.05em;color:var(--ink-faint);
  margin-bottom:.4rem}
.rulecard.principle .rmeta{color:#9a6f10}
.rulecard.open .rmeta{color:var(--xred)}
.rstate{margin:0;font-size:1.04rem;line-height:1.5;color:var(--ink);
  font-weight:600}
.rdetail{margin:.5rem 0 0;font-size:.92rem;line-height:1.55;color:var(--ink-dim)}
.ropen{margin:.6rem 0 0;font-size:.88rem;line-height:1.5;color:var(--xred);
  font-weight:600}
.rnone{color:var(--ink-dim);line-height:1.6;max-width:60ch}

.askempty{background:var(--sky);border-radius:14px;padding:1.1rem 1.2rem;
  color:var(--ink-dim);line-height:1.6}
.askempty p{margin:0 0 .6rem}
.askempty p:last-child{margin-bottom:0}
.askempty b{color:var(--ink)}

@media (max-width:560px){
  .askbox input{font-size:1rem;padding:.85rem .9rem}
  .rstate{font-size:.98rem}
  .chips{margin-bottom:1.2rem}
}
/* ==================== THE LEARNING SUB NAVIGATION ====================
   The bar under the banner, one per family, revealed by CSS on body[data-page].

   ⚠ ITS HISTORY, because it has been argued both ways in one day and the next
   person will otherwise "fix" it back. Aidan, 2026-08-26, first: "the drop down
   should be on the top banner only not duplicated under the top banner", and it
   was deleted. Then, same day: "put the sub-tabs as toggles at the top of each
   respective page like you had before so when I click learn to play there is
   strategy, rules etc all available to click at the top". So it is back.

   The two are not the same thing and that is the point. The BANNER MENU is
   navigation: it is how you reach another branch of the site from anywhere.
   THIS BAR is orientation: it shows, without a click, the pages that sit beside
   the one you are reading. What Aidan objected to was a second bar that did the
   banner's job. Keeping both is fine as long as this one stays a set of
   siblings and never grows into a copy of the menu.

   Deliberately NOT sticky: play.html already has a sticky progress bar, and two
   stacked sticky bars eat most of a phone screen.

   Matching on the family attribute as well as the page keeps it honest: without
   it, landing on a page in one family would reveal all three bars stacked.
   Aidan, 2026-08-24. */
.subnav{display:none;background:var(--paper);border-bottom:1px solid var(--rule)}
body[data-page="play"]      .subnav[data-family="learn"],
body[data-page="rules"]     .subnav[data-family="learn"],
body[data-page="strategy"]  .subnav[data-family="learn"],
body[data-page="faq"]       .subnav[data-family="learn"],
body[data-page="ask"]       .subnav[data-family="learn"],
body[data-page="reference"] .subnav[data-family="learn"],
body[data-page="cards"]     .subnav[data-family="cards"],
body[data-page="story"]     .subnav[data-family="world"],
body[data-page="characters"] .subnav[data-family="world"]{display:block}
.subnav-in{max-width:var(--maxw);margin:0 auto;padding:0 1.4rem;
  display:flex;gap:.3rem;overflow-x:auto;-webkit-overflow-scrolling:touch;
  scrollbar-width:none}
.subnav-in::-webkit-scrollbar{display:none}
.subnav a{flex:none;font-family:var(--display);font-weight:650;font-size:.92rem;
  color:var(--ink-dim);text-decoration:none;padding:.75rem .8rem;
  border-bottom:3px solid transparent;white-space:nowrap}
.subnav a:hover{color:var(--royal)}
.subnav a[aria-current="page"]{color:var(--royal);border-bottom-color:var(--gold)}
@media (max-width:560px){
  .subnav-in{padding:0 .9rem}
  .subnav a{font-size:.85rem;padding:.65rem .55rem}
}


/* the drawer now nests the learning pages under Learn to Play */
.drawer ul.sub{list-style:none;margin:.2rem 0 .4rem;padding:0 0 0 1rem;
  border-left:2px solid var(--rule)}
/* ⚠ The drawer sits on --royal, so anything inside it must be light. These
   inherited --ink-dim and --royal, which is dark grey and dark blue on dark
   blue. Nearly invisible. Aidan, 2026-08-24. */
.drawer ul.sub a{font-size:.95rem;font-weight:600;color:#fff;
  opacity:.88;padding:.45rem 0}
.drawer ul.sub a:hover{color:var(--gold-2);opacity:1}
.drawer ul.sub{border-left-color:rgba(255,255,255,.28)}
.drawer ul.sub li{border-top:0}

/* ⚠ The sub lists start CLOSED and open on a click. Aidan, 2026-08-24: "the sub
   tabs also should not auto expand you should have to click to expand".

   The chevron has to be its OWN button beside the parent link, not the parent
   link doubling as a toggle. Every parent here is a real page, so making the
   row a disclosure would leave the drawer unable to reach Learn to Play, the
   set list or The World at all. One row, two targets: the name goes to the
   page, the chevron opens what is underneath.

   Hiding is done with the hidden attribute rather than a class, so the list is
   correctly hidden from a screen reader too. [hidden] carries !important
   further up this file, because an author display rule beats a bare [hidden]. */
.drawer .row{display:flex;align-items:center;gap:.5rem}
.drawer .row a{flex:1 1 auto}
.drawer .subtog{flex:none;width:40px;height:40px;padding:0;background:none;border:0;
  cursor:pointer;color:#e7eefc;opacity:.75;display:grid;place-items:center;
  border-radius:8px}
.drawer .subtog:hover{opacity:1;background:rgba(255,255,255,.12);color:var(--gold-2)}
/* a chevron drawn in CSS, so the drawer needs no icon file */
.drawer .subtog::before{content:"";width:9px;height:9px;
  border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  transform:translateY(-2px) rotate(45deg);transition:transform .18s ease}
.drawer .subtog[aria-expanded="true"]::before{transform:translateY(2px) rotate(-135deg)}

/* play.html's sticky progress bar sits under the top bar, and the sub nav
   scrolls away above it, so the offset is unchanged. */
/* ==================== THE FINISH ====================
   Aidan, 2026-08-24: show the Geopals reaching the end of a fully set up board,
   because "the last tile is not the end" is the rule people get wrong and a
   paragraph does not fix it.

   The finished token sits at left:118% of the LAST map card, which puts it clear
   of the map. The row needs room on the right for it, hence the padding. */
.maprow.finrow{padding-right:9%;overflow:visible}
.mapcard.last{overflow:visible}
.mapcard .token.done{top:51%;
  box-shadow:0 0 0 2px #fff,0 0 0 4px #3f9e5a,0 3px 10px rgba(19,35,63,.45);
  animation:finpulse 2.6s ease-in-out infinite}
.mapcard .token.notyet{opacity:.95;
  box-shadow:0 0 0 1.5px #fff,0 0 0 3px var(--gold),0 2px 6px rgba(19,35,63,.4)}
@keyframes finpulse{
  0%,100%{transform:translate(-50%,-50%) scale(1)}
  50%    {transform:translate(-50%,-50%) scale(1.09)}
}
@media (prefers-reduced-motion:reduce){ .mapcard .token.done{animation:none} }
.donetick{position:absolute;left:118%;top:80%;transform:translateX(-50%);
  font-family:var(--display);font-weight:800;font-size:.6rem;color:#fff;
  background:#3f9e5a;border-radius:20px;padding:.12rem .4rem;white-space:nowrap;
  z-index:4}
.donetick::after{content:" Finished"}

/* the two outcomes, side by side */
.fincap{display:grid;gap:.7rem;margin:1rem 0 .9rem;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr))}
.fc{background:var(--paper);border:1px solid var(--rule);border-radius:14px;
  padding:.9rem 1rem;border-left:4px solid var(--rule)}
.fc.no{border-left-color:var(--gold);background:rgba(245,179,36,.07)}
.fc.yes{border-left-color:#3f9e5a;background:rgba(63,158,90,.08)}
.fc b{display:block;font-family:var(--display);font-size:1rem;margin-bottom:.25rem}
.fc.no b{color:#9a6f10}
.fc.yes b{color:#2f7a45}
.fc span{color:var(--ink-dim);font-size:.9rem;line-height:1.5}
/* ==================== BETWEEN GAMES ====================
   Aidan, 2026-08-24: this was behind a dropdown and it is one of the easiest
   things in the game to get wrong. A match is best of three, so it happens
   twice, and almost everything resets EXCEPT the Stamina and Items on your
   Geopals. Splitting it into "stays" and "resets" is the whole point: a list of
   five steps buries the exception, two columns make it the first thing you
   see. */
.between{background:var(--paper);border:2px solid var(--royal);border-radius:18px;
  padding:1.2rem;margin:1.6rem 0 1.2rem;
  box-shadow:0 4px 18px rgba(19,35,63,.10)}
.btitle{font-family:var(--display);font-size:1.25rem;color:var(--royal);
  margin:0 0 .4rem}
.bintro{margin:0 0 1.1rem;color:var(--ink-dim);line-height:1.6}

.bsplit{display:grid;gap:.9rem;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr))}
.bkeep,.bgoes{border-radius:14px;padding:.95rem 1.05rem}
.bkeep{background:rgba(63,158,90,.09);border:1px solid rgba(63,158,90,.35)}
.bgoes{background:var(--sky);border:1px solid var(--rule)}
.blab{display:inline-block;font-family:var(--display);font-weight:800;
  font-size:.7rem;text-transform:uppercase;letter-spacing:.07em;
  padding:.2rem .55rem;border-radius:20px;margin-bottom:.6rem;color:#fff}
.blab.keep{background:#3f9e5a}
.blab.goes{background:var(--ink-faint)}
.bkeep ul,.bgoes ul{margin:0;padding-left:1.1rem;color:var(--ink-dim);
  line-height:1.55}
.bkeep li,.bgoes li{margin-bottom:.45rem}
.bkeep li:last-child,.bgoes li:last-child{margin-bottom:0}
.bkeep b,.bgoes b{color:var(--ink)}
.bnote{margin:.7rem 0 0;font-size:.87rem;line-height:1.5;color:#2f7a45;
  font-weight:600}
.bfirst{margin:1.1rem 0 0;padding-top:.9rem;border-top:1px solid var(--rule);
  color:var(--ink-dim);line-height:1.6}
.bfirst b{color:var(--ink)}
@media (max-width:560px){
  .between{padding:.95rem}
  .btitle{font-size:1.12rem}
}
/* ---- Tabletop Simulator on the tutorial ----
   Aidan wants the build reachable from the site. Two honest barriers stated up
   front rather than buried: TTS is a paid Steam app, and it cannot be embedded
   in a web page, so this is a download and four steps. */
.ttsbox{background:var(--paper);border:1px solid var(--rule);
  border-left:4px solid var(--royal);border-radius:16px;padding:1.2rem;
  margin:1.6rem 0}
.ttsbox h3{font-family:var(--display);font-size:1.15rem;color:var(--royal);
  margin:0 0 .5rem}
.ttsbox p{margin:0 0 .7rem;color:var(--ink-dim);line-height:1.6}
.ttsbox .ttsnote{font-size:.87rem;background:var(--sky);border-radius:9px;
  padding:.55rem .7rem;color:var(--ink-dim)}
.ttsbox code{background:var(--sky);padding:.1rem .3rem;border-radius:4px;
  font-size:.9em}
.ttsbox ol{margin:0 0 .8rem}
.ttsbox a{color:var(--royal);font-weight:600}
/* ==================== QUICK REFERENCE ====================
   One page for someone mid-game with a phone in one hand, or printed and left
   beside the board. The only page on the site not written to teach: it exists
   to remind, so it is deliberately terse.
   Every line is a view of the game-rules register. If they disagree, fix the
   register first and let this follow. */
.ref .refgrid{display:grid;gap:.9rem;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr))}
.refcard{background:var(--paper);border:1px solid var(--rule);border-radius:14px;
  padding:1rem 1.1rem;break-inside:avoid}
.refcard h2{font-family:var(--display);font-size:1rem;color:var(--royal);
  margin:0 0 .55rem;text-transform:uppercase;letter-spacing:.05em}
.refcard ul.tight,.refcard ol.tight{margin:0 0 .6rem;padding-left:1.1rem}
.refcard li{margin-bottom:.3rem;font-size:.9rem;line-height:1.45;color:var(--ink-dim)}
.refcard li b{color:var(--ink)}
.refcard .hot{margin:.5rem 0;padding:.5rem .65rem;background:rgba(216,51,47,.08);
  border-left:3px solid var(--xred);border-radius:0 8px 8px 0;
  font-size:.87rem;line-height:1.45;color:var(--ink)}
.refcard .small{margin:.4rem 0 0;font-size:.82rem;color:var(--ink-faint);line-height:1.45}
.reftab{width:100%;border-collapse:collapse;font-size:.85rem;margin-top:.4rem}
.reftab td{padding:.22rem .4rem;border-bottom:1px solid var(--rule)}
.reftab td:first-child{font-family:var(--display);font-weight:700;color:var(--ink);width:38%}
.reftab td:last-child{color:var(--ink-dim)}
.reftab tr:last-child td{border-bottom:0}
.reftab.weak td:last-child{color:var(--xred)}
.refprint{display:flex;align-items:center;gap:.7rem;margin:0 0 1.2rem}
.refprint button{cursor:pointer;font-family:var(--display);font-weight:700;
  font-size:.9rem;color:#fff;background:var(--royal);border:0;border-radius:22px;
  padding:.55rem 1.1rem}
.refprint button:hover{background:var(--royal-2)}
.refprint span{font-size:.83rem;color:var(--ink-faint)}

@media print{
  .topnav,.subnav,.drawer,footer,.refprint,.lede,.ref .sub,.parentcrumb{display:none !important}
  body{background:#fff}
  .page{padding:0}
  .ref h1{font-size:1.2rem;margin:0 0 .5rem}
  .ref .refgrid{grid-template-columns:1fr 1fr;gap:.5rem}
  .refcard{border:1px solid #bbb;padding:.5rem .6rem;border-radius:6px}
  .refcard h2{font-size:.8rem;margin-bottom:.3rem}
  .refcard li,.reftab{font-size:.72rem}
  .refcard .hot{font-size:.72rem;padding:.3rem .4rem}
  .refcard .small{font-size:.68rem}
}
/* ---- the TTS panel, collapsed ----
   Aidan, 2026-08-24: it took too much space open. It is an aside, not a step,
   so it folds away and states what it is on the closed line. */
.ttsbox{padding:0;overflow:hidden}
.ttsbox > summary{cursor:pointer;list-style:none;display:flex;align-items:center;
  gap:.7rem;padding:.85rem 1.1rem}
.ttsbox > summary::-webkit-details-marker{display:none}
.ttsbox > summary b{font-family:var(--display);font-size:1rem;color:var(--royal);
  flex:1 1 auto}
.ttsbox > summary .tt{flex:none;font-family:var(--display);font-weight:700;
  font-size:.76rem;color:var(--royal);background:var(--sky);border-radius:20px;
  padding:.28rem .65rem;display:inline-flex;align-items:center;gap:.4rem}
.ttsbox > summary .tt::after{content:"";width:6px;height:6px;
  border-right:2px solid var(--royal);border-bottom:2px solid var(--royal);
  transform:rotate(45deg) translateY(-1px);transition:transform .2s}
.ttsbox[open] > summary .tt::after{transform:rotate(-135deg) translateY(-1px)}
.ttsbox[open] > summary{border-bottom:1px solid var(--rule)}
.ttsbox .ttsin{padding:1rem 1.1rem}
.ttsbox h3{display:none}
@media (prefers-reduced-motion:reduce){ .ttsbox > summary .tt::after{transition:none} }
/* ============================================================================
   NESTED PAGES: the child link panel, and the crumb back up
   Aidan, 2026-08-24: "quick reference should be part of 'rules' not a separate
   tab and the ask about the game part should be under 'questions' not a
   separate tab."

   Both pages stayed as pages. Quick reference has real print styles and a one
   sheet layout that cannot survive being folded into the rules, and Ask is
   GENERATED from the rules register, so folding it in would mean generating the
   questions page too. What changed is that they are no longer siblings in the
   sub bar. They are reached from a panel at the top of their parent, and each
   says where it came from.
   ============================================================================ */
/* ⚠ Capped. It sits directly under main.page, which is 1180px, and at that
   width it was one long thin bar with a sentence stretched across it. 720px is
   about the same measure as the lede above it. */
.childlink{display:flex;align-items:center;gap:.9rem;margin:0 0 1.4rem;
  max-width:min(100%,720px);
  padding:.95rem 1.05rem;background:var(--paper);text-decoration:none;
  border:1px solid var(--rule);border-left:4px solid var(--gold);border-radius:12px;
  transition:box-shadow .18s ease,transform .18s ease,border-color .18s ease}
.childlink:hover{box-shadow:var(--shadow-2);transform:translateY(-1px);
  border-color:var(--gold-2);border-left-color:var(--gold-2)}
.cl-ico{flex:none;width:40px;height:40px;border-radius:10px;background:var(--royal);
  color:#fff;display:grid;place-items:center;gap:3px;align-content:center;
  font-family:var(--display);font-weight:800;font-size:1.15rem}
/* the three bars of the quick reference icon, drawn rather than shipped */
.cl-ico span{display:block;width:17px;height:2px;background:currentColor;border-radius:2px}
.cl-ico span:nth-child(2){width:12px}
.cl-txt{flex:1 1 auto;color:var(--ink-dim);font-size:.9rem;line-height:1.5}
.cl-txt b{display:block;font-family:var(--display);color:var(--royal);
  font-size:1.05rem;margin-bottom:.15rem}
.cl-go{flex:none;width:9px;height:9px;margin-right:.3rem;
  border-top:2px solid var(--royal);border-right:2px solid var(--royal);
  transform:rotate(45deg)}
@media (max-width:560px){
  .childlink{gap:.7rem;padding:.8rem .85rem}
  .cl-ico{width:34px;height:34px}
  .cl-txt{font-size:.86rem}
}

.parentcrumb{margin:0 0 .35rem;font-family:var(--display);font-weight:700;
  font-size:.85rem;color:var(--ink-faint);letter-spacing:.02em}
.parentcrumb a{color:var(--royal);text-decoration:none;border-bottom:2px solid var(--gold)}
.parentcrumb a:hover{color:var(--gold-2);border-bottom-color:var(--gold-2)}
.parentcrumb span{margin:0 .35rem;opacity:.6}

/* ============================================================================
   THE THREE PHASES, ILLUSTRATED
   Aidan, 2026-08-24: "rules requires more visuals to illustrate phases".

   Real artwork, same as everywhere else on this site. No animation: this is the
   page you look at mid-game, and something moving while you are trying to read
   a number is a nuisance rather than a help. Learn to Play is where the moving
   walkthrough lives.

   GEOMETRY IS MEASURED. The tile centres on the 5-tile card are the same values
   recorded in the REAL-CARD ILLUSTRATIONS header near the top of this file:
   13.9, 30.9, 48.9, 68.3, 87.8. The token starts on tile 1 and finishes on tile
   4, which is a move of three tiles, which is what three Stamina cards buy. If
   that picture and the caption ever disagree, the picture is the one that lies.
   ============================================================================ */
/* ⚠ Three phases have to read as three, side by side. The rules column is about
   585px, so three panels came out about 175px each and the card art inside them
   was too small to read. This is the one block on the page that is a picture
   rather than prose, so it escapes the reading column and takes 880px.

   ⚠ It overflows its parent ON PURPOSE. .rules is capped at 64ch and left
   aligned inside a 1180px page, so there is room to its right and nothing is
   clipped. The 100vw guard is what stops it pushing a horizontal scrollbar on a
   narrow window; leave it in.

   ⚠ Three columns, stated, not auto-fit. auto-fit gave a 2 + 1 layout at tablet
   widths, and three phases laid out as two things and then another thing is a
   worse lie than three small pictures. One column below the breakpoint.
   Aidan, 2026-08-24. */
.phasestrip{display:grid;gap:.9rem;margin:1.4rem 0 1.6rem;grid-template-columns:1fr}
@media (min-width:620px){
  .phasestrip{grid-template-columns:repeat(3,1fr);
    width:min(880px,calc(100vw - 4rem))}
}
.ph{position:relative;background:var(--paper);border:1px solid var(--rule);
  border-radius:14px;padding:1.15rem 1rem 1.05rem}
.ph .pn{position:absolute;top:-13px;left:1rem;width:27px;height:27px;border-radius:50%;
  background:var(--royal);color:#fff;font-family:var(--display);font-weight:800;
  font-size:.85rem;display:grid;place-items:center;
  box-shadow:0 0 0 3px var(--paper)}
.ph h3{margin:.15rem 0 .7rem;font-size:1.1rem;color:var(--royal)}
.ph p{margin:.7rem 0 0;font-size:.9rem;line-height:1.5;color:var(--ink-dim)}

.phart{position:relative;aspect-ratio:16/9;border-radius:10px;overflow:hidden;
  border:1px solid var(--rule);
  background:linear-gradient(180deg,#eef2fa,#dfe7f5)}
.phart img{position:absolute;display:block;border-radius:4px;
  box-shadow:0 3px 10px rgba(19,35,63,.42)}
/* a dashed run with an arrowhead, shared by the Action and End panels */
.phart .ar{position:absolute;height:0;border-top:2px dashed var(--royal);z-index:4}
.phart .ar::after{content:"";position:absolute;right:-2px;top:-6px;
  border:6px solid transparent;border-left-color:var(--royal);border-right:0}

/* ---- 1. Action: cards leave your hand and land on a Geopal ----
   ⚠ The step between the three hand cards has to be most of a card width, not a
   sliver. At an 8% step against a 19% card only the top one was legible and the
   fan read as one card with edges behind it. 11% against 18% shows about two
   thirds of each. */
.phart.act .h1{left:1%;top:21%;width:18%;transform:rotate(-11deg);z-index:1}
.phart.act .h2{left:12%;top:15%;width:18%;transform:rotate(-4deg);z-index:2}
.phart.act .h3c{left:23%;top:11%;width:18%;transform:rotate(4deg);z-index:3}
.phart.act .ar{left:44%;top:50%;width:12%}
.phart.act .geo{right:15%;top:8%;width:24%;z-index:2}
.phart.act .att{right:4%;top:46%;width:17%;transform:rotate(7deg);z-index:3}

/* ---- 2. Movement: three tiles along the ground ---- */
.phart.mv{display:grid;place-items:center;padding:0 12%;
  background:linear-gradient(180deg,#eef2fa,#dfe7f5)}
.phart.mv .terrwrap{position:relative;display:block;width:100%}
.phart.mv .terr{position:relative;width:100%;border-radius:6px}
.phart.mv .tk{position:absolute;top:51%;width:15%;aspect-ratio:1;border-radius:50%;
  transform:translate(-50%,-50%);z-index:3;overflow:hidden}
.phart.mv .tk img{position:static;width:100%;border-radius:0;box-shadow:none}
.phart.mv .tk.a{left:13.9%;box-shadow:0 0 0 2px #fff,0 0 0 4px var(--royal),
  0 4px 10px rgba(19,35,63,.4)}
/* Where it ends up. A faded copy of the SAME token, not an empty dashed ring:
   at this size the ring rendered as a small grey cog and read as a second
   object on the board rather than as a destination. Faded, it reads as "this
   one, later". */
.phart.mv .tk.b{left:68.3%;opacity:.42;
  box-shadow:0 0 0 2px #fff,0 0 0 4px var(--royal)}
.phart.mv .mvlbl{position:absolute;left:41.1%;top:51%;z-index:5;
  transform:translate(-50%,-175%);font-family:var(--data);font-weight:700;
  font-size:.62rem;color:#fff;background:var(--royal);white-space:nowrap;
  padding:.1rem .45rem;border-radius:20px}
/* ⚠ Gold, not royal. The run crosses the terrain artwork, which is dark brown
   and dark grey, and a dark blue dashed line on it was invisible. The two
   dashed runs on the other panels sit on a pale background and stay royal. */
.phart.mv .run{position:absolute;top:51%;left:13.9%;width:54.4%;height:0;
  border-top:2px dashed var(--gold);z-index:2}
.phart.mv .run::after{content:"";position:absolute;right:-2px;top:-6px;
  border:6px solid transparent;border-left-color:var(--gold);border-right:0}

/* ---- 3. End: draw back up to six ---- */
.phart.dr .deck{left:7%;top:20%;width:20%}
.phart.dr .ar{left:31%;top:50%;width:11%}
.phart.dr .fan{position:absolute;right:5%;bottom:16%;width:48%;height:58%}
.phart.dr .fan i{position:absolute;bottom:0;width:24%;aspect-ratio:900/1226;
  background:url(assets/cardback.jpg) center/cover;border-radius:3px;
  box-shadow:0 2px 7px rgba(19,35,63,.4);transform-origin:50% 100%}
.phart.dr .fan i:nth-child(1){left:0;transform:rotate(-15deg)}
.phart.dr .fan i:nth-child(2){left:14%;transform:rotate(-9deg)}
.phart.dr .fan i:nth-child(3){left:28%;transform:rotate(-3deg)}
.phart.dr .fan i:nth-child(4){left:42%;transform:rotate(3deg)}
.phart.dr .fan i:nth-child(5){left:56%;transform:rotate(9deg)}
.phart.dr .fan i:nth-child(6){left:70%;transform:rotate(15deg)}
.phart.dr .lbl{position:absolute;right:6%;top:6%;font-family:var(--data);
  font-size:.7rem;font-weight:700;color:#fff;background:var(--royal);
  padding:.15rem .5rem;border-radius:20px;z-index:5}

/* ============================================================================
   ORDERING, AS TWO TRACKS
   Which phase you do a thing in is the rule people get wrong, and the cost of
   getting it wrong is invisible in prose. Side by side it is not.
   ============================================================================ */
.twomove{display:grid;gap:1rem;margin:1rem 0 .4rem;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,250px),1fr))}
.tm{border:1px solid var(--rule);border-radius:12px;padding:.95rem 1rem 1rem;
  background:var(--paper)}
.tm.ok{border-left:4px solid var(--xgreen)}
.tm.no{border-left:4px solid var(--xred)}
.tmtag{display:inline-block;font-family:var(--display);font-weight:800;
  font-size:.75rem;letter-spacing:.05em;text-transform:uppercase;
  padding:.18rem .55rem;border-radius:20px;margin-bottom:.6rem}
.tm.ok .tmtag{background:rgba(47,122,70,.12);color:var(--xgreen)}
.tm.no .tmtag{background:rgba(216,51,47,.12);color:var(--xred)}
.tm ol{margin:0;padding-left:1.2rem}
.tm li{margin-bottom:.35rem;font-size:.9rem;line-height:1.5;color:var(--ink-dim)}
.tm li b{color:var(--ink)}
.tmres{margin:.55rem 0 0;font-family:var(--display);font-weight:700;font-size:.92rem}
.tm.ok .tmres{color:var(--xgreen)}
.tm.no .tmres{color:var(--xred)}
/* ==================== JOEL'S DECKS ====================
   A deck showcase inside a strategy panel: the video, then the decklist as
   actual card images, then the reasoning.

   The decklist escapes the 64ch reading column on purpose, the same trick the
   rules phase strip uses. A deck is a picture of forty cards; squeezed to 585px
   the art is unreadable and the reader learns nothing a list would not tell
   them. Below 900px it falls back to the reading width and the cards get
   smaller, because a phone has no width to escape into. */
.jdeck{margin:2.5rem 0 0}
.jdeck > h3{font-family:var(--display);font-size:1.15rem;color:var(--royal);
  margin:0 0 .3rem;display:flex;align-items:baseline;gap:.6rem;flex-wrap:wrap}
.jdeck > h3 .by{font-family:var(--body);font-size:.85rem;font-weight:400;color:var(--ink-dim)}
.jdeck .jsub{color:var(--ink-dim);margin:0 0 1.1rem;max-width:64ch;font-size:.95rem}

/* 16:9, and the iframe fills it. Drive's player has its own chrome, so the
   frame gets a border rather than trying to look like part of the page. */
.jvid{position:relative;width:100%;aspect-ratio:16/9;background:#000;
  border:1px solid var(--rule);border-radius:14px;overflow:hidden;margin:0 0 .6rem}
.jvid iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
.jvidnote{color:var(--ink-dim);font-size:.85rem;margin:0 0 1.8rem}

.jgroup{margin:0 0 1.6rem}
.jgroup h4{font-family:var(--display);font-size:1rem;margin:0 0 .1rem}
.jgroup .gn{color:var(--ink-dim);font-size:.87rem;margin:0 0 .7rem}

/* auto-fill, not auto-fit: with auto-fit a group holding one card stretches it
   to the full width of the strip, which makes a single Orb look like a feature
   rather than one card in a deck. */
.jcards{display:grid;gap:.9rem;grid-template-columns:repeat(auto-fill,minmax(132px,1fr))}
.jcard{margin:0}
.jcard .jimgwrap{position:relative;display:block;border-radius:9px;overflow:hidden;
  border:1px solid var(--rule);background:var(--paper);
  box-shadow:0 2px 8px rgba(19,35,63,.10)}
.jcard img{display:block;width:100%;height:auto}
/* The count sits on the art because a deck is read by counting copies. */
.jcard .qty{position:absolute;top:6px;right:6px;background:var(--royal);color:#fff;
  font-family:var(--display);font-weight:700;font-size:.78rem;line-height:1;
  padding:.28rem .42rem;border-radius:6px;box-shadow:0 1px 4px rgba(0,0,0,.35)}
.jcard figcaption{font-size:.82rem;line-height:1.4;color:var(--ink-dim);margin:.4rem 0 0}
.jcard figcaption b{display:block;color:var(--ink);font-size:.86rem}

/* A card Joel named but does not own, or a slot he left open. Shown as a gap
   rather than omitted, because the deck he describes is the deck we list. */
.jcard.ghost .jimgwrap{border-style:dashed;background:transparent;box-shadow:none;
  aspect-ratio:.72;display:flex;align-items:center;justify-content:center}
.jcard.ghost .gtxt{color:var(--ink-dim);font-size:.8rem;text-align:center;padding:.5rem;line-height:1.35}

.jnotes{max-width:64ch;margin:1.8rem 0 0}
.jnotes h4{font-family:var(--display);font-size:1.05rem;color:var(--royal);margin:1.4rem 0 .45rem}
.jnotes p{color:var(--ink-dim);margin:0 0 .6rem}
.jnotes ul{padding-left:1.2rem;margin:0 0 .6rem}
.jnotes li{color:var(--ink-dim);margin-bottom:.4rem}

/* A rules problem in a published example deck has to be visible, or the deck
   teaches the mistake. Warm, not alarming: the deck is still worth copying. */
.jflag{background:#fff8e6;border:1px solid #e8c97a;border-left:4px solid var(--gold);
  border-radius:10px;padding:.85rem 1rem;margin:1.2rem 0}
.jflag b{font-family:var(--display)}
.jflag p{margin:0;color:var(--ink);font-size:.93rem;line-height:1.55}
.jflag p + p{margin-top:.5rem}

@media (min-width:900px){
  .jdeck{width:min(880px,calc(100vw - 4rem))}
}
@media (max-width:520px){
  .jcards{grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:.6rem}
  .jcard figcaption{font-size:.76rem}
}

/* ==================== TREASURE HUNTS ====================
   The public half of the hunt platform, published as an ordinary page because
   the static site cannot run the distance check, the claim or the profile. Those
   live on the app; this is everything somebody reads before they leave home.

   Aidan, 2026-08-26: "i dont want to use cloudflare yet - can you just put it
   on the github preview site". */
.hunton{display:inline-block;background:var(--gold);color:var(--royal-3);
  font-family:var(--display);font-weight:800;font-size:.78rem;letter-spacing:.06em;
  padding:.28rem .7rem;border-radius:999px;margin:0 0 .7rem}
.huntsub{font-family:var(--display);font-size:1.2rem;color:var(--royal);margin:2.2rem 0 .2rem}
.huntnote{color:var(--ink-dim);margin:0 0 .5rem}
.huntfoot{color:var(--ink-faint);font-size:.85rem;margin-top:.7rem}

/* Nilgie explaining the process. Same cutout the tutorial uses, but with a
   bubble: Aidan asked for one here on 2026-08-26, having rejected one on the
   tutorial on 2026-08-24. The objection then was that he looked boxed in and
   small, so he stays large and transparent and the bubble sits beside him. */
.says{display:grid;grid-template-columns:150px 1fr;gap:.9rem;align-items:center;margin:1.4rem 0 1.6rem}
.says > img{width:100%;display:block;filter:drop-shadow(0 14px 18px rgba(19,35,63,.20))}
.bub{position:relative;background:var(--paper);border:1px solid var(--rule);
  border-radius:16px;padding:.95rem 1.1rem;box-shadow:0 2px 10px rgba(19,35,63,.07)}
.bub::before,.bub::after{content:"";position:absolute;left:-9px;top:50%;
  width:16px;height:16px;transform:translateY(-50%) rotate(45deg)}
.bub::before{background:var(--rule)}
.bub::after{background:var(--paper);left:-7px}
.bub p{margin:0 0 .55rem;color:var(--ink-dim);line-height:1.6;font-size:.96rem}
.bub p:last-child{margin-bottom:0}
.bub .hi{font-family:var(--display);font-size:1.1rem;color:var(--ink);font-weight:700}
.bub ol{margin:.4rem 0 .55rem;padding-left:1.15rem;color:var(--ink-dim);font-size:.94rem}
.bub li{margin-bottom:.3rem}

.hwrap{display:flex;border:1px solid var(--rule);border-radius:16px;overflow:hidden;
  background:var(--paper);margin-top:.4rem;position:relative}
#hmap{flex:1;height:30rem;background:var(--mist)}
/* The embedded 3D world (2026-08-29): same footprint as the 2D map had. */
#map3dframe{flex:1;height:38rem;border:0;display:block;background:var(--mist)}
.hwrap.full #map3dframe{height:100%}
.hside{width:22rem;flex:none;background:var(--paper);border-left:1px solid var(--rule);
  overflow-y:auto;padding:1rem;height:30rem}
.hside h3{font-family:var(--display);font-size:1rem;color:var(--royal);margin:0 0 .6rem}
/* ⚠ CSS full screen, not the Fullscreen API. Safari on iPhone does not support
   requestFullscreen on an element, and a map is precisely what somebody wants
   big on a phone, so the API would fail exactly where it is needed. */
.hwrap.full{position:fixed;inset:0;z-index:2000;border-radius:0;border:0;margin:0}
.hwrap.full #hmap{height:100%}
.hwrap.full .hside{height:100%}
.fsbtn{position:absolute;top:.6rem;right:.6rem;z-index:1000;width:auto;
  padding:.45rem .85rem;font-size:.85rem;font-family:var(--display);font-weight:700;
  background:var(--paper);color:var(--ink);border:1px solid var(--rule);border-radius:999px;
  box-shadow:0 2px 8px rgba(19,35,63,.18);cursor:pointer}
.fsbtn:hover{background:var(--mist)}
/* Spots drop-down in full screen (Aidan, 2026-08-28): full screen on a phone
   is map only, so the spot info gets a button next to Close that drops the
   whole list over the map. Hidden outside full screen; the ordinary layouts
   already show the list beside or under the map. */
.spotsbtn{display:none;position:absolute;top:.6rem;right:6rem;z-index:1000;width:auto;
  padding:.45rem .85rem;font-size:.85rem;font-family:var(--display);font-weight:700;
  background:var(--paper);color:var(--ink);border:1px solid var(--rule);border-radius:999px;
  box-shadow:0 2px 8px rgba(19,35,63,.18);cursor:pointer}
.spotsbtn:hover{background:var(--mist)}

/* The region colour rides on a left edge, the way the card borders do. */
.hm{border:1px solid var(--rule);border-left:4px solid var(--rc,var(--rule));
  border-radius:12px;padding:.7rem .8rem;margin:0 0 .6rem;cursor:pointer;
  background:var(--paper);display:flex;gap:.65rem;align-items:flex-start}
.hm:hover{background:var(--sky)}
.hm.on{box-shadow:0 0 0 2px rgba(245,179,36,.45)}
/* Already found: greyed so nobody hunts it twice (2026-08-30). */
.hm.hm-found{opacity:.55;filter:grayscale(.6)}
.hm .orb{width:30px;height:40px;flex:none;object-fit:contain;margin-top:.1rem}
.hm .mb{min-width:0;flex:1}
.hm b{font-family:var(--display);display:block}
.hm .r{color:var(--ink-faint);font-size:.8rem;display:block}
.hm .rate{color:var(--ink-faint);font-size:.78rem;display:block;margin-top:.15rem;letter-spacing:.05em}
.hm .c{color:var(--ink-dim);font-size:.88rem;margin-top:.5rem;display:none}
.hm.on .c{display:block}
.hm .c p{margin:0 0 .5rem}
.hm .c p:last-child{margin-bottom:0}
.hm .c .clue{background:var(--sky);border-radius:8px;padding:.5rem .6rem;color:var(--ink)}
/* Safety gets its own flag, never folded into a paragraph about parking. It is
   the sentence that keeps somebody off a wet rock. */
.hm .c .safe{background:#fff8e6;border-left:3px solid var(--gold);border-radius:6px;padding:.45rem .6rem}
.pill{display:inline-block;font-size:.7rem;font-family:var(--display);font-weight:800;
  letter-spacing:.05em;padding:.1rem .45rem;border-radius:999px;margin-left:.35rem}
.pill.live{background:#e8f5ec;color:#14532d}
.pill.unc{background:#fff8e6;color:#7a5b06}
.hempty{color:var(--ink-dim);font-size:.92rem}
.leaflet-container{font:inherit}

@media (max-width:860px){
  .hwrap{flex-direction:column}
  #hmap{height:22rem;flex:none}
  #map3dframe{height:34rem;flex:none}
  .hside{width:auto;height:auto;max-height:26rem;border-left:0;border-top:1px solid var(--rule)}
  /* Full screen on a phone: the sidebar cannot fit beside the map, so it
     hides until the Spots button drops it over the top. */
  .hwrap.full .hside{display:none}
  .hwrap.full .spotsbtn{display:block}
  .hwrap.full.spots .hside{display:block;position:absolute;top:3.3rem;left:.6rem;right:.6rem;
    z-index:1001;max-height:64vh;border:1px solid var(--rule);border-radius:14px;
    box-shadow:0 18px 50px rgba(9,22,52,.4)}
}
@media (max-width:620px){
  .says{grid-template-columns:1fr;gap:.5rem;justify-items:center}
  .says > img{width:130px}
  .bub::before,.bub::after{left:50%;top:-9px}
  .bub::before{transform:translateX(-50%) rotate(45deg)}
  .bub::after{top:-7px;transform:translateX(-50%) rotate(45deg)}
}
