/* =============================================================================
   world.css — Campus World page styles.

   Page-specific sheet loaded only by world.html, following the calendar.css /
   midnight.css precedent. Everything colour-related goes through the design
   tokens in style.css, so the page follows light / dark / oled and the user's
   accent picker like every other page.
   ============================================================================= */

.world-stage {
  position: relative;
  width: 100%;
  height: calc(100svh - var(--nav-h));
  min-height: 340px;
  background: var(--surface);
  overflow: hidden;
}
@media (min-width: 900px) {
  .world-stage { height: calc(100svh - var(--nav-h)); }
}

/* Belt and braces against MapLibre's own .maplibregl-map rule, which sets
   position:relative at the same specificity. The link order in world.html puts
   us last so we win, and the explicit box means that even if some future sheet
   does beat us on `position`, the map still has a size instead of collapsing to
   zero height and rendering an invisible black canvas. */
.world-map {
  position: absolute !important;
  top: 0; left: 0;
  width: 100%; height: 100%;
}
.world-map canvas { outline: none; }

/* ── loading shim ─────────────────────────────────────────────────────────
   The DEM tiles have to land before the buildings can be placed on them, so
   there are a few seconds where the map is real but the campus is not. Cover
   that honestly rather than showing an empty valley. */
.world-shim {
  position: absolute; inset: 0; z-index: 3;
  display: grid; place-items: center;
  background: var(--bg);
  transition: opacity .55s ease;
}
.world-shim.gone { opacity: 0; pointer-events: none; }
.ws-inner { text-align: center; color: var(--text2); }
.ws-peak { font-size: 40px; animation: ws-float 2.6s ease-in-out infinite; }
.ws-inner p { margin: 10px 0 2px; font-weight: 600; color: var(--text); }
.ws-inner small { font-size: 12px; color: var(--text3); }
@keyframes ws-float { 0%, 100% { transform: translateY(0) } 50% { transform: translateY(-7px) } }
@media (prefers-reduced-motion: reduce) { .ws-peak { animation: none } }

/* ── HUD ──────────────────────────────────────────────────────────────── */

.world-hud {
  position: absolute; z-index: 4;
  left: 10px; bottom: 10px;
  display: flex; flex-direction: column; gap: 6px;
  max-width: calc(100% - 20px);
}
body:not(.world-overview) .world-hud { display: none; }
body.world-overview .game-hud,
body.world-overview .touch-controls { display: none !important; }

/* Guest entry */
.world-entry { position:absolute; inset:0; z-index:8; display:grid; place-items:center; padding:18px; background:linear-gradient(rgba(4,10,11,.42),rgba(4,10,11,.66)); backdrop-filter:blur(5px); transition:opacity .25s ease; }
.world-entry.gone { opacity:0; pointer-events:none; visibility:hidden; }
.entry-card { width:min(470px,100%); max-height:calc(100svh - var(--nav-h) - 34px); overflow:auto; padding:24px; border-radius:24px; color:#f7fbfa; background:rgba(10,17,18,.92); border:1px solid rgba(255,255,255,.16); box-shadow:0 25px 70px rgba(0,0,0,.45); }
.entry-peak { font-size:34px; }.entry-kicker { margin:5px 0 3px; font-size:10px; letter-spacing:.18em; font-weight:800; color:#69e0ad; }.entry-card h1{margin:0;font-size:27px}.entry-copy{margin:6px 0 18px;color:#c3ceca;font-size:13px;line-height:1.45}.entry-card label,.entry-label{display:block;margin:0 0 6px;font-size:11px;font-weight:700;color:#dce7e3}.entry-card input{box-sizing:border-box;width:100%;padding:11px 12px;border:1px solid rgba(255,255,255,.2);border-radius:11px;background:rgba(255,255,255,.08);color:#fff;font:inherit;outline:none}.entry-card input:focus{border-color:#69e0ad;box-shadow:0 0 0 3px rgba(105,224,173,.12)}#wEntrySpawn{margin-top:14px}#wEntrySpawn.hidden{display:none}.spawn-choices{display:grid;grid-template-columns:repeat(3,1fr);gap:7px}.spawn-card{min-height:62px;padding:8px 5px;border:1px solid rgba(255,255,255,.15);border-radius:11px;background:rgba(255,255,255,.06);color:#dbe4e1;font:inherit;cursor:pointer}.spawn-card span{display:block;font-size:18px}.spawn-card strong{display:block;font-size:10.5px}.spawn-card.selected{border-color:#69e0ad;background:rgba(42,190,126,.17);color:#fff}.entry-error{height:16px;margin:7px 0 2px;color:#ffaaa5;font-size:11px}.entry-submit{width:100%;padding:12px;border:0;border-radius:12px;background:#22b978;color:white;font:inherit;font-weight:800;cursor:pointer}.entry-submit:disabled{opacity:.55;cursor:wait}.entry-card>small{display:block;margin-top:9px;text-align:center;color:#8fa09a;font-size:10px}

/* In-game HUD */
.game-hud{display:none;position:absolute;z-index:5;inset:10px 50px auto 10px;pointer-events:none;grid-template-columns:auto auto minmax(150px,1fr) auto;align-items:center;gap:7px;color:#fff}.world-playing .game-hud{display:grid}.game-hud button,.hud-stats,.hud-destination{pointer-events:auto;border:1px solid rgba(255,255,255,.16);background:rgba(9,15,16,.76);color:#fff;backdrop-filter:blur(12px);box-shadow:0 4px 18px rgba(0,0,0,.25)}.hud-name{padding:9px 11px;border-radius:12px;font:inherit;font-size:12px;font-weight:700}.online-dot{display:inline-block;width:7px;height:7px;margin-right:6px;border-radius:50%;background:#55dc92}.hud-stats{display:flex;gap:12px;padding:9px 11px;border-radius:12px;font-size:12px}.hud-stats b{font-variant-numeric:tabular-nums}.hud-best{color:#aebbb6}.hud-destination{justify-self:start;display:flex;align-items:center;gap:8px;padding:7px 11px;border-radius:12px}.hud-destination small{font-size:8px;color:#7ddbad;letter-spacing:.1em}.hud-destination strong{font-size:11px}.hud-destination span{font-size:10px;color:#b8c4c0}.hud-actions{display:flex;gap:6px;pointer-events:auto}.hud-actions button{padding:9px 10px;border-radius:12px;font:inherit;font-size:11px;font-weight:700;cursor:pointer}

/* Panels */
.world-panel{position:absolute;z-index:7;top:10px;right:10px;width:min(330px,calc(100% - 20px));max-height:calc(100% - 20px);overflow:auto;box-sizing:border-box;padding:16px;border:1px solid rgba(255,255,255,.15);border-radius:18px;background:rgba(9,15,16,.94);color:#f5faf8;box-shadow:0 20px 50px rgba(0,0,0,.35);transform:translateX(calc(100% + 24px));transition:transform .2s ease}.world-panel.open{transform:translateX(0)}.world-panel header{display:flex;justify-content:space-between;align-items:start;margin-bottom:10px}.world-panel h2{margin:1px 0;font-size:19px}.world-panel header small{font-size:9px;letter-spacing:.15em;color:#60d99e}.world-panel header button{border:0;background:transparent;color:white;font-size:27px;cursor:pointer}.world-panel>p{color:#aebcb7;font-size:12px;line-height:1.45}.landmark-list{display:grid;gap:5px}.landmark-row{display:grid;grid-template-columns:28px 1fr auto;align-items:center;text-align:left;padding:9px;border:0;border-radius:10px;background:rgba(255,255,255,.06);color:white;cursor:pointer}.landmark-row strong{font-size:12px}.landmark-row small{font-size:9px;color:#68dba3}.panel-secondary{width:100%;margin-top:9px;padding:9px;border:1px solid rgba(255,255,255,.16);border-radius:10px;background:transparent;color:#dfe8e5;font:inherit;font-size:11px;cursor:pointer}.collectible-legend{display:flex;flex-wrap:wrap;gap:5px;margin-top:12px}.collectible-legend span{padding:5px 7px;border-radius:8px;background:rgba(255,255,255,.06);font-size:9px}.garage-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}.garage-grid button{padding:14px 8px;border:1px solid rgba(255,255,255,.14);border-radius:12px;background:rgba(255,255,255,.06);color:white;cursor:pointer}.garage-grid span,.garage-grid strong,.garage-grid small{display:block}.garage-grid span{font-size:25px}.garage-grid strong{margin:5px 0 2px}.garage-grid small{color:#9faea9}

/* Touch controls are shown only on coarse pointers. */
.touch-controls{display:none;position:absolute;z-index:5;inset:auto 14px 16px 14px;align-items:end;justify-content:space-between;pointer-events:none}.world-playing .touch-controls{display:none}.joystick{width:108px;height:108px;border:1px solid rgba(255,255,255,.18);border-radius:50%;background:rgba(7,12,13,.35);pointer-events:auto;touch-action:none;display:grid;place-items:center}.joystick span{width:46px;height:46px;border-radius:50%;background:rgba(255,255,255,.7);box-shadow:0 3px 16px rgba(0,0,0,.35);transform:translate(0,0)}.touch-buttons{display:grid;gap:8px;justify-items:end;pointer-events:auto}.touch-buttons button{min-width:70px;padding:12px;border:1px solid rgba(255,255,255,.18);border-radius:999px;background:rgba(8,14,15,.7);color:white;font:inherit;font-size:11px;font-weight:700}.touch-buttons #wAction{min-width:104px;background:rgba(30,165,105,.8)}
@media (pointer:coarse),(max-width:740px){.world-playing .touch-controls{display:flex}.game-hud{inset:8px 44px auto 8px;grid-template-columns:auto 1fr}.hud-destination{display:none}.hud-actions{grid-column:1/-1}.hud-actions button{padding:8px}.hud-best{display:none}.world-readout{display:none}.maplibregl-ctrl-top-right{top:74px}.world-note{display:none}.spawn-choices{gap:5px}.entry-card{padding:18px}.entry-card h1{font-size:23px}}
.wv-row { display: flex; flex-wrap: wrap; gap: 6px; }

.wv-btn {
  appearance: none; cursor: pointer;
  font: inherit; font-size: 12px; font-weight: 600;
  padding: 7px 11px; border-radius: 999px;
  color: var(--text);
  background: var(--glass-bg, rgba(20, 22, 28, .72));
  border: 1px solid var(--glass-border, var(--border));
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  box-shadow: var(--shadow-1, 0 1px 4px rgba(0, 0, 0, .25));
  transition: background var(--transition), border-color var(--transition), transform var(--transition);
}
.wv-btn:hover { background: var(--hover); }
.wv-btn:active { transform: scale(.96); }
.wv-btn.on {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.wv-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.world-readout {
  position: absolute; z-index: 4;
  right: 10px; bottom: 10px;
  font-size: 11px; font-variant-numeric: tabular-nums;
  color: var(--text2);
  background: var(--glass-bg, rgba(20, 22, 28, .72));
  border: 1px solid var(--glass-border, var(--border));
  border-radius: var(--radius);
  padding: 5px 9px;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  pointer-events: none;
}
/* MapLibre's own controls sit top-right; keep the readout clear of the scale bar */
@media (max-width: 520px) {
  .world-readout { bottom: 40px; }
}

/* ── explainer below the stage ────────────────────────────────────────── */

.world-note {
  max-width: 680px;
  margin: 0 auto;
  padding: 16px 14px 80px;
}
.world-note h1 { font-size: 19px; font-weight: 800; margin: 0 0 8px; }
.world-note p { font-size: 13.5px; line-height: 1.55; color: var(--text2); margin: 0 0 10px; }
.world-note .wn-prov {
  font-size: 12px; color: var(--text);
  background: var(--accent-bg); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 7px 10px;
  display: inline-block;
}
.world-note .wn-sub { font-size: 12.5px; color: var(--text3); }
.world-note a { color: var(--accent); }

/* ── fatal fallback ───────────────────────────────────────────────────────
   WebGL can be absent: an old phone, a blocklisted driver, or headless Chrome
   with --disable-gpu (which is how scripts/smoke.mjs opens every page). The
   page must still render something real. */
.world-fallback {
  display: grid; place-items: center; align-content: center;
  gap: 8px; height: 100%; padding: 24px 18px; text-align: center;
}
.world-fallback .wf-icon { font-size: 38px; }
.world-fallback h2 { font-size: 17px; font-weight: 800; margin: 0; }
.world-fallback p { font-size: 13px; color: var(--text2); margin: 0; max-width: 40ch; }
.world-fallback .wf-sub { font-size: 12px; color: var(--text3); }
.world-fallback .btn-primary { margin-top: 8px; text-decoration: none; }

/* When the 3D layer is gone, the stage no longer needs to fill the viewport. */
body.world-dead .world-stage { height: auto; min-height: 300px; }
body.world-dead .world-hud,
body.world-dead .world-readout { display: none; }
