/* Player web app — page-local styles over ui-kit/tokens.css. */
/* Reserve the scrollbar gutter always. Screens differ in height, so without
   this the vertical scrollbar appears and disappears as you move between them
   and the viewport changes width by ~15px each time. That shifts the whole
   layout, and it silently defeats the nav's scroll-the-active-tab-into-view:
   the tab is measured and scrolled to BEFORE the screen's content arrives, and
   the scrollbar that content raises then pushes it back off the edge. */
html{background:#020a12;scrollbar-gutter:stable}
body{margin:0;min-height:100vh;font-family:var(--font-body);font-size:var(--text-base);
  line-height:var(--lh-prose);color:var(--ink);background:var(--ground);background-attachment:fixed}
.app{max-width:64rem;margin:0 auto;padding:var(--s-4) var(--s-4) 6rem}

.gate{max-width:34rem;margin:0 auto;padding:6rem var(--s-4);text-align:center}
.gate .eyebrow{font-family:var(--font-display);font-weight:700;letter-spacing:.18em;
  text-transform:uppercase;font-size:.8rem;color:var(--foam);margin:0 0 .5rem}
.gate h1{font-family:var(--font-display);font-weight:600;font-size:var(--text-2xl);
  line-height:var(--lh-tight);margin:0 0 .6rem;color:#f3fafd}
.gate .lede{color:var(--ink-dim);margin:0 auto var(--s-5);max-width:28rem}
.gate-actions{display:flex;gap:var(--s-3);flex-wrap:wrap;justify-content:center}

.mast{display:flex;align-items:center;gap:var(--s-3);padding:var(--s-3) var(--s-4);
  background:#0a2a42cc;border:var(--border);border-radius:var(--r-panel);backdrop-filter:blur(8px);
  position:sticky;top:var(--s-2);z-index:5;margin-bottom:var(--s-4);flex-wrap:wrap}
.mast .brand{font-family:var(--font-display);font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;font-size:.8rem;color:var(--foam);white-space:nowrap}
.mast .sp{flex:1}
.purse{display:flex;align-items:center;flex-wrap:wrap;gap:var(--s-3);font-size:var(--text-sm);
  font-variant-numeric:tabular-nums}
.purse b{color:var(--gold)}
/* Each figure moves as a whole or not at all. Without this the masthead runs
   out of room on a phone by breaking BETWEEN the coin and its number, which
   reads as two unrelated things. */
.purse > span{white-space:nowrap}
/* Level sits with the purse so the masthead answers "how am I doing" beside
   "what can I spend". The bar is screens.css's .meter at masthead scale; the
   min-width stops the whole cluster jumping sideways as the numbers grow. */
.lvl{display:flex;flex-direction:column;gap:.1rem;min-width:7.5rem}
.lvl-top{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2)}
.lvl b{color:var(--foam);white-space:nowrap}
.lvl-xp{color:var(--ink-dim);font-size:var(--text-xs);white-space:nowrap}
.lvl .meter{height:5px;margin:0}
.who{display:flex;align-items:center;gap:var(--s-2);font-size:var(--text-sm);color:var(--ink-dim)}
.avatar{width:26px;height:26px;border-radius:50%;background:linear-gradient(140deg,var(--foam),#2b7fa8)}
/* The gradient stays behind the image, so a Discord avatar that is slow or
   fails to load leaves the placeholder rather than a broken-image box. */
img.avatar{object-fit:cover;border:1px solid var(--line)}

.picker select{font:inherit;font-size:var(--text-sm);color:var(--ink);background:var(--depth-shallow);
  border:var(--border);border-radius:var(--r-control);padding:.3rem .5rem}

/* Two-tier navigation, built from the screen registry. Row 1 is the pinned
   screens and one chip per category; row 2 is the screens of whichever category
   the current screen belongs to, and carries `hidden` when there is none.
   Desktop: both rows wrap. Mobile: row 1 drops its labels and becomes an icon
   grid that WRAPS rather than scrolls, so the whole top level is visible at
   once — which the old single strip of thirty tabs never managed. */
.tabs{display:flex;flex-direction:column;gap:var(--s-2);margin-bottom:var(--s-4);
  padding-top:.4rem}
.nav-row{display:flex;flex-wrap:wrap;gap:var(--s-2);align-items:center}
/* Row 2 says "these belong to the chip above": inset, indented, quieter. Its
   own padding also clears the badge overhang once it becomes a scroller below. */
.nav-secondary{padding:var(--s-2) var(--s-3);margin-left:var(--s-4);
  background:var(--depth-deep);border:var(--border);border-radius:var(--r-panel)}
.tab{font:inherit;font-weight:700;cursor:pointer;padding:.45rem .9rem;border-radius:var(--r-control);
  border:var(--border);background:var(--depth-shallow);color:var(--ink-dim);white-space:nowrap;
  position:relative;display:inline-flex;align-items:center;gap:.35rem}
.nav-secondary .tab{font-size:var(--text-sm);padding:.35rem .75rem}
.tab.on{background:var(--card);color:var(--foam)}
/* An open category is not the active screen — the active screen is in row 2 —
   so it is marked differently rather than identically. */
.tab.cat.open{color:var(--foam);border-color:var(--foam)}
.tab .caret{font-size:var(--text-xs)}
.tab.cat.open .caret{transform:rotate(180deg)}
/* The notification pill, overlapping the chip's corner the way a messages app
   does. It overhangs, so two things keep it from being clipped: .tabs's
   padding-top clears the masthead above row 1, and .nav-secondary's own padding
   clears it inside the scroller row 2 becomes on mobile. Dark ink on --bad, not
   white: white on #ff6b6b is about 2.9:1, which fails a count you are meant to
   read. */
.badge{position:absolute;top:-.35rem;right:-.35rem;min-width:1.15rem;height:1.15rem;
  padding:0 .3rem;border-radius:var(--r-pill);background:var(--bad);color:var(--abyss);
  font-size:var(--text-xs);font-weight:700;line-height:1.15rem;text-align:center;
  font-variant-numeric:tabular-nums;pointer-events:none}
.screen{display:block}

@media(max-width:768px){
  /* Row 1 as an icon grid, sized to wrap to exactly TWO lines at 390px, where
     the row is 351px wide.
     Measured budget: an icon chip is 44px (the touch-target floor) and the gap
     is 4px, so 13 icons come to 620px — two comfortable lines. Only ONE chip
     is ever labelled, and only when a screen in row 1 is the active one; a
     label costs about 80px, which still fits.
     The open CATEGORY deliberately keeps its icon: its label runs to 126px and
     tips the row onto a third line, and it is already unmistakable from its
     foam border, its flipped caret, and row 2 sitting right beneath it. */
  .nav-primary{gap:var(--s-1)}
  .nav-primary .tab{min-width:2.75rem;justify-content:center;padding:.45rem .55rem}
  .nav-primary .tab-label,
  .nav-primary .tab .caret{display:none}
  .nav-primary .tab.on .tab-label,
  .nav-primary .tab.cat.open .caret{display:inline}
  /* Row 2 keeps its words and scrolls instead; only Compete's eight items
     overflow, and show()'s scrollIntoView brings the landed chip back.
     scroll-padding gives it slack at the trailing edge, because a screen's
     content arrives after the nav has scrolled and any vertical scrollbar it
     raises narrows the viewport under us. */
  .nav-secondary{flex-wrap:nowrap;overflow-x:auto;margin-left:0;
    scroll-padding-inline:var(--s-3) var(--s-6)}
}

.panel{background:var(--card);border:var(--border);border-radius:var(--r-panel);
  padding:var(--s-4) var(--s-5);backdrop-filter:blur(4px);margin-bottom:var(--s-4)}
.panel-head{display:flex;align-items:baseline;gap:var(--s-3);margin-bottom:var(--s-4)}
.panel-head h2{font-family:var(--font-display);font-weight:600;font-size:1.15rem;color:var(--foam);margin:0}

.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:var(--s-3)}
.tile{background:#08233866;border:var(--border);border-radius:var(--r-control);padding:.85rem .95rem}
.tile .k{color:var(--ink-dim);font-size:var(--text-xs);text-transform:uppercase;
  letter-spacing:.06em;font-weight:700}
.tile .v{font-family:var(--font-display);font-weight:600;font-size:1.6rem;line-height:var(--lh-tight);
  margin-top:.3rem;font-variant-numeric:tabular-nums;color:#f3fafd}
.tile .d{font-size:var(--text-xs);margin-top:.15rem;color:var(--ink-dim)}
.tile.accent .v{color:var(--gold)}

.btn{font:inherit;font-weight:700;cursor:pointer;display:inline-flex;align-items:center;gap:.45rem;
  padding:.5rem 1rem;border-radius:var(--r-control);border:1px solid transparent;
  background:var(--foam);color:#04121f;text-decoration:none}
.btn.ghost{background:var(--depth-shallow);color:var(--ink);border-color:var(--line)}
.btn:disabled{cursor:not-allowed;opacity:.55}
.btn.cast{background:linear-gradient(180deg,var(--gold),#e0ac3f);color:#241701;
  font-family:var(--font-display);font-size:1.0625rem;padding:.7rem 1.4rem}

/* An author `display` beats the UA sheet's [hidden] rule, so .btn[hidden] would
   still render. Anything the scripts hide must actually disappear. */
[hidden]{display:none !important}

.muted{color:var(--ink-dim)}
.err{color:var(--bad)}
/* Toasts. The CONTAINER is the fixed element and the toasts are blocks inside
   it — one fixed box per message put every message at the same coordinates, so
   they covered each other instead of stacking (see ui-kit/components-feedback
   for the pattern this follows).

   The stack grows away from the corner it is pinned to, so the newest message
   is always in the same place and an expiring one never shifts the rest.
   z-index clears the sticky masthead's 5. pointer-events are off on the
   container so its empty area never eats a click, and back on for each toast so
   it can be dismissed. */
.toasts{position:fixed;z-index:50;display:flex;flex-direction:column;
  align-items:flex-end;gap:var(--s-2);pointer-events:none;
  right:calc(1rem + env(safe-area-inset-right, 0px));
  bottom:calc(1rem + env(safe-area-inset-bottom, 0px));
  width:min(26rem, calc(100vw - 2rem))}
/* The blur is what keeps the message readable. A toast lands on top of whatever
   happens to be under it — on a phone that is the masthead — and at this alpha
   the text behind it otherwise ghosts straight through. Same device .mast and
   .panel use. */
.toast{pointer-events:auto;cursor:pointer;max-width:100%;backdrop-filter:blur(8px);
  background:#0a2a42ee;border:var(--border);border-left:3px solid var(--bad);
  border-radius:var(--r-control);padding:.85rem 1rem;
  font-size:var(--text-base);line-height:var(--lh-prose);
  box-shadow:var(--shadow-panel);animation:toast-in .18s ease-out}
@keyframes toast-in{from{opacity:0;transform:translateY(.5rem)}to{opacity:1;transform:none}}

@media(max-width:768px){
  .app{padding-left:var(--s-3);padding-right:var(--s-3)}
  .who span:last-child{display:none}
  /* Bottom-right is the one band of a phone screen the browser keeps for
     itself: iOS Safari draws its toolbar over the bottom of the layout viewport
     and the home indicator sits under that, so a toast pinned 16px off the
     bottom edge rendered behind both and never appeared. The top of the layout
     viewport is never overlaid, so the stack goes there and spans the width.
     column-reverse keeps the newest against that top edge. */
  .toasts{top:calc(var(--s-2) + env(safe-area-inset-top, 0px));bottom:auto;
    left:calc(var(--s-3) + env(safe-area-inset-left, 0px));
    right:calc(var(--s-3) + env(safe-area-inset-right, 0px));
    width:auto;align-items:stretch;flex-direction:column-reverse}
  .toast{animation-name:toast-in-top}
}
@keyframes toast-in-top{from{opacity:0;transform:translateY(-.5rem)}to{opacity:1;transform:none}}
