:root {
  --ui-ink: #f2e6bd;
  --ui-muted: #a9b79e;
  --ui-dim: #73806b;   /* disabled states and decorative hairlines only — never running text */
  --ui-well: #0f1813;
  --ui-panel: #1c2921;
  --ui-raised: #2a3a2f;
  --ui-hairline: rgba(198, 168, 91, .5);
  --ui-hairline-soft: rgba(198, 168, 91, .16);
  --font-body: ui-rounded, "Avenir Next", "Trebuchet MS", system-ui, sans-serif;
  --ui-moss-0: #09110d;
  --ui-moss-1: #152119;
  --ui-moss-2: #1b2f22;
  --ui-moss-3: #244534;
  --ui-leaf: #78c884;
  --ui-leaf-bright: #a9e69a;
  --ui-brass: #c6a85b;
  --ui-brass-hi: #f2e6bd;
  --ui-leaded-teal: #2e6e6a;
  --ui-leaded-violet: #5c3b78;
  --ui-berry: #8a3b52;
  --ui-wood: #553b26;
  --ui-blue: #7fc8da;
  --ui-plan: #7fc8da;
  --ui-reflex: #e0c36f;
  --ui-violet: #bfa6f5;
  --ui-danger: #e77d72;
  --ui-shadow: rgba(1, 5, 3, .78);
}

/* Visually hidden labels/status remain available to assistive technology. */
.sr-only {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

/* Canvas actions gain a real DOM mirror for screen readers and keyboard play.
   It stays off-stage until one of its buttons receives focus, then becomes a
   compact ordinary panel instead of leaving a sighted keyboard user stranded
   on an invisible control. */
.nearby-action-mirror {
  position: fixed;
  left: -120vw;
  top: 88px;
  z-index: 30;
  width: min(320px, calc(100vw - 24px));
  max-height: min(55vh, 420px);
  overflow: auto;
  padding: 10px;
  border: 1px solid rgba(198, 168, 91, 0.58);
  border-radius: 12px;
  background: rgba(19, 31, 24, 0.97);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45);
}
.nearby-action-mirror:focus-within { left: 12px; }
.nearby-action-list { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.nearby-action-list li { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.nearby-action-target { flex: 1 0 100%; color: #f2e6bd; font-size: 12px; }
.nearby-action-list button {
  padding: 7px 9px;
  border: 1px solid rgba(131, 149, 122, 0.45);
  border-radius: 8px;
  background: rgba(39, 61, 46, 0.95);
  color: #e6edf3;
  font: inherit;
  font-size: 11px;
}

html, body {
  color: var(--ui-ink);
  font-family: ui-rounded, "Avenir Next", "Trebuchet MS", system-ui, sans-serif;
}

/* One focus ring for everything interactive; selection and focus may coexist. */
:where(button, [role="switch"], [role="button"], input, select, textarea, summary, a):focus-visible {
  outline: 3px solid #d6e9a7;
  outline-offset: 2px;
}
/* Keyboard-key hints mean nothing to a thumb. */
@media (pointer: coarse) { #plancard .keyhint { display: none; } }

.ui-icon {
  --icon-leaf: #5f7d49;
  --icon-fill: .9;
  --icon-stroke: 2.08;
  display: inline-block;
  width: 1.25em;
  height: 1.25em;
  flex: none;
  overflow: visible;
  color: currentColor;
  vertical-align: -.23em;
  filter: drop-shadow(0 1px 0 rgba(0, 0, 0, .55));
  pointer-events: none;
}

#hovermenu .btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }

.gbuy, .shoptab, #shop .btn, .mbtn, #namego, #gback, .gbtn { align-items: center; gap: 7px; }
.gbuy .ui-icon, .shoptab .ui-icon, #shop .btn .ui-icon, .mbtn .ui-icon, #namego .ui-icon, #gback .ui-icon { flex: 0 0 auto; width: 16px; height: 16px; }
.gbuy, .shoptab, #shop .btn, .mbtn, #namego, #gback { display: inline-flex; justify-content: center; }
.gbtn { display: flex; }
.gbtn > .ui-icon { flex: 0 0 auto; width: 25px; height: 25px; color: #e4ce7f; }
.gbtn > span { display: flex; min-width: 0; flex-direction: column; }
.shop-title, .shop-section-title, .shop-state, .shop-hint, #shopwallet, .owned { display: inline-flex; align-items: center; gap: 6px; }
.shop-title, .shop-section-title { color: var(--ui-brass-hi); font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; }
.shop-section-title { margin-bottom: 6px; }
.shop-section-title.divided { display: flex; margin: 10px 0 7px; padding-top: 8px; border-top: 1px solid rgba(205, 169, 93, .18); }
.shop-title .ui-icon, .shop-section-title .ui-icon, .shop-state .ui-icon, .shop-hint .ui-icon, #shopwallet .ui-icon, .owned .ui-icon { width: 15px; height: 15px; }
.shop-state.installed, .owned { color: var(--ui-leaf-bright); }
.shop-state.locked, .shop-hint { color: var(--ui-muted); }
.shop-hint { margin-top: 8px; font-size: 11.5px; }

/* Merchant storefront ------------------------------------------------------
   Zelda clarity (one object, one purpose) with Hades immediacy (price beside
   the choice): shop work gets its own surface instead of borrowing dialogue. */
#merchant {
  position: fixed;
  inset: 0;
  z-index: 22;
  display: none;
  place-items: center;
  padding: 24px;
  box-sizing: border-box;
  background: rgba(3, 8, 5, .76);
  backdrop-filter: blur(5px) saturate(.82);
}
.merchant-shell {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(880px, calc(100vw - 48px));
  max-height: min(780px, calc(100dvh - 48px));
  overflow: hidden;
  background: linear-gradient(150deg, rgba(29, 47, 36, .99), rgba(11, 20, 14, .995));
  border-color: rgba(222, 190, 109, .48);
  box-shadow: 0 0 0 1px rgba(255, 231, 165, .06), 0 28px 90px #000c;
}
.merchant-header {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px 18px;
  border-bottom: 1px solid rgba(205, 169, 93, .24);
  background: linear-gradient(90deg, rgba(205, 169, 93, .09), transparent 56%);
}
#merchantface {
  width: 68px;
  height: 68px;
  flex: 0 0 68px;
  object-fit: contain;
  image-rendering: pixelated;
  border: 1px solid rgba(205, 169, 93, .5);
  border-radius: 13px;
  background: #19271e;
  box-shadow: inset 0 0 18px #0007, 0 4px 18px #0006;
}
.merchant-heading { min-width: 0; }
#merchantname { margin: 2px 0 3px; color: #fff0bd; font: 800 25px/1 var(--font-display); letter-spacing: .02em; }
#merchantline { margin: 4px 0 0; color: #e8dcc0; font: 600 13px/1.35 var(--font-body); font-style: italic; }
/* forge rows: a before/after picture of the stat, not a sentence */
.udiag { display: inline-flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; }
.udiag-row { display: inline-flex; align-items: center; gap: 4px; }
.udiag-row .ui-icon { width: 14px; height: 14px; color: #f0bd62; }
.udiag-pips { display: inline-flex; gap: 2px; }
.udiag-pips i { width: 7px; height: 11px; border-radius: 2px; background: #3a4a36; }
.udiag-pips i.have { background: #9fb89a; }
.udiag-pips i.gain { background: #ffd66b; box-shadow: 0 0 5px rgba(255, 214, 107, .7); }
.udiag-arrow { color: #cbe9b9; font-weight: 800; }
#merchantclose { position: static; margin-left: auto; flex: 0 0 42px; width: 42px; height: 42px; }
.merchant-talk { margin-left: auto; display: inline-flex; align-items: center; gap: 7px; min-height: 42px; padding: 0 16px; color: #fff0bd; background: rgba(205, 169, 93, .14); border: 1px solid rgba(205, 169, 93, .55); border-radius: 11px; font: 800 14px/1 var(--font-display); letter-spacing: .02em; cursor: pointer; }
.merchant-talk:hover, .merchant-talk:focus-visible { background: rgba(205, 169, 93, .28); border-color: #e4ce7f; }
.merchant-talk .ui-icon { width: 18px; height: 18px; }
.merchant-talk + #merchantclose { margin-left: 8px; }
#merchant #shop { display: block; min-height: 0; padding: 14px 18px 18px; overflow-y: auto; font-size: 12px; }
#merchant #shophdr { position: sticky; top: -14px; z-index: 2; margin: -14px -18px 0; padding: 12px 18px 0; background: rgba(14, 25, 18, .98); }
#merchant .shoptab { min-height: 38px; padding: 7px 18px; font-weight: 800; letter-spacing: .03em; }
#merchant #shopwallet { padding: 7px 10px; border: 1px solid rgba(120, 200, 132, .22); border-radius: 999px; background: rgba(32, 66, 40, .36); color: #b8e8a2; font-weight: 750; }
.shop-section + .shop-section { margin-top: 16px; }
.merchant-list { display: grid; gap: 8px; }
.merchant-card {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr) 132px;
  gap: 13px;
  align-items: center;
  min-height: 92px;
  padding: 11px 12px;
  box-sizing: border-box;
  border: 1px solid rgba(180, 204, 172, .14);
  border-radius: 12px;
  background: linear-gradient(105deg, rgba(48, 71, 53, .72), rgba(24, 38, 28, .78));
  transition: border-color .14s ease, transform .14s ease, background .14s ease;
}
.merchant-card:hover { transform: translateY(-1px); border-color: rgba(226, 197, 120, .4); background: linear-gradient(105deg, rgba(54, 79, 59, .84), rgba(28, 44, 32, .86)); }
.merchant-card.installed { opacity: .76; }
.merchant-card-art { display: grid; place-items: center; width: 64px; height: 64px; border-radius: 10px; background: #142219; box-shadow: inset 0 0 0 1px rgba(198, 168, 91, .12); }
.merchant-card-art img { width: 54px; height: 54px; object-fit: contain; image-rendering: pixelated; filter: drop-shadow(0 4px 6px #0008); }
.merchant-card-art .ph { display: grid; place-items: center; width: 46px; height: 46px; border-radius: 50%; color: #09110d; font-size: 20px; font-weight: 800; }
.merchant-card-art.service-art .ui-icon { width: 31px; height: 31px; color: #edce82; }
.merchant-card-art img.forge-art { width: 100%; height: 100%; border-radius: 10px; object-fit: cover; image-rendering: auto; filter: none; }
.merchant-card-copy { min-width: 0; }
.merchant-card h3 { margin: 2px 0 3px; color: #edf4e8; font: 800 15px/1.2 var(--font-display); }
.merchant-card-effect { color: #cbe9b9; font-size: 12.5px; font-weight: 750; }
/* the phrase that uses it, as a little speech chip */
.merchant-card-delivery { display: inline-flex; align-items: center; gap: 5px; margin-top: 6px; padding: 3px 9px 3px 7px; border-radius: 999px; background: rgba(216, 195, 139, .12); color: #e8d49c; font-size: 12px; font-weight: 600; }
.merchant-card-delivery .ui-icon { width: 14px; height: 14px; }
.merchant-card-buy { display: grid; justify-items: stretch; gap: 7px; }
.merchant-card-buy .btn { justify-content: center; min-height: 38px; padding: 7px 10px; color: #241808; background: linear-gradient(180deg, #f0d98e, #c69a49); border-color: #f7e3a4; font-weight: 850; }
.merchant-card-buy .btn:disabled { color: #b7b3a8; background: #343a34; border-color: #555d55; opacity: .62; cursor: not-allowed; }
.merchant-card-art { position: relative; }
.merchant-owned { position: absolute; right: -5px; bottom: -5px; min-width: 22px; padding: 2px 5px; box-sizing: border-box; border-radius: 9px; background: #2c5a37; color: #e6f5d6; font: 700 11px/1.2 var(--font-body); text-align: center; box-shadow: 0 2px 4px #0009; }
.merchant-card-buy .shop-state { justify-content: center; min-height: 38px; padding: 0 6px; text-align: center; }
/* the forge fork (r2 Cairn): the exclusive first tunes as portraits under one lock */
.forge-fork { position: relative; padding: 18px 8px 8px; border: 1px solid rgba(226, 197, 120, .38); border-radius: 12px; background: rgba(20, 30, 22, .7); }
.forge-fork .fork-lock { position: absolute; top: -13px; left: 50%; transform: translateX(-50%); display: inline-flex; align-items: center; gap: 3px; padding: 3px 9px; border-radius: 999px; background: #2a2114; border: 1px solid #e2c578; color: #f3dc98; font: 800 12px/1 var(--font-body); }
.forge-fork .fork-lock .ui-icon { width: 14px; height: 14px; }
.forge-fork .fork-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: 8px; }
.fork-pick { display: grid; justify-items: center; gap: 5px; padding: 8px 6px; border-radius: 10px; background: #142219; text-align: center; }
.fork-pick .fork-art { width: 72px; height: 72px; border-radius: 10px; overflow: hidden; box-shadow: inset 0 0 0 1px rgba(198, 168, 91, .2); }
.fork-pick .fork-art img { width: 100%; height: 100%; object-fit: cover; }
.fork-pick b { color: #edf4e8; font: 800 12.5px/1.2 var(--font-display); }
.fork-pick .btn { justify-content: center; min-height: 36px; width: 100%; padding: 6px 8px; color: #241808; background: linear-gradient(180deg, #f0d98e, #c69a49); border-color: #f7e3a4; font-weight: 850; }
.fork-pick .btn:disabled { color: #b7b3a8; background: #343a34; border-color: #555d55; opacity: .62; }
/* r3 Cairn: a path is chosen by a HOLD. The fill sweeps across the button while the press stays on it and drains when it lets go. */
.fork-pick .fork-hold { position: relative; overflow: hidden; touch-action: none; user-select: none; -webkit-user-select: none; }
.fork-pick .fork-hold::before { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, #fff6c9, #ffd66b); transform: scaleX(0); transform-origin: left; transition: transform .25s ease-in; opacity: .75; pointer-events: none; }
.fork-pick .fork-hold > * { position: relative; }
.fork-pick .fork-hold.holding::before { transform: scaleX(1); transition: transform var(--hold-ms, 900ms) linear; }
.fork-pick .fork-hold.armed, .fork-pick .fork-hold.holding { box-shadow: 0 0 0 2px #fff3c4, 0 0 14px rgba(255, 214, 107, .6); }
.fork-pick .fork-hold.chosen::before { transform: scaleX(1); }
.fork-pick .fork-hold .hold-ring { width: 22px; height: 22px; flex: none; margin-right: 2px; transform: rotate(-90deg); overflow: visible; }
.fork-pick .fork-hold .hold-ring circle { fill: none; stroke-width: 2.6; }
.fork-pick .fork-hold .hold-ring .hr-track { stroke: rgba(36, 24, 8, .3); }
.fork-pick .fork-hold .hold-ring .hr-fill { stroke: #241808; stroke-linecap: round; stroke-dasharray: 100; stroke-dashoffset: 78; animation: hold-ring-breathe 1.6s ease-in-out infinite; }
.fork-pick .fork-hold .hold-ring .hr-tip { fill: #241808; stroke: none; }
.fork-pick .fork-hold.holding .hold-ring .hr-fill { animation: none; stroke-dashoffset: 0; transition: stroke-dashoffset var(--hold-ms, 900ms) linear; }
.fork-pick .fork-hold.chosen .hold-ring .hr-fill { animation: none; stroke-dashoffset: 0; }
.fork-pick .fork-hold:disabled .hold-ring { opacity: .55; }
.fork-pick .fork-hold:disabled .hold-ring .hr-fill { animation: none; }
@keyframes hold-ring-breathe { 0%, 100% { stroke-dashoffset: 86; } 50% { stroke-dashoffset: 62; } }
@media (prefers-reduced-motion: reduce) { .fork-pick .fork-hold .hold-ring .hr-fill { animation: none; } }
/* the decided fork stays as the record: the chosen path lit, the roads not taken greyed under the lock */
.forge-fork.decided { border-color: rgba(226, 197, 120, .22); }
.fork-pick.chosen { box-shadow: inset 0 0 0 2px rgba(126, 231, 135, .55); }
.fork-pick.closed { opacity: .5; filter: grayscale(.9); }
.fork-pick .shop-state { display: inline-flex; justify-content: center; align-items: center; gap: 4px; min-height: 36px; }
#merchant .shopgrid { grid-template-columns: repeat(auto-fill, minmax(138px, 1fr)); }
#merchant .shop-section { margin-top: 12px; }
.gearcard .gslot { display: grid; place-items: center; margin: 3px auto 0; }
.gearcard .gslot .ui-icon { width: 15px; height: 15px; color: #9fbf9a; }
#merchant .gearcard { border: 1px solid rgba(180, 204, 172, .14); background: linear-gradient(150deg, rgba(48, 71, 53, .82), rgba(23, 37, 27, .9)); }
#merchant .sellrow { min-height: 50px; padding: 7px 9px; border: 1px solid rgba(180, 204, 172, .12); border-radius: 10px; background: rgba(40, 61, 45, .48); }

@media (max-width: 620px) {
  #merchant { padding: 0; align-items: end; }
  .merchant-shell { width: 100%; max-height: 92dvh; border-radius: 17px 17px 0 0; border-width: 1px 0 0; }
  .merchant-header { padding: 11px 12px; }
  #merchantface { width: 52px; height: 52px; flex-basis: 52px; }
  #merchantname { font-size: 20px; }
  #merchant #shop { padding: 10px 11px calc(14px + env(safe-area-inset-bottom, 0px)); }
  #merchant #shophdr { top: -10px; margin: -10px -11px 0; padding: 9px 11px 0; }
  .merchant-card { grid-template-columns: 54px minmax(0, 1fr); gap: 9px; padding: 9px; }
  .merchant-card-art { width: 50px; height: 50px; }
  .merchant-card-art img { width: 44px; height: 44px; }
  .merchant-card-buy { grid-column: 1 / -1; grid-template-columns: 1fr; align-items: center; }
  .merchant-card-buy .btn { min-height: 44px; }
  #merchant .sellrow { flex-wrap: wrap; }
  #merchant .sellrow button { min-height: 44px; }
}

.panel {
  position: fixed;
  color: var(--ui-ink);
  /* One background, one border, one shadow. Persistent panels sit light enough
     that they stop punching holes in the sunlit meadow. */
  background: linear-gradient(150deg, rgba(30, 48, 37, .95), rgba(16, 27, 20, .96));
  border: 1px solid var(--ui-hairline);
  border-radius: 14px;
  box-shadow: 0 14px 44px rgba(0, 0, 0, .48);
}
.panel > * { position: relative; z-index: 1; }

.btn,
.rpg-button,
.panel-close {
  min-height: 34px;
  color: var(--ui-ink);
  background: linear-gradient(160deg, #2d533d, #162a20);
  border: 1px solid var(--ui-hairline);
  border-radius: 10px;
  box-shadow: 0 3px 0 rgba(4, 9, 6, .72);
  font-family: inherit;
  font-weight: 700;
  letter-spacing: .02em;
  transition: transform .09s ease, border-color .15s ease, filter .15s ease, box-shadow .15s ease;
}

.btn:hover,
.rpg-button:hover,
.panel-close:hover {
  border-color: var(--ui-brass-hi);
  filter: brightness(1.12);
}

.btn:active,
.rpg-button:active,
.panel-close:active {
  transform: translateY(2px) scale(.97);
  box-shadow: 0 1px 0 rgba(4, 9, 6, .72);
}

.button-label { margin-left: 7px; }

.game-panel-header {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  margin: -2px -1px 10px;
  padding: 0 2px 11px;
  border-bottom: 1px solid var(--ui-hairline-soft);
}

.game-panel-header > .ui-icon,
.panel-title-icon {
  box-sizing: content-box;
  width: 23px;
  height: 23px;
  padding: 8px;
  color: #f2e6bd;
  background:
    radial-gradient(circle, rgba(18, 38, 27, .94) 0 48%, transparent 50%),
    conic-gradient(from -15deg, var(--medallion-a, var(--ui-leaded-teal)) 0 12.5%, #304f4b 12.5% 25%, var(--medallion-b, var(--ui-leaded-violet)) 25% 37.5%, #6b4152 37.5% 50%, #496c42 50% 62.5%, var(--medallion-a, var(--ui-leaded-teal)) 62.5% 75%, #53376e 75% 87.5%, var(--ui-berry) 87.5%);
  border: 2px solid #8f743f;
  border-radius: 50%;
  box-shadow: inset 0 0 0 2px #17231a, inset 0 0 0 3px rgba(242, 230, 189, .28), 0 2px 7px #0009;
}
#places { --medallion-a: #2e6e6a; --medallion-b: #486f5b; }
#bag { --medallion-a: #78633b; --medallion-b: #8a3b52; }
#wardrobe { --medallion-a: #5c3b78; --medallion-b: #8a3b52; }
#settings { --medallion-a: #7a5f38; --medallion-b: #4e6b3f; }

.panel-heading { min-width: 0; flex: 1; }
.panel-kicker {
  margin-top: 2px;
  color: var(--ui-brass);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.panel-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  min-height: 32px;
  padding: 0;
  color: var(--ui-muted);
  cursor: pointer;
}
.panel-close .ui-icon { width: 18px; height: 18px; }
/* A close is just an X (2026-09-24 playtest): no plate, no ring, no shadow.
   Shared by every game panel, so they all match. */
.panel-close,
.panel-close:hover,
.panel-close:active { background: transparent; border-color: transparent; box-shadow: none; }
.panel-close:hover { color: #fff5d5; filter: none; }
/* Painted header art (the same picture as the HUD button that opens the
   panel) stands on its own; the stained-glass medallion stays for the rest. */
.game-panel-header > .panel-title-art {
  flex: none; width: 32px; height: 32px; image-rendering: pixelated;
  filter: drop-shadow(0 2px 0 rgba(0, 0, 0, .4));
}
.panel-count {
  color: var(--ui-brass-hi);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .04em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* A carved field-guide clasp: wood chips, gilded stamps, berry counters. */
#topbtns {
  gap: 7px;
  padding: 7px;
  background: linear-gradient(150deg, rgba(30, 48, 37, .95), rgba(16, 27, 20, .96));
  border: 1px solid var(--ui-hairline);
  border-radius: 14px;
  box-shadow: 0 9px 30px rgba(0, 0, 0, .42);
}

#topbtns .btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  min-height: 42px;
  padding: 0;
  color: #f6e6b8;
  --icon-leaf: #6f8d50;
  background: linear-gradient(155deg, #2a3a2f, #16241b);
  border-color: rgba(198, 168, 91, .4);
  border-radius: 12px;
  box-shadow: 0 3px 0 #0b140e;
}

#topbtns .btn .ui-icon { width: 25px; height: 25px; }
/* Painted 32x32 art (2026-09-24), drawn 1:1 so every pixel stays crisp; the
   same PixelLab style as the Settings tiles. */
#topbtns .btn .hud-art {
  width: 32px; height: 32px; image-rendering: pixelated; pointer-events: none;
  filter: drop-shadow(0 2px 0 rgba(0, 0, 0, .4));
}
#topbtns .btn:hover .ui-icon,
#topbtns .btn:hover .hud-art { animation: fieldguide-wiggle .24s ease-in-out; }
/* The bottom docks joined the painted set (2026-09-27 playtest): the social
   dock's emote + chat and the plan dock's Plan / Write / Speak, same 32x32
   PixelLab style, drawn 1:1 whatever size their button is. */
#socialdock .btn .hud-art, #orders .hud-art {
  width: 32px; height: 32px; image-rendering: pixelated; pointer-events: none;
  filter: drop-shadow(0 2px 0 rgba(0, 0, 0, .4));
}
#socialdock .btn:hover .hud-art, .dockbtn:hover .hud-art, #orders.idle:hover .orders-art { animation: fieldguide-wiggle .24s ease-in-out; }
@keyframes fieldguide-wiggle { 0%, 100% { transform: rotate(0); } 35% { transform: rotate(-3deg) translateY(-1px); } 70% { transform: rotate(2deg); } }
#topbtns .btn[aria-pressed="true"],
#topbtns .btn[aria-expanded="true"],
#topbtns .btn.open {
  color: #fff5c7;
  border-color: var(--ui-brass-hi);
  --icon-leaf: #88aa60;
  background: radial-gradient(circle at 50% 42%, rgba(171, 221, 112, .42), transparent 58%), linear-gradient(155deg, #526c38, #263a24 58%, #182219);
  box-shadow: inset 0 0 10px rgba(179, 230, 114, .2), inset 0 2px 0 rgba(255, 247, 198, .16), 0 0 18px rgba(142, 212, 125, .3);
}
#topbtns #guidebtn { display: none; }

#topbtns .ct,
#bagbtn .ct {
  right: -5px;
  top: -6px;
  min-width: 14px;
  height: 16px;
  padding: 0 4px;
  display: none;
  align-items: center;
  justify-content: center;
  color: #fff0d0;
  background: radial-gradient(circle at 35% 28%, #db7c73, #8a3b52 62%, #4f2232 100%);
  border: 1px solid #f0b39a;
  border-radius: 50%;
  box-shadow: 0 2px 6px #000b;
  font: 700 11px/16px ui-rounded, system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
}
/* The bag count is not actionable information, so the badge stays off. */
#bagbtn .ct { display: none !important; }

/* Hero HUD: portrait/vitals over two large fantasy verbs. */
#hud {
  width: 232px;
  padding: 11px;
  border-color: var(--ui-hairline);
}
#hud .hudrow { gap: 11px; }
#face, #npcface {
  background: radial-gradient(circle at 50% 30%, #436847, #15241b 70%);
  border: 1px solid rgba(229, 204, 142, .62);
  border-radius: 13px;
  box-shadow: inset 0 0 0 2px rgba(4, 10, 6, .5), 0 3px 12px #0008;
}
#hud b { color: #fff2c7; font: 700 16px/1 var(--font-display); letter-spacing: .02em; }
#conn { display: block; margin-top: 3px; color: var(--ui-muted) !important; font-size: 11px; letter-spacing: .06em; text-transform: uppercase; }   /* F46: lifted off --ui-dim for legibility */
#glimmerCt { color: var(--ui-leaf-bright) !important; }
#hpwrap, #xpwrap { border: 1px solid rgba(0, 0, 0, .45); background: #07100b; }
#hpbar { background: linear-gradient(90deg, #477a45, #9ad26f, #d7e985); box-shadow: inset 0 1px 0 #ffffff33; }
#xpbar { background: linear-gradient(90deg, #9a7436, #f0c76d, #fff0a0); }
#xpline { color: var(--ui-muted); font-size: 11px; font-variant-numeric: tabular-nums; }
/* The level lives on the portrait as a brass coin (2026-09-22); the XP bar
   already says how far along it is, so no "0 / 2,800 xp" line repeats it. The
   line under the bars is only the away-pace pitch, and only once there is one.
   Connection state is silent while live: the banner speaks up when it is not. */
#facewrap { position: relative; flex: none; display: inline-block; line-height: 0; }
#lvbadge {
  position: absolute; right: -7px; bottom: -6px; min-width: 20px; height: 20px; padding: 0 4px; box-sizing: border-box;
  display: grid; place-items: center; border-radius: 10px;
  background: linear-gradient(#f1d27d, #c99443); color: #22170e; border: 1px solid #7a5f38;
  font: 700 11px/1 var(--font-body); font-variant-numeric: tabular-nums; box-shadow: 0 2px 4px #0009;
}
#lvbadge:empty { display: none; }
#xpline:empty { display: none; }
#conn.is-live { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* Core inventory/map surfaces. */
#places, #bag, #wardrobe {
  top: 72px;
  right: 14px;
  box-sizing: border-box;
  padding: 13px;
}
#places {
  z-index: 6;
  width: 318px;
  max-height: calc(100dvh - 86px);
  overflow: auto;
}
#places.expanded {
  top: 50%;
  left: 50%;
  right: auto;
  z-index: 20;
  width: min(920px, calc(100vw - 120px));
  max-height: calc(100dvh - 32px);
  transform: translate(-50%, -50%);
  /* scrim law: the takeover map dims the world behind it */
  box-shadow: 0 0 0 100vmax rgba(2, 7, 4, .62), 0 14px 44px rgba(0, 0, 0, .48);
}
#bag { width: 326px; }
#wardrobe { width: 390px; }
#mapexpand {
  width: 34px;
  height: 34px;
  padding: 7px;
  color: #f5dc99;
  cursor: pointer;
}
#mapexpand:hover { border-color: #f1d27d; }
#mapexpand span::before { content: "⛶"; font: 700 18px/1 ui-monospace, monospace; }
#places.expanded #mapexpand span::before { content: "⊡"; }
.map-canvas-wrap {
  position: relative;
  overflow: hidden;
  border: 2px solid rgba(205, 169, 93, .44);
  border-radius: 10px;
  background: #101b13;
  box-shadow: inset 0 0 18px #0008;
}
#minimap, #worldmap {
  width: 100%;
  height: auto;
  display: block;
  box-sizing: border-box;
  cursor: crosshair;
  touch-action: manipulation;
}
.world-map-layout {
  display: block;
  margin-top: 10px;
}
.compact-map-main { display: block; margin-bottom: 8px; }
.world-map-main { display: none; min-width: 0; }
#places.expanded .world-map-layout { display: grid; grid-template-columns: minmax(0, 1fr) 250px; gap: 13px; align-items: start; }
#places.expanded .compact-map-main { display: none; }
#places.expanded .world-map-main { display: block; }
#maplegend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 13px;
  padding: 8px 3px 3px;
  color: #aebba8;
  font: 700 11px/1 ui-rounded, system-ui, sans-serif;
  letter-spacing: .06em;
  text-transform: uppercase;
}
#maplegend span { display: inline-flex; align-items: center; gap: 5px; }
#maplegend i { display: inline-block; width: 8px; height: 8px; box-sizing: border-box; }
.legend-you { border: 2px solid #fff3c4; border-radius: 50%; background: #7fc8da; box-shadow: 0 0 5px #7fc8da; }
.legend-ball { border-radius: 50%; background: #f18b38; box-shadow: 0 0 0 2px #8c3f19; }
.legend-place { transform: rotate(45deg); background: #f1d27d; }
.legend-route { height: 3px !important; background: #a8bc78; box-shadow: 0 1px #32492c; }
#mapstatus {
  min-height: 15px;
  padding: 5px 3px 0;
  color: #d6c99d;
  font: 600 12px/1.35 ui-rounded, system-ui, sans-serif;
}
#maptooltip {
  position: fixed;
  z-index: 70;
  display: none;
  max-width: min(260px, 70vw);
  padding: 7px 9px;
  color: #fff3c4;
  background: rgba(5, 12, 7, .96);
  border: 1px solid rgba(241, 210, 125, .64);
  border-radius: 8px;
  box-shadow: 0 5px 16px #000a;
  font: 700 12px/1.35 ui-rounded, system-ui, sans-serif;
  pointer-events: none;
}
#placelist { display: grid; grid-template-columns: 1fr; gap: 7px; line-height: 1.3; align-content: start; }
#places.expanded #placelist { grid-template-columns: 1fr; }
#placelist .p, #placelist .u { min-width: 0; min-height: 52px; padding: 6px 8px; border-radius: 9px; background: var(--ui-raised); }
#placelist .p {
  appearance: none;
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px;
  width: 100%;
  color: #d8e8cf;
  border: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
#placelist .p:hover { color: #fff0b4; background: rgba(95, 133, 70, .3); }
#placelist .u { display: flex; align-items: center; gap: 9px; color: #849180; }
#placelist .place-fog { flex-wrap: wrap; gap: 6px; min-height: 0; padding: 8px; background: none; }
.place-mystery { display: grid; place-items: center; width: 34px; height: 34px; border: 1px dashed rgba(137, 153, 126, .38); border-radius: 50%; font: 700 16px var(--font-body); }
/* The mob thumbnail is BIGGER than its box on purpose (a tight crop on the
   creature). It must be absolutely centered: as a grid item the oversized auto
   track overflows toward inline-end, which rendered every sprite pulled right
   and clipped (bug report 2026-08-04). Same pattern as #plancard .tgt-art. */
.place-art { position: relative; display: grid; place-items: center; width: 40px; height: 40px; overflow: hidden; border-radius: 10px; background: radial-gradient(circle, rgba(98, 143, 87, .2), rgba(4, 11, 7, .12)); }
.place-art img { position: absolute; top: 50%; left: 50%; width: 58px; height: 58px; object-fit: contain; image-rendering: pixelated; transform: translate(-50%, -50%) scale(1.25); transform-origin: center; }
.place-art .ui-icon { width: 25px; height: 25px; color: var(--ui-plan); }
.place-copy { min-width: 0; }
.place-copy b { display: block; overflow: hidden; color: #eef1da; font: 700 13px/1.2 var(--font-body); text-overflow: ellipsis; white-space: nowrap; }
.place-copy > span { display: block; margin-top: 2px; overflow: hidden; color: #a9b6a4; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
.place-copy .place-warning { display: flex; align-items: center; gap: 4px; color: #e6c98b; }
.place-warning .ui-icon { width: 13px; height: 13px; flex: none; }
.place-badge { padding: 3px 7px; color: var(--threat, #e9cc7e); background: rgba(5, 12, 8, .52); border: 1px solid color-mix(in srgb, var(--threat, #e9cc7e) 48%, transparent); border-radius: 999px; font-size: 11px; font-weight: 700; white-space: nowrap; }
.place-badge.safe { color: #a8d6a1; border-color: rgba(139, 200, 132, .35); }
#baggrid { gap: 8px; }
#baggrid .bagpocket-label { grid-column: 1 / -1; display: flex; align-items: center; gap: 5px; margin-top: 4px; font-size: 11px; color: #d7b8ef; letter-spacing: .04em; }
#baggrid .slot {
  position: relative;
  border: 0;
  border-radius: 10px;
  background: var(--ui-raised);
}
#baggrid .slot:not(.filled)::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 21px;
  background: linear-gradient(145deg, rgba(126, 160, 83, .12), rgba(126, 160, 83, .035));
  border: 1px solid rgba(166, 191, 119, .13);
  border-radius: 100% 0 100% 0;
  transform: translate(-50%, -50%) rotate(34deg);
  box-shadow: inset -3px -3px 7px rgba(0, 0, 0, .2);
}
#baggrid .slot.filled:hover { transform: translateY(-3px) scale(1.04); box-shadow: 0 6px 14px #0007; }
#baggrid .slot.sel { box-shadow: 0 0 0 2px var(--ui-brass-hi), 0 0 14px rgba(242, 230, 189, .35); }
#bagdetail { padding: 11px; border: 0; border-radius: 10px; background: rgba(5, 12, 8, .44); }
.bagdetail-lead { display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: 11px; align-items: center; }
.bagdetail-art { display: grid; place-items: center; width: 62px; height: 62px; border: 0; border-radius: 12px; background: var(--ui-raised); }
.bagdetail-art img, .bagdetail-art .ph { display: grid; place-items: center; width: 54px; height: 54px; object-fit: contain; image-rendering: pixelated; border-radius: 10px; }
.bagdetail-copy { min-width: 0; }
#bagdetail .dn { color: #fff0bd; font: 700 15px/1.25 var(--font-body); }
#bagdetail .dr { margin: 2px 0 4px; font-size: 11.5px; }
#bagdetail .dl { color: #cdd8c2; font-size: 12.5px; font-style: normal; line-height: 1.5; }
#bagdetail .dv { font-size: 12px; }

#dollwrap img.doll {
  box-sizing: border-box;
  width: 112px;
  height: 112px;
  padding: 8px;
  border: 1.5px solid var(--ui-brass);
  border-radius: 50%;
  background: radial-gradient(circle at 50% 32%, #2f5137, #182a1e 72%);
  box-shadow: 0 4px 15px #0009;
}
#slotrow { gap: 8px; }
.wslot {
  border: 0;
  border-radius: 10px;
  background: var(--ui-raised);
}
.wslot .se { opacity: .68; color: #9fbf9a; }
.wslot .se .ui-icon { width: 23px; height: 23px; }
.wslot .sl { color: #8f9e87; }
.wslot.filled { box-shadow: 0 0 0 2px var(--ui-brass-hi); }
/* A worn slot carries its own stat chips (the bag tile's chips, same look), so
   the square gives way to content height; the row still lines up via the grid. */
.wslot.filled { aspect-ratio: auto; padding: 6px 2px 5px; }
.wslot.filled img, .wslot.filled .ph { width: 34px; height: 34px; }
.wslot .wstats { display: flex; flex-wrap: wrap; justify-content: center; gap: 2px; margin-top: 2px; }
.wslot .wstats:empty { display: none; }
.wslot .wstats .stat { padding: 0 3px; border-radius: 5px; font-size: 11px; }
#wbaglist { border-top-color: rgba(205, 169, 93, .22); }
#wbaglist .wrow { min-height: 42px; padding: 8px 3px; border: 0; border-bottom: 1px solid rgba(130, 155, 114, .17); border-radius: 0; background: transparent; }
#wbaglist .wrow:last-child { border-bottom: 0; }
#wbaglist .wrow img, #wbaglist .wrow .ph { width: 34px; height: 34px; }
#wbaglist .wrow .wn { font-size: 13px; }
#wbaglist .wrow .wn small { font-size: 11px; letter-spacing: .04em; }
#wbaglist .wrow button { font-size: 12px; }

/* The tabled Instincts tree's skill-panel stylesheet used to sit here and in
   four later blocks. The parts the Skills menu reuses were repointed into
   viewer/skills-menu.css, which its pack injects only when a world declares
   the block that activates it; the parts that served the POINT-SPEND (the
   point coin, the rank buttons, the apply tray, the branch/tier rails, the
   concord grid) were deleted with the spend. A skill's number moves only by
   playing its mini-game. */

/* Quest tracker: a compact entry into the full behavior codex. */
#orders {
  width: 318px;
  box-sizing: border-box;
  padding: 10px 12px;
  border-color: var(--ui-hairline);
  background: linear-gradient(150deg, rgba(28, 44, 36, .95), rgba(14, 24, 18, .96));
}
#orders:hover { border-color: var(--ui-blue); }
/* No running plan → the card folds to one quiet round button (the entry to the
   Behavior view). The automation HUD only exists while automation is running. */
#orders.idle { width: auto; padding: 9px; border-radius: 50%; }
#orders.idle .orders-title,
#orders.idle .orders-open,
#orders.idle .orders-stop,
#orders.idle #rawcmd,
#orders.idle #taskinfo,
#orders.idle #rules { display: none; }
#orders.idle .orders-head { margin: 0; gap: 0; }
#orders.idle .orders-head > .orders-art { width: 27px; height: 27px; }
.orders-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; color: #e8f2df; }
.orders-head > .orders-art { width: 32px; height: 32px; flex: none; }
.orders-title { font: 700 15px var(--font-display); }
/* the one-tap off-ramp: an unmistakable ✕ Stop pill, same cancel voice as the
   plan view's Stop button */
.orders-stop {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 44px;
  margin-left: auto;
  padding: 0 11px;
  color: #e77d72;
  background: rgba(20, 14, 12, .55);
  border: 1px solid rgba(231, 125, 114, .55);
  border-radius: 999px;
  font: 700 11px var(--font-display);
  letter-spacing: .03em;
  cursor: pointer;
}
.orders-stop .ui-icon { width: 12px; height: 12px; }
.orders-stop:hover { color: #ffb3a8; border-color: #e77d72; background: #3c261f; }
/* the whole panel is the button; a quiet chevron is the only hint */
.orders-open { color: var(--ui-muted); font-size: 16px; line-height: 1; }
#rawcmd {
  overflow: hidden;
  margin: 2px 0 5px;
  color: #e6d79f !important;
  font: 700 12.5px/1.45 ui-rounded, system-ui, sans-serif;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#rules { margin: 5px 0 0; padding-left: 0; color: #b5c4ab; font-size: 12.5px; list-style: none; }
/* the mini panel shows the plan at a glance: the quote plus a strip of action
   marks; the full picture lives one tap deeper in the Behavior view */
#rules .mini-acts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 3px; }
.mini-act { display: inline-grid; place-items: center; width: 28px; height: 28px; color: #eef0cc; background: var(--ui-raised); border-radius: 50%; }
.mini-act .ui-icon { width: 16px; height: 16px; }
.mini-act img { width: 25px; height: 25px; object-fit: contain; image-rendering: pixelated; }
.mini-act.now { box-shadow: 0 0 0 2px var(--ui-plan); animation: miniactnow 1.6s ease-in-out infinite; }
@keyframes miniactnow {
  0%, 100% { box-shadow: 0 0 0 2px var(--ui-plan); }
  50% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--ui-plan) 38%, transparent); }
}
.mini-act.done { opacity: .45; }
.mini-act.more, .mini-act.loop { color: var(--ui-muted); font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums; }
#rules li { margin-top: 3px; line-height: 1.35; }
#rules code { color: #91d1ad; font-family: inherit; }
#taskinfo { color: #9fc4bc; font-size: 12px; }
/* free reflex slots as pips, not "1/4 SLOTS" (r5) */
.rslot-pips { margin-left: auto; display: inline-flex; gap: 4px; }
.rslot-pips i { width: 9px; height: 9px; border-radius: 50%; border: 1px solid rgba(241, 210, 125, .6); }
.rslot-pips i.on { background: #f1d27d; border-color: #ffe9a8; }

/* Behavior Codex: plan, actions, triggers, and saved routines share one wide view. */
#plancard, #planview {
  align-items: center;
  padding: max(18px, env(safe-area-inset-top)) 18px max(18px, env(safe-area-inset-bottom));
  background:
    radial-gradient(circle at 50% 14%, rgba(91, 142, 105, .24), transparent 38%),
    rgba(2, 7, 4, .82);
  backdrop-filter: blur(5px);
}
#plancard .card, #planview .card {
  position: relative;
  box-sizing: border-box;
  max-height: calc(100dvh - 36px);
  padding: 16px;
  color: var(--ui-ink);
  background: linear-gradient(150deg, rgba(30, 50, 38, .99), rgba(10, 20, 14, .995));
  border: 1px solid rgba(198, 168, 91, .6);
  border-radius: 16px;
  box-shadow: 0 24px 90px #000d;
}
#planview .card { width: min(1080px, calc(100vw - 36px)); }
#plancard .card { width: min(820px, calc(100vw - 36px)); }
#plancard .hdr, #planview .hdr { position: relative; align-items: center; margin: 0; padding: 2px 3px 16px; border-bottom: 0; }
#plancard .hdr::after, #planview .hdr::after {
  content: "";
  position: absolute;
  left: 3px;
  right: 3px;
  bottom: 3px;
  height: 1px;
  background: var(--ui-hairline-soft);
}
#plancard .hdr img, #planview .hdr img {
  box-sizing: border-box;
  width: 58px;
  height: 58px;
  padding: 5px;
  border: 2px solid #9b7d42;
  border-radius: 50%;
  background: radial-gradient(circle, #365c3c 0 53%, transparent 55%), conic-gradient(from -12deg, #2e6e6a, #4a4942, #5c3b78, #8a3b52, #4e6b3f, #2e6e6a, #5c3b78, #7a5f38, #2e6e6a);
  box-shadow: inset 0 0 0 2px #142119, 0 3px 10px #0009;
}
#plancard .kicker, #planview .kicker { color: var(--ui-brass); font-size: 11px; font-weight: 700; letter-spacing: .06em; }
#plancard .say, #planview .say { margin-top: 4px; color: #f4efd9; font: 700 16px/1.3 var(--font-body); }
.plan-variable { margin: 0 0 9px; padding: 8px; background: rgba(20, 50, 45, .34); border-radius: 10px; }
.plan-variable-head { display: flex; align-items: baseline; gap: 8px; margin: 0 2px 7px; }
.plan-variable-head b { color: #e9edd9; font-size: 12px; }
.plan-variable-head small { margin-left: auto; color: #98aaa0; font-size: 10.5px; }
.plan-tier-strip {
  display: flex;
  gap: 7px;
  overflow-x: auto;
  padding: 1px 1px 5px;
  overscroll-behavior-inline: contain;
  scrollbar-width: thin;
}
.plan-tier {
  position: relative;
  display: grid;
  flex: 0 0 88px;
  grid-template-rows: 44px auto auto;
  justify-items: center;
  min-width: 88px;
  min-height: 82px;
  padding: 5px 5px 6px;
  color: #eef1de;
  background: linear-gradient(150deg, rgba(38, 83, 71, .88), rgba(12, 32, 27, .94));
  border: 1px solid rgba(118, 190, 177, .62);
  border-radius: 9px;
  cursor: pointer;
}
.plan-tier:hover { border-color: #b7dfd5; }
.plan-tier-art { position: relative; display: grid; place-items: center; width: 44px; height: 44px; overflow: hidden; }
.plan-tier-art img { position: absolute; top: 50%; left: 50%; width: 58px; height: 58px; object-fit: contain; image-rendering: pixelated; transform: translate(-50%, -50%) scale(1.14); }
.plan-tier-art .ui-icon { width: 24px; height: 24px; }
.plan-tier-name { overflow: hidden; width: 100%; font-size: 10.5px; font-weight: 800; text-align: center; text-overflow: ellipsis; white-space: nowrap; }
.plan-tier-meta { color: #d9c47e; font-size: 9.5px; font-variant-numeric: tabular-nums; }
.plan-tier.on::after { content: "✓"; position: absolute; top: 4px; right: 4px; display: grid; place-items: center; width: 17px; height: 17px; color: #102017; background: #addca7; border-radius: 50%; box-shadow: 0 2px 5px #0008; font-size: 10px; font-weight: 900; }
.plan-tier:not(.on) { color: #87978d; background: rgba(12, 22, 18, .78); border-color: rgba(105, 129, 113, .28); opacity: .72; }
.plan-tier:not(.on) .plan-tier-art { filter: grayscale(1) brightness(.62); }
.plan-tier:not(.on) .plan-tier-meta { color: #819087; }
.plan-tier:disabled { cursor: wait; }
.plan-tier.shake { animation: plan-tier-shake .3s ease; }
@keyframes plan-tier-shake { 0%, 100% { transform: none; } 25% { transform: translateX(-3px); } 75% { transform: translateX(3px); } }
#plancard ol.plan, #planview ol.plan { gap: 7px; margin: 7px 0 0; }
#plancard ol.plan li, #planview ol.plan li {
  position: relative;
  min-height: 38px;
  align-items: center;
  gap: 8px;
  padding: 7px 9px;
  color: #dde4d5;
  background: rgba(8, 18, 12, .6);
  border: 0;
  border-radius: 10px;
  font-size: 13px;
  line-height: 1.4;
}
#plancard ol.plan li .pri, #planview ol.plan li .pri { min-width: 56px; color: var(--ui-brass); font-size: 11px; font-weight: 700; letter-spacing: .02em; }
#plancard ol.plan li .aicon, #planview ol.plan li .aicon {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  color: #eef0cc;
  background: linear-gradient(145deg, #3d5334, #1c2c21);
  border: 0;
  border-radius: 50%;
}
#plancard ol.plan li .aicon .ui-icon, #planview ol.plan li .aicon .ui-icon { width: 16px; height: 16px; }
#plancard ol.plan li .aicon img, #planview ol.plan li .aicon img { width: 24px; height: 24px; object-fit: contain; image-rendering: pixelated; }
/* the live rule wears the same pulsing ring as the HUD strip's active mark */
#planview ol.plan li.live .aicon { box-shadow: 0 0 0 2px var(--ui-plan); animation: miniactnow 1.6s ease-in-out infinite; }
#plancard ol.plan li > .rule-x, #planview ol.plan li > .rule-x, #rules .rule-x {
  display: inline-grid;
  place-items: center;
  width: 44px;
  height: 44px;
  min-height: 44px;
  margin-left: auto;
  padding: 0;
  color: #cdbd88;
  background: linear-gradient(155deg, #2b3826, #141b14);
  border: 1px solid rgba(198, 168, 91, .3);
  border-radius: 50%;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05);
  font-size: 0;
}
#plancard ol.plan li > .rule-x .ui-icon, #planview ol.plan li > .rule-x .ui-icon, #rules .rule-x .ui-icon { width: 13px; height: 13px; }
#plancard ol.plan li > .rule-x:hover, #planview ol.plan li > .rule-x:hover, #rules .rule-x:hover { color: #f1c2a9; border-color: #a96553; background: #3c261f; }
.chip { padding: 2px 6px; border-radius: 7px; font-size: 12px; }
#planview .current .ui-icon, #planview .loopline .ui-icon, #planview .meta .ui-icon { width: 13px; height: 13px; vertical-align: -2px; }
.plan-shelf { margin-top: 10px; padding: 10px; background: rgba(4, 11, 7, .42); border: 0; border-radius: 12px; }
.plan-shelf-row { display: flex; flex-wrap: wrap; gap: 6px; }
#planview .shelfbtn { display: inline-flex; align-items: center; gap: 6px; max-width: 280px; min-height: 32px; padding: 6px 9px; color: #e6d28f; background: linear-gradient(145deg, #2d341e, #10180f); border-color: rgba(205, 169, 93, .36); font-size: 11.5px; }
#planview .shelfbtn .ui-icon { width: 15px; height: 15px; }
#plancard .btns, #planview .btns, .plan-actionbar {
  display: flex;
  gap: 7px;
  flex-wrap: wrap;
  position: sticky;
  bottom: -16px;
  z-index: 3;
  margin: 11px -16px -16px;
  padding: 18px 16px 14px;
  background: linear-gradient(transparent, rgba(7, 15, 10, .98) 35%);
}
#plancard .btns button, #planview .btns button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  flex: 1 1 130px;
  min-height: 48px;
  padding: 8px 11px;
  color: #efe9d0;
  background: linear-gradient(160deg, #31543d, #15271c);
  border: 1px solid var(--ui-hairline);
  border-radius: 10px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}
#plancard .btns button .ui-icon, #planview .btns button .ui-icon { width: 18px; height: 18px; }
/* THE primary action: one butter-gold button per screen. */
#plancard .btns .go, #planview .btns .go { color: #22170e; background: linear-gradient(180deg, #f1d27d, #c99443); border-color: #f1d27d; }
#plancard .btns .go .ui-icon, #planview .btns .go .ui-icon { color: #22170e; }
#plancard .btns .alt, #planview .btns .alt { color: #f2d894; background: linear-gradient(160deg, #534b25, #262711); border-color: rgba(225, 192, 101, .65); }
/* Destructive goes ghost: outline and danger text, never a loud fill. */
#plancard .btns .stop, #planview .btns .stop { color: var(--ui-danger); background: transparent; border-color: rgba(231, 125, 114, .55); }
#plancard .btns .no, #planview .btns .no { flex: 0 1 108px; min-width: 96px; white-space: nowrap; color: #9dac98; background: transparent; border-color: rgba(131, 149, 122, .25); }   /* F25: 76px basis wrapped "Keep current" onto two lines */
#plancard .meta, #planview .meta, #plancard .loopline, #planview .loopline, #plancard .current, #planview .current { color: #a7b6a0; font-size: 11.5px; line-height: 1.5; }
.plan-pane .loopline { color: var(--ui-plan) !important; }
.draft-layout { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(220px, .8fr); gap: 10px; margin-top: 10px; }
.draft-layout.solo { grid-template-columns: 1fr; }
.draft-side { display: flex; flex-direction: column; gap: 8px; }
.draft-card { padding: 9px; background: rgba(5, 13, 8, .46); border: 1px solid rgba(143, 167, 126, .2); border-radius: 11px; }
.draft-card-title { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; color: #e8ddbb; font: 800 11px Georgia, serif; }
.draft-card-title .ui-icon { width: 17px; height: 17px; color: var(--ui-brass-hi); }
/* clauses the compiler couldn't honor — shown so a confirm never ratifies a silent loss */
.draft-card.unparsed { border-color: rgba(214, 158, 96, .45); background: rgba(38, 22, 8, .5); }
.draft-card.unparsed .draft-card-title { color: #e0b070; }
.draft-card.unparsed .meta { color: #cfa878; font-style: italic; }
#plancard .targets { display: grid; grid-template-columns: repeat(auto-fit, minmax(145px, 1fr)); gap: 8px; }
#plancard .tgt { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: 66px auto auto; align-items: center; min-width: 0; min-height: 112px; padding: 7px 10px 8px; color: #eff1d9; background: linear-gradient(145deg, rgba(33, 79, 68, .78), rgba(13, 37, 31, .9)); border-color: rgba(104, 184, 177, .62); text-align: left; }
#plancard .tgt:hover { border-color: #a9dad2; background: linear-gradient(145deg, rgba(43, 95, 81, .82), rgba(16, 45, 37, .92)); }
#plancard .tgt-art { position: relative; grid-column: 1 / -1; grid-row: 1; justify-self: center; width: 64px; height: 64px; overflow: hidden; border-radius: 12px; background: radial-gradient(circle, rgba(116, 176, 112, .18), rgba(4, 12, 8, .18) 68%, transparent 70%); }
#plancard .tgt-art img { position: absolute; top: 50%; left: 50%; display: block; width: 82px; height: 82px; object-fit: contain; image-rendering: pixelated; transform: translate(-50%, -50%) scale(1.18); transform-origin: center; }
#plancard .tgt .tl { grid-column: 1 / -1; grid-row: 2; overflow: hidden; justify-self: center; max-width: 100%; font-size: 13px; font-weight: 700; text-align: center; text-overflow: ellipsis; white-space: nowrap; }
#plancard .tgt .tlv { grid-column: 1; grid-row: 3; justify-self: start; color: #f0ce79; font-size: 11.5px; }
#plancard .tgt .tct { grid-column: 2; grid-row: 3; justify-self: end; color: #aebcb1; font-size: 11.5px; font-variant-numeric: tabular-nums; }
#plancard .tgt.on::after { content: "✓"; position: absolute; top: 7px; right: 7px; display: grid; place-items: center; width: 20px; height: 20px; color: #112018; background: #a9d7a2; border: 1px solid #d9efc9; border-radius: 50%; box-shadow: 0 2px 6px #0007; font-size: 12px; font-weight: 700; }
#plancard .tgt:not(.on) { color: #91a196; background: rgba(15, 26, 20, .74); border-color: rgba(111, 133, 116, .34); opacity: .82; }
#plancard .tgt:not(.on) .tgt-art { filter: grayscale(1) brightness(.66); }
#plancard .tgt:not(.on) .tlv, #plancard .tgt:not(.on) .tct { display: none; }
#plancard .tgt:not(.on)::after { content: "Not targeted"; grid-column: 1 / -1; grid-row: 3; justify-self: center; color: #9dcea1; font-size: 11.5px; text-transform: none; }
#plancard .pact-target-note { display: flex; align-items: center; gap: 7px; margin: 7px 0 2px; padding: 6px 8px; color: #d8ceaa; background: rgba(76, 61, 24, .25); border-radius: 8px; font-size: 11.5px; line-height: 1.4; }
#plancard .pact-target-note .ui-icon { width: 17px; height: 17px; flex: none; color: var(--ui-reflex); }
#plancard .pact-target-note { font-size: 12px; }
#plancard .pact-meta-list { display: grid; gap: 5px; margin-top: 7px; }
#plancard .pact-meta-row { display: flex; align-items: center; gap: 7px; min-height: 22px; color: #bac7b5; }
#plancard .pact-meta-row > .ui-icon { width: 17px; height: 17px; color: #9fc9c5; }
/* Oversized thumb in a smaller box: absolute centering, same reasoning as .place-art */
#plancard .pact-mini-art { position: relative; display: grid; place-items: center; width: 32px; height: 32px; overflow: hidden; border-radius: 8px; background: rgba(4, 12, 8, .38); }
#plancard .pact-mini-art img { position: absolute; top: 50%; left: 50%; width: 46px; height: 46px; object-fit: contain; image-rendering: pixelated; transform: translate(-50%, -50%) scale(1.22); transform-origin: center; }
#plancard .pact-meta-row.target-meta { color: #e5e7d2; font-weight: 700; }
#plancard .pact-meta-row { font-size: 12.5px; }
#plancard .rxhdr, #planview .rxhdr, #plancard .tgthdr { display: none; }
#plancard ol.plan.rx li { border-color: rgba(218, 183, 91, .36); background: linear-gradient(145deg, rgba(72, 57, 18, .44), rgba(11, 18, 9, .8)); }

/* Companion Pact: one plain-English consent view, with rules and targets in a
   single scan path. */
#plancard .card { display: flex; flex-direction: column; overflow: hidden; }
#plancard .hdr { flex: none; }
#plancard .hdr > div { min-width: 0; flex: 1; }
#plancard .say { overflow-wrap: anywhere; }
#plancard .pact-body { min-height: 0; overflow: auto; overscroll-behavior: contain; padding: 0 2px 2px; }
#plancard .pact-grid { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(220px, .8fr); gap: 9px; margin-top: 8px; }
#plancard .pact-grid.solo { grid-template-columns: 1fr; }
#plancard .pact-stack { display: flex; flex-direction: column; gap: 7px; }
#plancard .pact-part { padding: 10px 11px; background: rgba(5, 13, 8, .48); border: 0; border-radius: 11px; }
#plancard .pact-part.plan { background: rgba(19, 50, 54, .35); }
#plancard .pact-part.reflex { background: rgba(66, 53, 18, .32); }
/* the Seal Court plan as three pictures (r5 Cairn): leap, slam, charge */
#plancard .court-panels { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
#plancard .court-panel { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 8px 6px 9px; background: rgba(3, 9, 6, .42); border-radius: 10px; }
#plancard .court-panel .cp-art { position: relative; width: 100%; aspect-ratio: 1 / 1; max-width: 132px; border-radius: 9px; overflow: hidden;
  background: radial-gradient(circle at 50% 60%, rgba(200, 117, 47, .28), rgba(20, 14, 10, .9) 70%); }
#plancard .court-panel img { position: absolute; image-rendering: pixelated; }
#plancard .court-panel .cp-move { width: 46%; left: 8%; top: 12%; border-radius: 8px; }
#plancard .court-panel .cp-boss { width: 86%; left: 7%; bottom: 0; }
#plancard .court-panel .cp-mob { width: 44%; right: 6%; bottom: 8%; }
#plancard .court-panel .cp-rift { position: absolute; left: 6%; right: 6%; bottom: 8%; width: 88%; overflow: visible; }
#plancard .court-panel .cp-rift rect { fill: #0b0806; stroke: #5b3a22; stroke-width: 1.5; }
#plancard .court-panel .cp-rift path { fill: none; stroke: #72ded5; stroke-width: 2.5; stroke-dasharray: 5 4; }
#plancard .court-panel .cp-crack { position: absolute; left: 42%; top: 22%; width: 18%; overflow: visible; }
#plancard .court-panel .cp-crack polyline { fill: none; stroke: #fff3c4; stroke-width: 3; stroke-linejoin: round; filter: drop-shadow(0 0 3px #ff6a2a) drop-shadow(0 0 6px #ff6a2a); }
#plancard .court-panel kbd { position: absolute; right: 5px; top: 5px; min-width: 18px; padding: 1px 5px; border-radius: 5px; background: #ffd66b; color: #2a1a08;
  font: 800 11px/1.4 system-ui, sans-serif; text-align: center; }
#plancard .court-panel figcaption { color: #edf1e6; font-size: 13px; line-height: 1.25; text-align: center; font-weight: 700; }
#plancard .pact-title { display: flex; align-items: center; gap: 7px; color: #f0e7c8; font: 700 15px var(--font-display); }
#plancard .pact-title .ui-icon { width: 20px; height: 20px; color: #a9bab0; }
#plancard .pact-part.plan .pact-title .ui-icon { color: var(--ui-plan); }
#plancard .pact-part.reflex .pact-title .ui-icon { color: var(--ui-reflex); }
#plancard .pact-title small { margin-left: auto; color: #aebba8; font: 700 11px ui-rounded, sans-serif; letter-spacing: .04em; text-transform: uppercase; }
#plancard .pact-promise { display: flex; align-items: center; gap: 9px; min-height: 42px; margin-top: 6px; padding: 5px 7px; color: #edf1e6; background: rgba(3, 9, 6, .36); border-radius: 8px; font-size: 13.5px; line-height: 1.4; }
#plancard .pact-promise .aicon, #plancard .pact-promise .ricon { display: grid; place-items: center; width: 34px; height: 34px; flex: none; color: #e8d88e; background: rgba(52, 69, 39, .64); border: 1px solid rgba(205, 169, 93, .26); border-radius: 50%; }
#plancard .pact-promise .aicon .ui-icon { width: 18px; height: 18px; }
#plancard .pact-promise .ricon img { width: 31px; height: 31px; object-fit: contain; image-rendering: pixelated; }
#plancard .pact-effect { margin-top: 7px; padding: 5px 8px; color: #e0d2a5; font-size: 12px; line-height: 1.5; }
#plancard .pact-warning { margin-top: 9px; border-color: rgba(231, 125, 114, .62); background: rgba(63, 27, 19, .58); }
#plancard .pact-warning .draft-card-title, #plancard .pact-warning .meta { color: #f0b2a0; }
#plancard .btns .edit { color: #c9d7c1; background: rgba(20, 34, 25, .82); border-color: rgba(143, 167, 126, .36); }
#plancard .btns .edit { flex: 0 1 92px; min-width: 78px; }
#plancard .pact-close { margin-left: auto; }
#plancard .btns .danger { color: #fff0e9; background: linear-gradient(160deg, #713b30, #381d18); border-color: #d88773; }
#plancard .keyhint { margin-left: auto; padding: 2px 6px; color: #cbe6c3; background: rgba(3, 10, 5, .34); border: 1px solid rgba(206, 239, 190, .22); border-radius: 6px; font-size: 11px; }
#plancard .rxreplace { border-color: rgba(224, 111, 99, .42); background: linear-gradient(145deg, rgba(74, 37, 26, .42), rgba(5, 13, 8, .62)); }
#plancard .rxchoices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; margin-top: 8px; }
#plancard .rxchoice { display: grid; grid-template-columns: auto 28px minmax(0, 1fr); align-items: center; gap: 7px; min-height: 44px; padding: 6px 8px; color: #ded7bd; background: rgba(4, 10, 6, .54); border: 1px solid rgba(199, 158, 96, .28); border-radius: 9px; cursor: pointer; font-size: 11.5px; }
#plancard .rxchoice:has(input:checked) { color: #fff0d2; border-color: #d88773; background: rgba(91, 46, 31, .58); }
#plancard .rxchoice input { width: 18px; height: 18px; accent-color: #d88773; }
#plancard .rxchoice .ricon { display: grid; place-items: center; width: 28px; height: 28px; }
#plancard .rxchoice .ricon img { width: 26px; height: 26px; object-fit: contain; image-rendering: pixelated; }
#plancard .rxchoice small { display: block; margin-top: 2px; color: #a8aa8f; font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
#plancard .pact-face { display: grid; place-items: center; width: 48px; height: 48px; flex: none; background: rgba(54, 58, 25, .72); border: 1px solid rgba(205, 169, 93, .45); border-radius: 50%; }
#plancard .pact-face img { width: 42px; height: 42px; object-fit: contain; image-rendering: pixelated; }
#plancard .btns { position: static; flex: none; bottom: auto; margin: 9px -16px -16px; padding: 10px 16px 14px; background: linear-gradient(rgba(7, 15, 10, .55), rgba(7, 15, 10, .98) 32%); }
#plancard.committing .card { pointer-events: none; }
#plancard.committing .btns button { opacity: .5; }
#plancard .btns button:disabled { opacity: .48; cursor: not-allowed; filter: saturate(.45); }
body.pactreview #chat { display: none !important; }


/* Prompt and chat controls join the same visual language. */
#chat {
  background: linear-gradient(150deg, rgba(24, 47, 35, .98), rgba(7, 15, 10, .99));
  border-color: rgba(205, 169, 93, .68);
  border-radius: 16px;
  box-shadow: 0 18px 60px #000a, inset 0 1px 0 rgba(255, 242, 203, .08);
}
#chatin { gap: 7px; border-top-color: rgba(205, 169, 93, .24); }
#promptflow {
  display: none;
  padding: 9px 11px 8px;
  color: #dce9d4;
  border-top: 1px solid var(--ui-hairline-soft);
  background: rgba(5, 13, 8, .42);
  font-size: 12px;
  line-height: 1.5;
}
#promptflow.show { display: block; }
#promptflow .pf-kicker { color: var(--ui-brass); font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
#promptflow .pf-line { margin-top: 2px; }
#promptflow .pf-utterance { color: #f7f1dd; font-style: italic; }
#promptflow.thinking .pf-line::after { content: ""; display: inline-block; width: 15px; height: 3px; margin-left: 6px; vertical-align: 2px; border-radius: 3px; background: var(--ui-leaf-bright); animation: prompt-breathe .9s ease-in-out infinite; }
body.promptpending #chat { border-color: rgba(169, 230, 154, .9); box-shadow: 0 18px 64px #000a, 0 0 28px rgba(125, 198, 119, .18); }
body.promptpending #cmd { color: #c8d8c1; }
/* Connection state remains visible during a prompt, but leaves the utterance and
   readback lane alone instead of painting over the core interaction. */
body.promptopen #connbanner { top: auto; bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
#chatin button:disabled { opacity: .42; cursor: default; transform: none; }
@keyframes prompt-breathe { 0%,100% { opacity:.2; transform:scaleX(.45); } 50% { opacity:1; transform:scaleX(1); } }
#cmd {
  color: #f7f1dd;
  background: rgba(3, 10, 6, .72);
  border: 1px solid rgba(139, 177, 124, .38);
  border-radius: 10px;
}
#cmd:focus { border-color: #99d58e; box-shadow: 0 0 16px rgba(125, 198, 119, .18); }
#planmode { color: #bac9b1; background: #111e16; border-color: rgba(135, 162, 119, .35); }
#mic, #send { display: none; align-items: center; justify-content: center; width: 44px; min-width: 44px; min-height: 44px; padding: 0; }
#mic .ui-icon, #send .ui-icon { width: 20px; height: 20px; }
#send { display: inline-flex; color: #eaf4df; background: linear-gradient(155deg, #4c7a52, #203d2a); }
#chatlogbtn { display: inline-flex; align-items: center; justify-content: center; width: 42px; height: 42px; padding: 0; }
#chatlogbtn .ui-icon { width: 23px; height: 23px; }
#chatloghdr { color: #d5dfce; border-bottom-color: rgba(205, 169, 93, .22); }

#toast { color: #f4ecd7; background: linear-gradient(150deg, rgba(35, 60, 44, .98), rgba(10, 18, 13, .98)); border-color: var(--ui-brass); border-radius: 12px; box-shadow: 0 8px 28px #0009; }

/* A roll is game grammar, not a throwaway toast. This compact, non-modal card
   teaches the die, the target, and the consequence without pausing play. */
#dicecheck {
  --dc-accent: #79c0ff;
  position: fixed; z-index: 28; top: calc(76px + env(safe-area-inset-top, 0px)); left: 50%;
  width: min(330px, calc(100vw - 28px)); box-sizing: border-box; padding: 10px 13px 11px;
  color: #f7f1dd; text-align: left; pointer-events: none; opacity: 0;
  transform: translate(-50%, -12px) scale(.92);
  background: linear-gradient(155deg, rgba(24, 35, 52, .98), rgba(8, 14, 20, .99));
  border: 1px solid color-mix(in srgb, var(--dc-accent) 72%, #fff 8%); border-radius: 13px;
  box-shadow: 0 14px 42px #000b, 0 0 24px color-mix(in srgb, var(--dc-accent) 24%, transparent);
  transition: opacity .16s ease, transform .28s cubic-bezier(.2, 1.4, .35, 1);
}
#dicecheck.show { opacity: 1; transform: translate(-50%, 0) scale(1); }
#dicecheck.pass { --dc-accent: #8ee6a1; }
#dicecheck.fail { --dc-accent: #ff9bce; }
#dicecheck.tie { --dc-accent: #ffd66b; }
#dicecheck .dc-kicker { color: var(--dc-accent); font: 700 11px/1 var(--font-display); letter-spacing: .09em; text-transform: uppercase; }
#dicecheck .dc-main { display: grid; grid-template-columns: 68px 1fr; align-items: center; gap: 11px; margin-top: 7px; }
/* The die is a hand-rasterized pixel canvas (mmo.js runDiceRollAnim). It is
   larger than its grid slot on purpose: sparks fly past the die's silhouette. */
#dicecheck .dc-die { position: relative; width: 68px; height: 62px; pointer-events: none; }
#dicecheck .dc-die canvas {
  position: absolute; left: 50%; top: 50%; width: 128px; height: 112px; margin: -56px 0 0 -64px;
  image-rendering: pixelated; filter: drop-shadow(0 3px 0 rgba(0,0,0,.42));
}
#dicecheck.reveal .dc-die canvas { animation: dc-die-stamp .3s cubic-bezier(.2, 1.8, .4, 1); }
@keyframes dc-die-stamp { 0% { transform: scale(1.3); } 100% { transform: scale(1); } }
#dicecheck .dc-copy { min-width: 0; }
#dicecheck .dc-rule { color: #d7dfd2; font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; }
#dicecheck .dc-result { margin-top: 3px; color: #fff3c4; font: 700 18px/1.05 var(--font-display); }
#dicecheck .dc-extra { margin-top: 5px; color: #bfcabd; font-size: 11px; line-height: 1.25; }
#dicecheck .dc-extra.unlocked { color: #baf0c3; }
@media (max-width: 560px) {
  #dicecheck { top: calc(140px + env(safe-area-inset-top, 0px)); width: min(310px, calc(100vw - 24px)); }
}
@media (prefers-reduced-motion: reduce) {
  #dicecheck { transition: none; }
  #dicecheck.reveal .dc-die canvas { animation: none; }
}

@media (max-width: 900px) {
  .draft-layout, #plancard .pact-grid { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
  /* width is owned solely by the #hud rule at the bottom of this file — three
     rules used to set it (here, in mmo.html, and there) and the last one quietly
     won, which is how the HUD ended up 1px from the top button column. */
  #hud { padding: 8px; }
  #hud .hudrow { gap: 7px; }
  #topbtns { right: calc(7px + env(safe-area-inset-right, 0px)); gap: 6px; padding: 5px; }
  #topbtns .btn { width: 42px; height: 42px; }
  #places, #bag, #wardrobe {
    top: 8px;
    right: 58px;
    width: calc(100vw - 66px);
    max-width: none;
    max-height: calc(100dvh - 16px);
  }
  /* a near-full-width panel owns the top lane — the HUD steps aside instead of
     sitting on the panel's header and close button (same move promptopen makes) */
  body.menuopen #hud { display: none; }
  #places.expanded {
    top: 8px;
    left: 8px;
    right: 8px;
    width: auto;
    transform: none;
  }
  #places.expanded .world-map-layout { grid-template-columns: 1fr; gap: 9px; }
  /* 2-up at 390px clipped "The Deepwood" / "Bunnyburrow" to "The Deepwo…" / "Bunny…". */
  #places.expanded #placelist { grid-template-columns: 1fr; }
  #maplegend { gap: 5px 9px; }
  #orders { right: calc(8px + env(safe-area-inset-right, 0px)); bottom: calc(8px + env(safe-area-inset-bottom, 0px)); width: min(304px, calc(100vw - 72px)); }
  #plancard, #planview {
    padding: calc(8px + env(safe-area-inset-top, 0px)) calc(8px + env(safe-area-inset-right, 0px)) calc(8px + env(safe-area-inset-bottom, 0px)) calc(8px + env(safe-area-inset-left, 0px));
    align-items: flex-start;
  }
  #plancard .card, #planview .card { width: calc(100vw - 16px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)); max-height: calc(100dvh - 16px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)); padding: 11px; border-radius: 14px; }
  #plancard .hdr img, #planview .hdr img { width: 43px; height: 43px; }
  #plancard .say, #planview .say { font-size: 16px; }
  #plancard .btns, #planview .btns { bottom: -11px; margin: 10px -11px -11px; padding: 12px 11px 10px; }
  #plancard .btns button, #planview .btns button { flex-basis: 42%; }
  #plancard .btns .no, #planview .btns .no { flex-basis: 108px; }   /* F25: keep "Keep current" on one line on phones too */
  #plancard .rxchoices { grid-template-columns: 1fr; }

}

/* The first view after The Descent introduces the durable HUD in layers: the
   character and WRITE/SPEAK controls arrive first, utilities and Behavior next. */
body.arrival-tools-calm #topbtns,
body.arrival-tools-calm #questlog,
body.arrival-behavior-calm #orders {
  opacity: 0;
  pointer-events: none;
}
body.arrival-tools-calm #topbtns,
body.arrival-tools-calm #questlog { transform: translateY(-8px); }
body.arrival-behavior-calm #orders { transform: translateY(10px); }
#topbtns, #questlog, #orders {
  transition: opacity .5s ease, transform .55s cubic-bezier(.2,.9,.25,1);
}

/* On a short landscape phone, reserve the left third for a shorter map so its
   legend remains visible; region cards use the wider right column. */
@media (max-height: 430px) and (orientation: landscape) {
  #places:not(.expanded) {
    top: 8px;
    right: 58px;
    width: min(520px, calc(100vw - 80px));
    max-height: calc(100dvh - 16px);
  }
  #places:not(.expanded) .world-map-layout {
    display: grid;
    grid-template-columns: minmax(240px, 1.2fr) minmax(190px, 1fr);
    gap: 10px;
    align-items: start;
  }
  #places:not(.expanded) .compact-map-main { margin-bottom: 0; }
  #places.expanded {
    top: 8px;
    bottom: 8px;
    left: 8px;
    right: 58px;
    width: auto;
    max-height: none;
    transform: none;
  }
  #places.expanded .world-map-layout {
    grid-template-columns: minmax(250px, 36%) minmax(0, 1fr);
    gap: 10px;
  }
  #places.expanded #placelist { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #places.expanded #maplegend { gap: 4px 8px; padding-top: 6px; }
  #places.expanded #mapstatus { padding-top: 3px; font-size: 11px; }
}

@media (prefers-reduced-motion: reduce) {
  #plancard .card, #planview .card, #plancard .tgt, #plancard .tgt.shake, .plan-tier, .plan-tier.shake,
  #plancard ol.plan li, #plancard .pact-promise, #topbtns .btn {
    animation: none !important;
    transition: none !important;
  }
  #promptflow.thinking .pf-line::after { animation: none !important; opacity: .7; transform: none; }
}

/* ============================================================ display face
   Pixelify Sans: chunky pixel letterforms that stay legible at menu sizes.
   Display voice only — titles, clasps, big labels; body copy keeps the
   rounded system face for maximum readability. */
/* This subset is built with NO `liga` feature, deliberately. The upstream
   Pixelify subset shipped fi/fl/ff ligature GLYPHS that draw the wrong shapes,
   so "High five" rendered "High Ave", "fluffy" rendered "Auffy", and "final"
   rendered "Anal" — in player-facing display copy. Stripping the feature is the
   only fix that also covers canvas text (postcards, arena callouts), because
   ctx.font ignores CSS font-variant-ligatures; and a CSS guard cannot be relied
   on anyway, since the `font:` shorthand resets font-variant-ligatures to
   normal and this codebase uses the shorthand almost everywhere.
   Rebuilt with: pyftsubset <src> --unicodes='*' --glyphs='*'
                 --layout-features='ccmp,locl' --flavor=woff2
   If you ever regenerate this file from upstream, drop `liga` again and
   re-check the words above.
   The C, c, G and 5 outlines are also redrawn (2026-10-02): upstream C was a
   ring with a one-pixel mouth ("CISTERN" read "OISTERN"), G read as 6 and 5
   as S. Reapply research/glow-font-2026-10-02/patch-pixelify.py after any
   regeneration; it asserts nothing else in the font changed. */
/* Pixelify's digits misread at every size (playtest 2026-09-27: a 2 reads as
   Z or 8, a 59 as S9). Digits 0-9 only come from a rounded face, Fredoka
   SemiBold (OFL, a 1.7 KB digits-only subset from Google Fonts), so every
   display-font number stays chunky but legible while letters stay pixel.
   The unicode-range keeps the swap to the ten digits; nothing else changes.
   Canvas text (ctx.font) names its families itself and is not covered. */
:root { --font-display: "Display Digits", "Pixelify Sans", ui-rounded, "Avenir Next", "Trebuchet MS", system-ui, sans-serif; }
/* Regular weight, one-pixel drop (2026-09-24 playtest: the bold face read "too thick"). */
.panel-title { font: 400 20px/1.05 var(--font-display); letter-spacing: .03em; color: #fff5d5; text-shadow: 0 1px 0 #000a; }
/* Takeover screens earn the larger display size. */
#places.expanded .panel-title { font-size: 24px; }
#signcard .st, #incident .it { font-family: var(--font-display); font-weight: 700; letter-spacing: .01em; }
.orders-title { font-family: var(--font-display); letter-spacing: .02em; }

/* ============================================================ quest tracker
   The objectives rail: a clasp under the top buttons, MMO-style. .has = there
   is something to track; .open = pinned open by the player; .peek = the world
   just advanced something, so the rail slides out on its own for a moment. */
#questlog { position: fixed; top: 78px; right: 12px; width: 270px; z-index: 4; display: none; }
#questlog.has { display: block; }
#questhdr {
  display: flex; align-items: center; gap: 7px; width: 100%; cursor: pointer;
  padding: 7px 10px; color: var(--ui-ink);
  background: linear-gradient(180deg, #223828, #17251b);
  border: 1px solid var(--ui-hairline); border-radius: 10px;
  box-shadow: 0 2px 7px #0009;
  font: 700 15px/1 var(--font-display); letter-spacing: .03em;
}
#questhdr:hover { border-color: #c6a85b; }
#questhdr .ui-icon { width: 17px; height: 17px; color: #e4ce7f; }
#questct { color: var(--ui-brass-hi); font-size: 12px; }
#questhdr .qcaret { margin-left: auto; color: var(--ui-muted); transition: transform .2s ease; }
#questlog.open .qcaret { transform: rotate(180deg); }
#questrows { display: none; flex-direction: column; gap: 6px; margin-top: 6px; max-height: min(68vh, 620px); overflow-y: auto; overscroll-behavior: contain; }
#questlog.open #questrows, #questlog.peek #questrows { display: flex; animation: questpeek .22s ease; }
@keyframes questpeek { from { transform: translateX(14px); opacity: 0; } to { transform: none; opacity: 1; } }
#questrows #eventinfo { margin: 0; background-color: rgba(13, 23, 17, .92); box-shadow: 0 1px 5px #0007; }
.favor {
  padding: 9px; border: 1px solid #3f5a43; border-radius: 8px;
  background: rgba(13, 23, 17, .9); box-shadow: 0 1px 5px #0007;
}
.favor.ready { border-color: #e4ce7f; background: linear-gradient(145deg, rgba(53, 58, 28, .96), rgba(20, 33, 23, .96)); box-shadow: 0 0 18px rgba(228, 206, 127, .2), 0 1px 5px #0007; }
.favor.claimed { border-color: #78c884; background: rgba(20, 45, 27, .94); }
.favor-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 6px; }
/* The row itself walks the bunny to the favor (playtest 2026-09-27). */
.favor-go { display: grid; grid-template-columns: 42px minmax(0, 1fr); align-items: center; gap: 9px; min-width: 0;
  padding: 0; margin: 0; color: inherit; background: none; border: 0; border-radius: 8px; font: inherit; text-align: left; }
button.favor-go { cursor: pointer; }
button.favor-go:hover .fname, button.favor-go:focus-visible .fname { color: #fff3c4; text-decoration: underline; text-underline-offset: 3px; }
button.favor-go:focus-visible { outline: 2px solid #e4ce7f; outline-offset: 2px; }
/* The (i): a favor's goal and lore, on the rail and on the board's pins. */
.qinfo { flex: none; display: grid; place-items: center; width: 24px; height: 24px; padding: 0; cursor: pointer;
  color: #e4ce7f; background: rgba(0, 0, 0, .25); border: 1px solid rgba(228, 206, 127, .55); border-radius: 50%;
  font: italic 700 13px/1 Georgia, "Times New Roman", serif; }
.qinfo:hover, .qinfo:focus-visible { color: #22170e; background: #e4ce7f; outline: none; }
.favor-art, .favor-mark { display: grid; place-items: center; width: 40px; height: 40px; object-fit: contain; image-rendering: pixelated; border-radius: 9px; background: radial-gradient(circle, rgba(106, 164, 94, .18), transparent 72%); }
.favor-mark { font-size: 24px; }
.favor-title { min-width: 0; }
.favor .fname { color: #e9f2d9; font: 600 14px/1.2 var(--font-display); }
.favor .fcount { color: var(--ui-leaf-bright); font-size: 11.5px; line-height: 1.3; margin-top: 3px; font-weight: 700; }
.favor.ready .fcount { color: #ffe9a8; font-size: 11px; line-height: 1.3; letter-spacing: .04em; }
.favor.claimed .fcount { color: #9ce082; }
/* The errand as pictures: one tile per step, the step's own object art, a tick when done. */
.favor .fsteps { display: flex; gap: 6px; margin: 7px 0 0; padding: 0; list-style: none; }
.favor .fsteps li { position: relative; width: 34px; height: 34px; display: grid; place-items: center; border-radius: 8px;
  background: #101a13; border: 1px solid #3c5040; }
.favor .fsteps li img { width: 28px; height: 28px; object-fit: contain; image-rendering: pixelated; filter: saturate(.55) brightness(.8); }
.favor .fsteps li.checked { border-color: #9ce082; background: #1b3120; }
.favor .fsteps li.checked img { filter: none; }
.favor .fsteps li b { position: absolute; right: -4px; bottom: -4px; min-width: 15px; height: 15px; border-radius: 50%;
  background: #9ce082; color: #10200f; font: 800 11px/15px var(--font-ui, system-ui); text-align: center; }
.favor .fsteps li b:empty { display: none; }
.favor .fsteps li > button, .favor .fsteps li > .fstep { display: grid; place-items: center; width: 100%; height: 100%; padding: 0;
  color: inherit; background: none; border: 0; border-radius: 8px; font: inherit; }
.favor .fsteps li > button { cursor: pointer; }
.favor .fsteps li:has(> button:hover), .favor .fsteps li:has(> button:focus-visible) { border-color: #e4ce7f; }
/* A short hunt as pips (●●○). */
.favor .fpips { display: flex; flex-wrap: wrap; gap: 3px; margin-top: 6px; }
.favor .fpips i { width: 9px; height: 9px; border-radius: 50%; background: #101a13; border: 1px solid #56705a; }
.favor .fpips i.on { background: #e4ce7f; border-color: #fff3c4; }
.favor.ready .fpips i.on, .favor.claimed .fpips i.on { background: #9ce082; border-color: #d8ffc8; }
.favor .fbar { height: 5px; margin-top: 4px; background: #101a13; border-radius: 4px; overflow: hidden; }
.favor .fbar i { display: block; height: 100%; background: linear-gradient(90deg, #78c884, #e4ce7f); }
.favor.ready .fbar i, .favor.claimed .fbar i { background: linear-gradient(90deg, #e4ce7f, #fff3c4); }
.favor.flash { animation: favorflash 1.1s ease; }
@keyframes favorflash { 0% { border-color: #3f5a43; } 30% { border-color: #ffe9a8; box-shadow: 0 0 18px rgba(255, 233, 168, .5); } 100% { border-color: #3f5a43; } }
body.tut #questlog, body.convo #questlog, body.cine #questlog, body.selftalk #questlog { display: none !important; }
/* A conversation owns the bottom sheet: the plan bar used to float over the log (r3 phone). */
body.convo #orders, body.convo #reflexnow,
body.planlive.convo:not(.menuopen) #topbtns:not(.guide-open) ~ #orders,
body.planlive.convo:not(.menuopen) #orders { display: none !important; }

/* ============================================================ settings */
#settings { top: 52px; right: 12px; width: 288px; padding: 10px 12px; font-size: 12px; display: none; z-index: 6; }
body.dev #settings { width: min(548px, calc(100vw - 24px)); max-height: calc(100dvh - 68px); overflow-y: auto; overscroll-behavior: contain; }
.setrow { display: flex; align-items: center; gap: 12px; padding: 9px 2px; }
.setlabel { flex: 1; min-width: 0; }
.setlabel b { display: block; color: #fff5d5; font: 600 15px/1.15 var(--font-display); letter-spacing: .02em; }
.setlabel small { display: block; margin-top: 2px; color: var(--ui-muted); font-size: 12px; line-height: 1.45; }
.settoggle {
  position: relative; flex: none; width: 64px; height: 34px; cursor: pointer;
  border: 2px solid #8f743f; border-radius: 18px; background: #1c2a20;
  transition: background .18s ease; box-shadow: inset 0 1px 4px rgba(0, 0, 0, .4);
}
.settoggle::before { content: "Off"; position: absolute; top: 50%; right: 7px; color: #9aa694; font: 700 11px/1 ui-rounded, system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; transform: translateY(-50%); }
.settoggle::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 24px; height: 24px;
  border-radius: 50%; background: #73806b; transition: left .18s ease, background .18s ease;
  box-shadow: 0 1px 3px #000a;
}
.settoggle[aria-checked="true"] { background: #2c5a37; }
.settoggle[aria-checked="true"]::before { content: "On"; right: auto; left: 9px; color: #d9edcf; }
.settoggle[aria-checked="true"]::after { left: 33px; background: #f2e6bd; }
.setdivider { height: 2px; margin: 7px 0; background: linear-gradient(90deg, transparent, rgba(198, 168, 91, .55) 18% 82%, transparent); }
/* Under the tiles, one small strip (2026-09-24 playtest: "a little thing that
   shows underneath"): the on-chain pill on the left, the Discord and X marks on
   the right. Lit mark = linked (the handle is its hover); dim mark = tap to
   link. Clover borrows #chainproof and #sociallink separately. */
.setlinks { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
.setlinks > .setdivider { flex: 0 0 100%; }
.setlinks:not(:has(> section:not([hidden]))) { display: none; }
#chainproof[hidden], #sociallink[hidden], .sociallink-note[hidden] { display: none; }
#chainproof { flex: 1 1 auto; min-width: 0; }
.chaingo {
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%; box-sizing: border-box;
  min-height: 34px; padding: 5px 12px 5px 9px; cursor: pointer; text-decoration: none;
  border: 1px solid rgba(241, 210, 125, .45); border-radius: 999px; background: rgba(241, 210, 125, .1);
  color: #f1d27d; font: 600 12px/1 var(--font-body); letter-spacing: .02em; white-space: nowrap;
}
.chaingo:hover { background: rgba(241, 210, 125, .2); border-color: #f1d27d; }
.chaingo .ui-icon { width: 16px; height: 16px; flex: none; }
.chaingo b { color: var(--ui-muted); font: 700 11px/1 ui-monospace, monospace; }
#sociallink { display: contents; }
#sociallink[hidden] { display: none; }
.sociallink-marks { display: flex; gap: 6px; margin-left: auto; }
.sociallink-mark {
  position: relative; display: inline-grid; place-items: center; width: 34px; height: 34px; padding: 0;
  cursor: pointer; border: 1px solid var(--ui-hairline); border-radius: 10px;
  background: var(--ui-raised); color: #8d9a86; transition: background .12s ease, color .12s ease, transform .1s ease;
}
.sociallink-mark .ui-icon { width: 18px; height: 18px; }
.sociallink-mark:hover:not(:disabled) { transform: translateY(-1px); color: #f2e6bd; }
.sociallink-mark:disabled { cursor: default; opacity: .55; }
.sociallink-mark[data-state="linked"][data-social-provider="discord"] { background: #5865f2; border-color: #5865f2; color: #fff; }
.sociallink-mark[data-state="linked"][data-social-provider="x"] { background: #000; border-color: #3a3a3a; color: #fff; }
.sociallink-mark[data-state="confirm"] { background: var(--ui-danger); border-color: var(--ui-danger); color: #1a0c09; }
/* the badge says the state without words: a green check when linked, a gold
   plus when there is something to link */
.sociallink-badge {
  position: absolute; right: -4px; bottom: -4px; width: 14px; height: 14px; border-radius: 50%;
  display: grid; place-items: center; font: 800 10px/1 var(--font-body); font-style: normal;
  border: 2px solid #1a2a20; box-sizing: border-box;
}
.sociallink-mark[data-state="linked"] .sociallink-badge { background: #3fb950; color: #0d1a10; }
.sociallink-mark[data-state="linked"] .sociallink-badge::before { content: "✓"; }
.sociallink-mark[data-state="open"] .sociallink-badge { background: #f1d27d; color: #22170e; }
.sociallink-mark[data-state="open"] .sociallink-badge::before { content: "+"; }
.sociallink-mark[data-state="confirm"] .sociallink-badge,
.sociallink-mark[data-state="busy"] .sociallink-badge { display: none; }
.sociallink-note { flex: 0 0 100%; padding: 2px 2px 0; color: var(--ui-muted); font-size: 12px; line-height: 1.45; }
.setlogout {
  flex: none; padding: 9px 14px; white-space: nowrap; cursor: pointer;
  background: transparent;
  border-color: rgba(231, 125, 114, .55); color: var(--ui-danger);
  font: 700 13px/1 var(--font-body); letter-spacing: .02em;
}
.setlogout.arm { background: var(--ui-danger); color: #1a0c09; box-shadow: 0 0 14px rgba(231, 125, 114, .45); }

/* Settings tiles (2026-09-22): picture + one word per control. The real
   control is stretched over its whole tile, so the tile IS the button; its old
   subtitle survives only as the accessible description. Everything is scoped
   to #settings .settiles: Clover borrows these rows into its own sheet, where
   they fall back to the plain row look above. */
#settings { width: 324px; }
.settile-art { display: none; }
#settings .settiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; padding: 6px 0 4px; }
#settings .settile {
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  gap: 4px; min-height: 96px; padding: 10px 4px 9px; box-sizing: border-box;
  border-radius: 12px; background: var(--ui-raised);
  box-shadow: inset 0 1px 0 rgba(242, 230, 189, .08), 0 2px 0 rgba(0, 0, 0, .28);
  transition: transform .12s ease, background .12s ease;
}
#settings .settile:hover { background: #33473a; transform: translateY(-1px); }
#settings .settile:active { transform: translateY(1px); }
#settings .settile-art {
  display: block; width: 56px; height: 56px; image-rendering: pixelated; pointer-events: none;
  filter: drop-shadow(0 3px 0 rgba(0, 0, 0, .35)); transition: filter .18s ease, opacity .18s ease;
}
#settings .settile .setlabel { flex: none; text-align: center; pointer-events: none; }
#settings .settile .setlabel b { font: 600 12px/1.2 var(--font-body); letter-spacing: .03em; color: #f2e6bd; }
#settings .settile .setlabel small {
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
/* the control covers the tile: one big target, its own chrome gone */
#settings .settile > button {
  position: absolute; inset: 0; width: auto; height: auto; min-height: 0; margin: 0; padding: 0;
  border: 0; border-radius: inherit; background: transparent; box-shadow: none;
  color: transparent; font-size: 0; cursor: pointer;
}
#settings .settile > button > * { display: none; }
#settings .settile > .settoggle::before { content: none; }
/* a toggle's state is the picture: lit when on, a sleeping grey when off */
#settings .settile > .settoggle::after {
  content: ""; top: 8px; right: 8px; left: auto; width: 10px; height: 10px;
  background: #3fb950; box-shadow: 0 0 8px rgba(63, 185, 80, .8);
}
#settings .settile > .settoggle[aria-checked="false"]::after { background: #55604f; box-shadow: none; }
#settings .settile:has(> .settoggle[aria-checked="false"]) .settile-art { filter: grayscale(1) brightness(.62); opacity: .7; }
#settings .settile:has(> .settoggle[aria-checked="false"]) .setlabel b { color: var(--ui-muted); }
/* WASD: the picture is four keycaps in the keyboard's own cross. A phone has
   no keys to hold, so the tile only exists where a real pointer does. */
#settings .settile-keys {
  display: grid; grid-template-columns: repeat(3, 17px); grid-template-rows: repeat(2, 17px);
  gap: 3px; place-content: center;
}
#settings .settile-keys kbd {
  display: grid; place-items: center; border-radius: 4px; background: #f2e6bd; color: #2a3a2e;
  font: 700 11px/1 var(--font-body); box-shadow: 0 2px 0 #9c8f62;
}
@media (hover: none) and (pointer: coarse) { #settings .settile[data-tile="wasd"] { display: none; } }
/* Switch is destructive: ember label, and the armed second tap reads on the tile */
#settings .settile[data-tile="switch"] .setlabel b { color: var(--ui-danger); }
#settings .settile > .setlogout.arm {
  background: var(--ui-danger); color: #1a0c09; font: 700 13px/1.2 var(--font-body);
  box-shadow: 0 0 14px rgba(231, 125, 114, .45); display: grid; place-items: center; padding: 8px;
}
#settings .settile:has(> .setlogout.arm) .settile-art,
#settings .settile:has(> .setlogout.arm) .setlabel { visibility: hidden; }

/* The test bench is present only after the local server's /dev handshake. It is
   intentionally denser than player settings: this is an instrument panel. */
#devadmin[hidden] { display: none; }
/* Dev bench bug capture: the BUG button + its note panel. Purple like the rest
   of the bench — tooling, not game UI. The button ships hidden; only the /dev
   handshake reveals it, so production can never grow a bug button. */
#bugbtn[hidden] { display: none; }
#bugbtn { font: 700 11px/1 var(--font-display); letter-spacing: .08em; color: #eadbff; border-color: #403950; background: linear-gradient(160deg, #33294d, #1a1526); }
#bugpanel { top: 52px; right: 12px; width: min(430px, calc(100vw - 24px)); padding: 10px 12px; font-size: 12px; display: none; z-index: 6; border-color: #403950; }
.bugbody { display: grid; gap: 9px; }
.bughint { color: var(--ui-muted); font-size: 12px; line-height: 1.45; }
#bugnote { min-width: 0; width: 100%; box-sizing: border-box; resize: vertical; min-height: 128px; padding: 9px 11px; border: 1px solid #403950; border-radius: 7px; color: #f0edf6; background: #0d1119; font: 500 13px/1.5 var(--font-body); outline: none; }
#bugnote:focus { border-color: #b993ef; box-shadow: 0 0 0 2px rgba(137,87,229,.16); }
.bugactions { display: flex; justify-content: flex-end; gap: 8px; }
.devhead { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 7px 2px 9px; }
.devhead > div { display: flex; align-items: center; gap: 8px; }
.devhead b { color: #f3eaff; font: 600 17px/1 var(--font-display); }
.devhead > span { color: #8e83a7; font-size: 11px; letter-spacing: .06em; text-transform: uppercase; }
.devbadge { padding: 4px 7px; border: 1px solid rgba(210,168,255,.65); border-radius: 999px; color: #eadbff; background: rgba(137,87,229,.18); font-size: 10px; font-weight: 700; letter-spacing: .06em; }
.devsection { margin: 7px 0; padding: 11px; border: 1px solid rgba(137,87,229,.32); border-radius: 10px; background: linear-gradient(145deg,rgba(25,20,39,.82),rgba(13,18,25,.78)); box-shadow: inset 0 1px rgba(255,255,255,.025); }
.devsection-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 9px; }
.devsection-head b { color: #f0e9ff; font: 600 15px/1.1 var(--font-display); }
.devsection-head small { color: #8e83a7; font-size: 11px; letter-spacing: .05em; text-transform: uppercase; }
.devticks, .devfilters { display: flex; flex-wrap: wrap; gap: 5px; }
.devticks button, .devfilters button { min-height: 29px; padding: 5px 9px; border: 1px solid #4a4260; border-radius: 7px; color: #aeb5c4; background: #171824; font: 700 11px/1 var(--font-body); cursor: pointer; }
.devticks button:hover, .devfilters button:hover { border-color: #9b77db; color: #f0e9ff; }
.devticks button.active, .devfilters button.active { border-color: #d2a8ff; color: #fff6d8; background: linear-gradient(145deg,#513277,#2b2548); box-shadow: 0 0 12px rgba(137,87,229,.25); }
.devstatgrid { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); gap: 7px; }
.devstatgrid label, .devlibrary-tools label { display: grid; gap: 4px; color: #9790a9; font-size: 11px; letter-spacing: .05em; text-transform: uppercase; }
.devstatgrid input, .devlibrary-tools input, .devlibrary-tools select, .devsearch { min-width: 0; box-sizing: border-box; border: 1px solid #403950; border-radius: 7px; color: #f0edf6; background: #0d1119; font: 600 12px/1 var(--font-body); outline: none; }
.devstatgrid input { width: 100%; height: 33px; padding: 6px 8px; }
.devstatgrid input:focus, .devlibrary-tools input:focus, .devlibrary-tools select:focus, .devsearch:focus { border-color: #b993ef; box-shadow: 0 0 0 2px rgba(137,87,229,.16); }
.devstep { display: grid; grid-template-columns: 30px minmax(0,1fr) 30px; }
.devstep button { border: 1px solid #403950; color: #d8c9f2; background: #252038; cursor: pointer; font-size: 15px; }
.devstep button:first-child { border-radius: 7px 0 0 7px; }
.devstep button:last-child { border-radius: 0 7px 7px 0; }
.devstep input { border-radius: 0; text-align: center; border-inline: 0; }
.devactions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 9px; }
.devactions .btn, .devlibrary-tools .btn { padding: 7px 9px; font-size: 11px; }
.devprimary { border-color: #9b77db; color: #eadbff; background: rgba(137,87,229,.2); }
.devmoverow { display: flex; align-items: center; gap: 12px; }
.devmoverow span { flex: 1; color: #a69fba; font-size: 11.5px; line-height: 1.45; }
.devmoverow .btn { flex: none; padding: 9px 12px; white-space: nowrap; }
.devsearch { width: 100%; height: 38px; padding: 8px 11px; margin-bottom: 7px; }
.devfilters { margin-bottom: 8px; }
.devlibrary-tools { display: grid; grid-template-columns: 1fr 92px auto auto; align-items: end; gap: 6px; margin-bottom: 8px; }
.devlibrary-tools input, .devlibrary-tools select { width: 100%; height: 31px; padding: 5px 7px; }
.devitems { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: 6px; max-height: 288px; overflow-y: auto; padding-right: 3px; overscroll-behavior: contain; }
.devitem { display: grid; grid-template-columns: 40px minmax(0,1fr); gap: 8px; align-items: center; min-width: 0; padding: 8px; border: 1px solid #343044; border-radius: 9px; background: rgba(9,12,18,.72); }
.devitem-art { width: 40px; height: 40px; display: grid; place-items: center; }
.devitem-art img { width: 38px; height: 38px; object-fit: contain; image-rendering: pixelated; filter: drop-shadow(0 4px 4px #0009); }
.devitem-main { min-width: 0; }
.devitem-main b { display: block; overflow: hidden; color: #e9edf7; font: 600 12px/1.2 var(--font-body); text-overflow: ellipsis; white-space: nowrap; }
.devitem-main small { display: block; margin-top: 2px; color: #7f8798; font-size: 11px; line-height: 1.3; }
.devitem-buttons { display: flex; gap: 4px; margin-top: 6px; }
.devitem-buttons button { min-height: 25px; flex: 1; padding: 4px 6px; border: 1px solid #453b5d; border-radius: 6px; color: #d8c9f2; background: #211b31; font: 700 11px/1 var(--font-body); cursor: pointer; }
.devitem-buttons button:hover { border-color: #b993ef; color: #fff6d8; }
.devempty { grid-column: 1/-1; padding: 24px 8px; color: #81798e; text-align: center; }
.devdanger { border-color: rgba(231,125,114,.35); background: rgba(56,23,30,.22); }
.devresetrow { display: flex; align-items: center; gap: 12px; }
.devresetrow span { flex: 1; color: #a69da5; font-size: 11.5px; line-height: 1.45; }
.devresetrow .setlogout { font-size: 12px; }

@media (max-width: 700px) {
  /* the phone HUD owns the top-left and the button column owns the right edge —
     the tracker hangs just below the buttons, hugging the same edge */
  #questlog { top: 230px; right: 8px; width: min(216px, calc(100vw - 24px)); }
  /* open rows must not sit on the player mid-screen: cap them and scroll inside */
  #questrows { max-height: 34dvh; }
  /* A phone map is visually busy enough that even 90%-opaque cards let names,
     sprites, and target brackets compete with the favor copy. The expanded
     rail gets one solid backing surface; individual card tints can stay rich
     without allowing the world to print through the text. */
  #questlog.open #questrows, #questlog.peek #questrows {
    padding: 6px;
    border: 1px solid var(--ui-hairline);
    border-radius: 10px;
    background: #0d1711;
    box-shadow: 0 8px 24px #000b;
  }
  /* A long-press choice is the active phone task. Do not leave the quest clasp
     under its callout: the same vertical lane belongs to exactly one surface. */
  body.actionmenu #questlog { display: none !important; }
  /* the bunny's bubble is the primary feedback channel at phone zoom — the
     collapsed clasp shares its band, so it ducks while a bubble is live */
  body.selfbubble #questlog:not(.open) { opacity: .12; pointer-events: none; transition: opacity .25s; }
  #settings { top: 12px; right: 60px; max-width: calc(100vw - 72px); }
  body.dev #settings { width: min(548px, calc(100vw - 72px)); }
}
body.menuopen #questlog { display: none; }

/* Compact viewport ownership -------------------------------------------------
   The field guide rail and a single open surface own the right/top lanes on a
   phone. Keep the canvas visible, but remove controls that would sit under an
   open panel and make the controls that remain comfortable touch targets. */
@media (max-width: 560px), (max-height: 430px) and (orientation: landscape) {
  body.menuopen #hud,
  body.menuopen #orders,
  body.menuopen #topbtns,
  body.menuopen #chatlog,
  body.menuopen #socialdock, body.menuopen #chatlogbtn { display: none; }

  #topbtns .btn,
  .panel-close,
  #mapexpand,
  #chatlogbtn,
  #chatloghdr button {
    width: 44px;
    min-width: 44px;
    height: 44px;
    min-height: 44px;
  }
  .panel-close { flex: 0 0 44px; }
  .panel-close,
  #mapexpand,
  #chatloghdr button { display: inline-grid; place-items: center; padding: 0; }
  #questhdr,
  #placelist .p,
  .shoptab,
  .gearcard .gbuy,
  #shop .sellrow button,
  #duelbar button,
  #wbaglist .wrow button,
  .setlogout,
  #setseeya,
  #photobtn,
  #setreport { min-height: 44px; }
  #baguse, #bagequip, #bagkeep, #bagdrop, #bagorder {
    min-height: 44px;
    box-sizing: border-box;
    font-size: 13px !important;
    padding: 8px 12px !important;
  }
  #placelist .p { display: grid; align-items: center; }

  .settoggle { min-height: 44px; border-radius: 23px; }
  .settoggle::after { top: 6px; width: 28px; height: 28px; }
  .settoggle[aria-checked="true"]::after { left: 29px; }
}

/* Match mmo.js's compactMenuQuery exactly. Combat strips the utility rail back
   to Map; survival controls in the HUD and Behavior card remain available. */
@media (max-width: 700px), (max-height: 430px) and (orientation: landscape) {
  body.danger #questlog { display: none !important; }
  body.danger #guidebtn,
  body.danger #gearbtn,
  body.danger #setbtn { display: none !important; }
  /* Bag stays: the minute HP moves is the minute a phone player needs a carrot.
     Do not restore the whole rail. */
  body.danger #topbtns #bagbtn { display: inline-flex !important; }
}

@media (max-width: 560px) {
  /* THE one phone-HUD width. It has to stop short of the #topbtns column, and
     every term below is a real measurement of that column rather than a round
     number: 14px HUD left offset + 7px column right offset + 5px column padding
     + 44px button + a 10px gutter = 80px, plus both safe-area insets (100vw
     includes them, so they must be subtracted explicitly). The previous 72px
     left exactly 1px of daylight between the HUD and the buttons. */
  #hud {
    width: calc(100vw - 80px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
  }
  #topbtns {
    top: calc(7px + env(safe-area-inset-top, 0px));
    right: calc(7px + env(safe-area-inset-right, 0px));
  }

  /* Guide and Map never jump when the secondary tools are disclosed. */
  #topbtns #guidebtn { display: inline-flex; order: 0; }
  #topbtns #mapbtn { order: 1; }
  /* Companion takes the free slot 2. Without an explicit order it fell to the default 0 and,
     sitting before #guidebtn in the DOM, sat ABOVE the Field Guide at the top of the column. */
  #topbtns #petbtn { order: 2; }
  #topbtns #gearbtn { order: 3; }
  #topbtns #bagbtn { order: 5; }
  #topbtns #setbtn { order: 6; }
  /* Stable slots (r3 phone): the dev bug button always sorts last. Unordered, it
     sorted ahead of Map the moment danger hid the guide, and a thumb reaching
     for the book landed on it; last, its late reveal never moves a player button. */
  #topbtns #bugbtn { order: 99; }
  #topbtns:not(.guide-open) #gearbtn,
  #topbtns:not(.guide-open) #bagbtn,
  #topbtns:not(.guide-open) #setbtn,
  #topbtns:not(.guide-open) #mapbtn { display: none; }
  /* WOR-19 four-surface law: a phone shows the HUD (health), ONE guide
     button, the chat launcher and emote paw, and the plan dock (talk: the
     quill and mic live there since 2026-09-25). Quests still reveal with the
     guide strip. A LIVE plan grows the dock into a bar, see body.planlive. */
  #topbtns:not(.guide-open) ~ #questlog { display: none !important; }
  #topbtns:not(.guide-open) ~ #socialdock #chatlogbtn::after { display: none; }
  /* the revealed quest rail steps left of the full button column */
  #topbtns.guide-open ~ #questlog { right: 58px; width: min(216px, calc(100vw - 70px)); }
  /* Combat still strips the rail: danger hides the guide (rule above), so
     Map takes that slot as the escape tool. Bag stays via the danger rule. */
  body.danger #topbtns #mapbtn { display: inline-flex !important; }
  /* A running plan is state, not a menu. One chip + Stop even with the rail
     closed and even in danger. The full Behavior card stays behind the guide.
     But an OPEN menu panel owns the whole compact screen (WOR-19): while
     body.menuopen the chip yields like every other surface, or the Stop
     button floats interactively over the bag/map/settings sheet. */
  body.planlive:not(.menuopen) #topbtns:not(.guide-open) ~ #orders,
  body.planlive:not(.menuopen) #orders {
    display: flex !important;
    flex-direction: column;
    left: calc(64px + env(safe-area-inset-left, 0px));
    right: calc(8px + env(safe-area-inset-right, 0px));
    bottom: calc(72px + env(safe-area-inset-bottom, 0px));
    width: auto;
    max-width: none;
    padding: 8px 10px;
    z-index: 20;
  }
  body.planlive #orders #rules,
  body.planlive #orders #taskinfo,
  body.planlive #orders .orders-open { display: none; }
  body.planlive #orders #rawcmd {
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 11px;
  }
  body.planlive #ordersstop { min-height: 44px; min-width: 72px; }
  /* The Descent hides the disclosure until the loot lesson grants the bag; the
     Between (also body.tut) keeps it, so a traveler can open bag/settings and
     see their things survived the crossing. */
  body.tut:not(.tutbag) #guidebtn { display: none !important; }

  #places {
    top: calc(8px + env(safe-area-inset-top, 0px));
    right: calc(8px + env(safe-area-inset-right, 0px));
    left: calc(8px + env(safe-area-inset-left, 0px));
    width: auto;
    max-height: calc(100dvh - 16px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
    overscroll-behavior: contain;
  }
  #places:not(.expanded) .world-map-layout {
    grid-template-columns: minmax(260px, 38%) minmax(0, 1fr);
  }
  #places.expanded {
    top: calc(8px + env(safe-area-inset-top, 0px));
    right: calc(8px + env(safe-area-inset-right, 0px));
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    left: calc(8px + env(safe-area-inset-left, 0px));
    width: auto;
    max-height: none;
  }
  #bag,
  #wardrobe,
  #settings {
    top: auto;
    right: calc(8px + env(safe-area-inset-right, 0px));
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    left: calc(8px + env(safe-area-inset-left, 0px));
    width: auto;
    max-width: none;
    max-height: min(72dvh, calc(100dvh - 16px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)));
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  }
  body.dev #settings { width: auto; }
  .devstatgrid { grid-template-columns: repeat(2,minmax(0,1fr)); }
  .devlibrary-tools { grid-template-columns: 1fr 84px; }
  .devitems { grid-template-columns: 1fr; max-height: 42dvh; }


  #world3card .cta { min-height: 44px; box-sizing: border-box; padding: 12px 20px; }
  #world3card .onward { min-height: 44px; padding: 12px 8px; }
  #world3card { box-shadow: 0 0 0 100vmax rgba(2,3,8,.9), 0 0 90px rgba(233,189,94,.28), 0 0 160px rgba(140,120,255,.22); }

  #naming .panel2 {
    width: calc(100vw - 24px);
    max-width: 360px;
    box-sizing: border-box;
    padding: 22px 18px calc(18px + env(safe-area-inset-bottom, 0px));
  }
  #nameinp { width: min(240px, 100%); min-height: 44px; font-size: 16px; }
  #namego { min-height: 44px; }
  /* Keyboard up: pin the naming panel to the visible strip so the CTA is not
     under the keys. Idle (no kb) stays centred — that's the pretty beat. */
  body.kb #naming {
    align-items: flex-end;
    padding: 12px 12px calc(12px + env(safe-area-inset-bottom, 0px) + var(--kb, 0px));
  }
  #merchant .shoptab { min-height: 44px; }
  #dicecheck { top: calc(176px + env(safe-area-inset-top, 0px)); }
}

/* Short landscape has width to spend. Keep the consent actions fixed, use two
   columns for the plan itself, and let only the compact pact body scroll. */
@media (min-width: 620px) and (max-height: 430px) and (orientation: landscape) {
  #plancard, #planview {
    padding: calc(6px + env(safe-area-inset-top, 0px)) calc(6px + env(safe-area-inset-right, 0px)) calc(6px + env(safe-area-inset-bottom, 0px)) calc(6px + env(safe-area-inset-left, 0px));
  }
  #plancard .card, #planview .card {
    width: calc(100vw - 12px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
    max-height: calc(100dvh - 12px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
    padding: 10px;
  }
  #plancard .hdr, #planview .hdr { padding-bottom: 10px; }
  #plancard .hdr img, #planview .hdr img { width: 42px; height: 42px; }
  #plancard .pact-grid:not(.solo) { grid-template-columns: minmax(0, 1.15fr) minmax(240px, .85fr); gap: 8px; }
  #plancard .pact-promise { min-height: 38px; padding-block: 3px; }
  #plancard .btns { margin: 7px -10px -10px; padding: 9px 10px 8px; }
}

/* The narrowest portrait gets genuine owned surfaces and a one-glance Behavior
   summary. The full rules, task detail, resume chain, and Stop action remain in
   the Codex opened by tapping the summary card. */
@media (max-width: 360px) {
  #places,
  #places.expanded,
  #bag,
  #wardrobe,
  #settings {
    top: calc(6px + env(safe-area-inset-top, 0px));
    right: calc(6px + env(safe-area-inset-right, 0px));
    bottom: calc(6px + env(safe-area-inset-bottom, 0px));
    left: calc(6px + env(safe-area-inset-left, 0px));
    width: auto;
    height: auto;
    max-width: none;
    max-height: none;
    box-sizing: border-box;
    overflow-y: auto;
    transform: none;
  }

  #orders { padding: 8px 10px; }
  #orders .orders-head { margin-bottom: 3px; }
  #orders #taskinfo { display: none; }
  #orders #rawcmd { margin: 1px 0 2px; }
}

/* An open surface owns short landscape and stays inside the safe viewport.
   This also prevents Behavior from sitting beneath the two-column compact map. */
@media (max-height: 430px) and (orientation: landscape) {
  #topbtns {
    top: calc(7px + env(safe-area-inset-top, 0px));
    right: calc(7px + env(safe-area-inset-right, 0px));
  }
  #topbtns #guidebtn { display: inline-flex; order: 0; }
  #topbtns #mapbtn { order: 1; }
  /* Companion takes the free slot 2. Without an explicit order it fell to the default 0 and,
     sitting before #guidebtn in the DOM, sat ABOVE the Field Guide at the top of the column. */
  #topbtns #petbtn { order: 2; }
  #topbtns #gearbtn { order: 3; }
  #topbtns #bagbtn { order: 5; }
  #topbtns #setbtn { order: 6; }
  /* Stable slots (r3 phone): the dev bug button always sorts last. Unordered, it
     sorted ahead of Map the moment danger hid the guide, and a thumb reaching
     for the book landed on it; last, its late reveal never moves a player button. */
  #topbtns #bugbtn { order: 99; }
  #topbtns:not(.guide-open) #gearbtn,
  #topbtns:not(.guide-open) #bagbtn,
  #topbtns:not(.guide-open) #setbtn,
  #topbtns:not(.guide-open) #mapbtn { display: none; }
  /* WOR-19 four-surface law, landscape edition: same reveal set as portrait.
     The strip is a row here, so the quest rail keeps its base spot below it. */
  #topbtns:not(.guide-open) ~ #questlog { display: none !important; }
  #topbtns:not(.guide-open) ~ #socialdock #chatlogbtn::after { display: none; }
  body.danger #topbtns #mapbtn { display: inline-flex !important; }
  /* Same menu-ownership exception as the narrow block: an open panel wins. */
  body.planlive:not(.menuopen) #topbtns:not(.guide-open) ~ #orders,
  body.planlive:not(.menuopen) #orders { display: flex !important; }
  /* Same scoping as the narrow block: pre-bag Descent only, never the Between. */
  body.tut:not(.tutbag) #guidebtn { display: none !important; }
  #places:not(.expanded) {
    top: calc(8px + env(safe-area-inset-top, 0px));
    right: calc(8px + env(safe-area-inset-right, 0px));
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    left: calc(8px + env(safe-area-inset-left, 0px));
    width: auto;
    max-width: none;
    max-height: none;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  #places:not(.expanded) .world-map-layout {
    grid-template-columns: minmax(260px, 38%) minmax(0, 1fr);
  }
  #places.expanded {
    top: calc(8px + env(safe-area-inset-top, 0px));
    right: calc(8px + env(safe-area-inset-right, 0px));
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    left: calc(8px + env(safe-area-inset-left, 0px));
    width: auto;
    max-height: none;
    transform: none;
  }
  #bag {
    top: calc(8px + env(safe-area-inset-top, 0px));
    right: calc(8px + env(safe-area-inset-right, 0px));
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    left: auto;
    width: min(326px, calc(100vw - 16px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)));
    max-width: none;
    max-height: none;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  #wardrobe {
    top: calc(8px + env(safe-area-inset-top, 0px));
    right: calc(8px + env(safe-area-inset-right, 0px));
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    left: auto;
    width: min(390px, calc(100vw - 16px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)));
    max-width: none;
    max-height: none;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  #settings {
    top: calc(8px + env(safe-area-inset-top, 0px));
    right: calc(8px + env(safe-area-inset-right, 0px));
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    left: auto;
    width: min(288px, calc(100vw - 16px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)));
    max-width: none;
    max-height: none;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}

/* ============================================================ mobile batch
   Phones are read at arm's length: reading surfaces bump to 15px, the consent
   card becomes a bottom sheet with its actions in the thumb zone. */
@media (max-width: 560px) {
  #plancard { align-items: flex-end; }
  #plancard .card { border-radius: 16px 16px 10px 10px; }
  #convolog, .sbody, #bagdetail .dl, #plancard .pact-promise { font-size: 15px; line-height: 1.5; }
  #plancard .say { font-size: 17px; }
}

/* The dev bench folds shut inside Settings: one tap opens the instrument panel. */
#devadmin > summary { cursor: pointer; list-style: none; }
#devadmin > summary::-webkit-details-marker { display: none; }

/* Progression v4 -----------------------------------------------------------
   What is left of the block that sat at the end of the cascade for the
   51-node tree: the technique tray, which survived the tabling. */
.tech-mark { position: absolute; right: -2px; bottom: -4px; display: grid; place-items: center; width: 16px; height: 16px; color: #ffe3a0; background: #263127; border: 1px solid #d5ae5b; border-radius: 50%; font-size: 9px; }
#techtray { margin: 8px 0 10px; }
.techtray-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; }
.techtray-head b { color: #f0d88f; font: 700 13px var(--font-display); }
.techtray-head small { color: #899586; font-size: 10px; }
.technique-grid { display: grid; grid-template-columns: repeat(5,minmax(0,1fr)); gap: 6px; }
.technique-card { min-width: 0; padding: 4px; background: rgba(9,16,11,.56); border: 1px solid rgba(205,172,91,.18); border-radius: 11px; }
.technique-chip { width: 100%; min-height: 52px; display: grid; grid-template-columns: 29px minmax(0,1fr); grid-template-rows: 1fr 1fr; align-items: center; gap: 0 6px; padding: 6px 8px; color: #e9eddf; text-align: left; background: linear-gradient(150deg,#28382d,#142119); border: 1px solid rgba(205,172,91,.34); border-radius: 8px; }
.technique-chip > span { grid-row: 1/3; font-size: 21px; }
.technique-chip b { overflow: hidden; font-size: 10.5px; text-overflow: ellipsis; white-space: nowrap; }
.technique-chip small { color: #a6b29f; font-size: 9px; }
.technique-chip.kind-signature { border-color: #d3ad57; background: linear-gradient(145deg,#49391f,#1c251b); box-shadow: inset 0 0 14px rgba(222,179,84,.08); }
.technique-chip.active { border-color: #f0d47d; box-shadow: inset 0 0 18px rgba(227,190,86,.2), 0 0 12px rgba(227,190,86,.12); }
.technique-chip:disabled { filter: saturate(.45); opacity: .64; }
.technique-teach { width: 100%; min-height: 44px; margin-top: 4px; padding: 5px 7px; color: #d7c98f; background: rgba(31,48,35,.7); border: 1px solid rgba(197,164,78,.25); border-radius: 7px; font: 800 10px var(--font-body); }
.technique-teach.taught { color: #9ed5ad; border-color: rgba(104,190,128,.28); }
.technique-teach .ui-icon { width: 13px; height: 13px; vertical-align: -2px; }
.quarry-readout { display: flex; align-items: center; gap: 7px; margin: 0 0 7px; padding: 7px 9px; color: #e5cf89; background: rgba(91,69,28,.32); border: 1px solid rgba(215,178,79,.3); border-radius: 9px; }
.quarry-readout > .ui-icon { width: 22px; height: 22px; }
.quarry-readout b, .quarry-readout small { display: block; }
.quarry-readout b { font-size: 10px; text-transform: uppercase; letter-spacing: .07em; }
.quarry-readout small { color: #dce5d4; font-size: 11px; }

@media (max-width: 900px) {
  .technique-grid { grid-template-columns: repeat(3,minmax(0,1fr)); }
}
@media (max-width: 560px) {
   .technique-chip small { font-size: 10px; }
  .technique-grid { grid-template-columns: repeat(2,minmax(0,1fr)); }
}
#devadmin > summary .devhead, #devadmin > summary { user-select: none; }
#devadmin[open] > summary { margin-bottom: 2px; }

/* ============================================================ throw HUD
   A held toy roots the bunny, so the screen grows one temporary control: the
   power meter. It sits on the LEFT edge, vertically centred — out of the way of
   the bottom prompt bar and the top button rail, and crucially never between the
   player and the spot they are aiming at. Hidden entirely unless something is
   actually in the bunny's paws. */
#throwhud {
  position: fixed;
  left: 14px;
  top: 50%;
  z-index: 40;
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  padding: 11px 10px 10px;
  color: var(--ui-ink);
  background: linear-gradient(150deg, rgba(30, 48, 37, .95), rgba(16, 27, 20, .96));
  border: 1px solid var(--ui-hairline);
  border-radius: 14px;
  box-shadow: 0 9px 30px rgba(0, 0, 0, .42);
  transform: translateY(-50%);
  animation: throwhud-in .18s ease-out;
}
body.holding #throwhud { display: flex; }
@keyframes throwhud-in { from { opacity: 0; transform: translate(-8px, -50%); } }

#throwmeter {
  position: relative;
  width: 20px;
  height: 168px;
  overflow: hidden;
  background: linear-gradient(180deg, #0c1410, #131f18);
  border: 1px solid var(--ui-hairline-soft);
  border-radius: 11px;
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, .55);
}
/* fills bottom-up, and shifts green -> brass -> hot as it tops out, so the
   full-power moment is legible from peripheral vision mid-aim */
#throwfill {
  position: absolute;
  right: 2px;
  bottom: 2px;
  left: 2px;
  height: 0;
  background: linear-gradient(0deg, var(--ui-leaf) 0%, var(--ui-leaf-bright) 55%, #ffe08a 100%);
  border-radius: 9px;
  transition: height .05s linear;
}
#throwhud.full #throwfill { background: linear-gradient(0deg, #ffd66b, #fff3c4 60%, #fff); box-shadow: 0 0 14px rgba(255, 214, 107, .75); }
#throwhud.full #throwmeter { border-color: var(--ui-brass-hi); }
/* the notch at the top: "this is what a full send looks like" */
#throwpeak { position: absolute; right: 2px; left: 2px; top: 12%; height: 1px; background: var(--ui-hairline); opacity: .7; }

#throwlabel { text-align: center; }
#throwlabel b { display: block; color: #fff2c7; font: 700 12px/1.25 var(--font-display, var(--font-body)); letter-spacing: .04em; text-transform: uppercase; }
#throwlabel span { display: block; max-width: 92px; color: var(--ui-muted); font: 500 10px/1.3 var(--font-body); }
#dropbtn { width: 100%; padding: 6px 8px; font-size: 11px; }

/* Phones: the rail moves to the bottom-left corner and lies flat, so it never
   fights the on-screen keyboard or the thumb reaching for the prompt. */
/* r2: it sits ABOVE the paw/chat dock (it used to cover the paw button), the
   empty meter only appears while a press is charging, and until then the bar
   shows what to do: a finger and "hold the map to throw". */
@media (max-width: 560px) {
  #throwhud { top: auto; left: 14px; right: 14px; bottom: calc(122px + env(safe-area-inset-bottom, 0px)); flex-direction: row; align-items: center; justify-content: space-between; transform: none; animation: none; }
  #throwmeter { display: none; width: 132px; height: 18px; flex: 1; }
  #throwhud.charging #throwmeter { display: block; }
  #throwfill { top: 2px; right: auto; bottom: 2px; width: 0; height: auto; transition: width .05s linear; }
  #throwpeak { top: 2px; right: 12%; bottom: 2px; left: auto; width: 1px; height: auto; }
  #throwlabel { display: flex; align-items: center; gap: 8px; text-align: left; }
  #throwlabel span { max-width: none; font-size: 12px; }
  #throwlabel span::before { content: "👆"; margin-right: 5px; font-size: 16px; display: inline-block; animation: throw-finger 1.3s ease-in-out infinite; }
  #throwhud.charging #throwlabel span { display: none; }
  #dropbtn { width: auto; flex: none; min-height: 40px; padding: 8px 14px; }
  /* r5: with a plan running, its bar owns the strip this tray used to take;
     the tray rides above the move buttons instead. */
  body.planlive #throwhud { bottom: calc(240px + env(safe-area-inset-bottom, 0px)); }
}
@keyframes throw-finger { 0%, 100% { transform: translateY(0); } 45% { transform: translateY(3px) scale(.9); } }
@media (prefers-reduced-motion: reduce) { #throwlabel span::before { animation: none; } }

/* ============================================================ Stoneframe action bar
   Cairn's direct-play verbs live in one predictable MMO action-bar slot: bottom
   centre, clear of the right-side Behavior card and below every decision
   surface. It remains visible during danger and uses honest touch targets. */
#suitdock {
  position: fixed;
  left: 50%;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  z-index: 19;
  display: none;
  gap: 5px;
  align-items: flex-end;
  max-width: calc(100vw - 148px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
  -webkit-touch-callout: none;
  user-select: none;
  -webkit-user-select: none;
  transform: translateX(-50%);
}
body.stoneframe #suitdock { display: flex; }
/* Plans, prompts, conversations and menus own the player's attention. Besides
   saving phone space, yielding here prevents an inert combat control from ever
   painting over the plan it cannot affect. Plan review already sets selftalk. */
body.promptopen #suitdock,
body.tutprompt #suitdock,
body.convo #suitdock,
body.selftalk #suitdock,
body.storefront #suitdock,
body.menuopen #suitdock { display: none; }
/* Aster's compact action bar, in Cairn's basalt and forge light: no panel,
   each slot is its painted art with the key in the corner. Charge and Jump hop
   out into their move; the mortar fires without leaving the tub. */
#suitdock .suit-move {
  position: relative;
  display: block;
  width: 54px;
  height: 54px;
  min-width: 0;
  min-height: 0;
  padding: 0;
  overflow: hidden;
  background: #121a1c;
  border: 2px solid rgba(119, 226, 218, .62);
  border-radius: 11px;
  box-shadow: 0 3px 9px rgba(0, 0, 0, .66);
  touch-action: manipulation;
}
#suitdock .suit-art { position: absolute; inset: 0; display: block; }
#suitdock .suit-art img { display: block; width: 100%; height: 100%; image-rendering: pixelated; pointer-events: none; }
#suitdock .suit-move:hover:not(:disabled), #suitdock .suit-move:focus-visible, #suitdock .suit-move.aiming {
  border-color: #f0bd62;
  box-shadow: 0 0 12px rgba(240, 189, 98, .45), 0 3px 9px rgba(0, 0, 0, .66);
}
#suitdock .suit-move:focus-visible { outline: 2px solid #fff3c4; outline-offset: 2px; }
#suitdock .suit-move.aiming .suit-art img { filter: brightness(1.18) saturate(1.1); }
#suitdock .suit-move:disabled { cursor: default; border-color: rgba(152, 163, 150, .45); }
#suitdock .suit-move:disabled .suit-art img { filter: grayscale(.55) brightness(.55); }
/* The heal slot (key 4, research/hud-quick-slots-2026-10-05.md step one): the
   same mechanism as Aster's fourth slot in the suit's basalt. The art is the
   item the bag would eat (an Ember Cell first) and the badge is its count,
   brass on moss at the 11px floor. Hidden until the bag has held a heal; grey
   through the shared :disabled look when a press would be refused. */
#suitdock .suit-move[hidden] { display: none; }
#suitdock .suit-heal .heal-art { background: #152119; }
#suitdock .suit-heal .heal-art img { padding: 9px; box-sizing: border-box; object-fit: contain; }
#suitdock .suit-heal .heal-n {
  position: absolute; right: 2px; top: 2px; z-index: 1; min-width: 9px; padding: 0 3px;
  border-radius: 3px; background: rgba(10, 18, 19, .92); color: #c6a85b;
  font: 700 11px/14px ui-rounded, system-ui, sans-serif; font-style: normal; font-variant-numeric: tabular-nums; text-align: center;
}
#suitdock .suit-heal .heal-n:empty { display: none; }
/* the cooldown coming back: one bright pulse, then quiet — an invitation, not a nag */
#suitdock .suit-move.ready-ping { animation: suit-ready-ping .7s ease-out; }
/* the move a scene is asking for (the Listener's read, the first-arrival kit
   demo): a steady invitation until the player answers it */
#suitdock .suit-move.cue:not(:disabled) { animation: suit-cue 1.1s ease-in-out infinite; border-color: #ffd66b; }
@keyframes suit-cue {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 214, 107, .7); transform: translateY(0); }
  50% { box-shadow: 0 0 0 7px rgba(255, 214, 107, 0); transform: translateY(-2px); }
}
@media (prefers-reduced-motion: reduce) { #suitdock .suit-move.cue:not(:disabled) { animation: none; box-shadow: 0 0 0 3px rgba(255, 214, 107, .8); } }
/* the Listener's open seal (r5 Cairn): the JUMP slot is THE button. It grows,
   burns gold and wears a NOW badge; one press slams the seal at full power. */
#suitdock .suit-move.seal-now:not(:disabled) { animation: suit-seal-now .55s ease-in-out infinite; border-color: #fff3c4; z-index: 2; }
#suitdock .suit-move.seal-now:not(:disabled)::after { content: "NOW"; position: absolute; left: 50%; top: 3px; transform: translateX(-50%); z-index: 3;
  padding: 1px 6px; border-radius: 7px; background: #ffd66b; color: #2a1a08; font: 800 11px/1.3 system-ui, sans-serif; letter-spacing: .06em;
  box-shadow: 0 0 10px rgba(255, 214, 107, .8); pointer-events: none; }
@keyframes suit-seal-now {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 214, 107, .95), 0 0 18px rgba(255, 150, 60, .6); transform: translateY(-2px) scale(1.1); }
  50% { box-shadow: 0 0 0 10px rgba(255, 214, 107, 0), 0 0 26px rgba(255, 150, 60, .9); transform: translateY(-4px) scale(1.16); }
}
@media (prefers-reduced-motion: reduce) { #suitdock .suit-move.seal-now:not(:disabled) { animation: none; transform: scale(1.1); box-shadow: 0 0 0 4px #ffd66b; } }
/* the window opening: a third of a second where the court holds its breath */
body.sealtime #c { filter: saturate(.35) contrast(1.18) brightness(.82); transition: filter .08s ease-out; }
body:not(.sealtime) #c { transition: filter .26s ease-in; }
@keyframes suit-ready-ping {
  0% { box-shadow: 0 0 0 0 rgba(255, 214, 107, .85), inset 0 0 13px rgba(240, 189, 98, .3); filter: brightness(1.8); }
  100% { box-shadow: 0 0 0 16px rgba(255, 214, 107, 0), inset 0 0 13px rgba(240, 189, 98, 0); filter: brightness(1); }
}
/* The name lives in the tooltip; <small> is live state only. A cooldown is a
   count over the dimmed art (Aster's shape); an aiming step is a caption. */
#suitdock b { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
#suitdock small { display: none; pointer-events: none; }
#suitdock .suit-move[data-cap="cd"] small {
  position: absolute; inset: 0; display: grid; place-items: center;
  color: #fff3c4; font: 700 15px/1 ui-rounded, system-ui, sans-serif; text-shadow: 0 2px 3px #000c;
}
#suitdock .suit-move[data-cap="note"] small {
  position: absolute; right: 2px; bottom: 3px; left: 2px; display: block; padding: 2px 1px;
  border-radius: 4px; background: rgba(8, 14, 15, .86); color: #fff3c4;
  font: 700 11px/1.05 var(--font-body); text-align: center; letter-spacing: -.01em;
}
#suitdock .suit-move[data-cap="note"] .suit-key { display: none; }
#suitdock .suit-key {
  position: absolute;
  right: 2px;
  bottom: 2px;
  z-index: 1;
  min-width: 9px;
  padding: 0 3px;
  color: #fff3c4;
  background: rgba(10, 18, 19, .92);
  border-radius: 3px;
  font: 700 10px/13px system-ui, sans-serif;
  text-align: center;
}
#suitdock .suit-cd { position: absolute; right: 0; bottom: 0; left: 0; z-index: 2; height: 3px; background: #6bd9cf; transform-origin: left; }
.suit-tip {
  position: absolute; bottom: calc(100% + 8px); left: 50%; width: max-content;
  max-width: min(240px, calc(100vw - 32px)); transform: translateX(-50%); padding: 7px 9px;
  border: 1px solid rgba(119, 226, 218, .36); border-radius: 9px; background: rgba(16, 26, 28, .96);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .5); color: #eef6ef;
  font: 500 12px/1.35 ui-rounded, system-ui, sans-serif; text-align: left; pointer-events: none;
}
.suit-tip[hidden] { display: none; }
#suitdock .suit-tip b { position: static; width: auto; height: auto; overflow: visible; clip: auto; font: 700 12px/1.35 ui-rounded, system-ui, sans-serif; letter-spacing: 0; }
.suit-tip kbd { margin-left: 6px; padding: 0 4px; border-radius: 3px; background: #0a1213; color: #fff3c4; font: 700 10px/14px system-ui, sans-serif; }
.suit-tip span { display: block; margin-top: 3px; color: #cfe0da; }
#suitpower { display: none; position: absolute; right: 4px; bottom: calc(100% + 6px); left: 4px; height: 8px; overflow: hidden; background: #0b1516; border: 1px solid rgba(119,226,218,.35); border-radius: 8px; }
#suitdock.jump-hold #suitpower { display: block; }
#suitdock.jump-hold .suit-tip { display: none; }
#suitpower > i { display: block; width: 0; height: 100%; background: linear-gradient(90deg, #62d6ce, #f0bd62 70%, #fff3c4); box-shadow: 0 0 10px rgba(255,222,135,.6); }
body.suit-aiming canvas { cursor: crosshair; }

/* Portrait phones and short landscape screens: the same painted slots (three
   moves plus the heal slot: 4 x 48px + 3 gaps = 204px, inside the 243px a
   375px screen leaves), slightly smaller, still honest touch targets. */
@media (max-width: 560px), (max-height: 430px) and (orientation: landscape) {
  #suitdock {
    bottom: calc(7px + env(safe-area-inset-bottom, 0px));
    gap: 4px;
    max-width: calc(100vw - 132px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
  }
  #suitdock .suit-move { width: 48px; height: 48px; }
}

/* Ravel swordsman dock: the Stoneframe dock's silhouette in chalk and copper. */
#sworddock {
  position: fixed;
  left: 50%;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  z-index: 19;
  display: none;
  gap: 6px;
  align-items: stretch;
  max-width: calc(100vw - 148px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
  padding: 6px;
  background: linear-gradient(150deg, rgba(39, 33, 27, .94), rgba(22, 17, 13, .97));
  border: 1px solid rgba(224, 168, 102, .4);
  border-radius: 14px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, .48), inset 0 0 18px rgba(224, 168, 102, .07);
  transform: translateX(-50%);
}
body.swordsman #sworddock { display: flex; }
body.promptopen #sworddock,
body.tutprompt #sworddock,
body.convo #sworddock,
body.selftalk #sworddock,
body.storefront #sworddock,
body.menuopen #sworddock { display: none; }
#sworddock .suit-move {
  position: relative;
  display: flex;
  min-width: 164px;
  min-height: 58px;
  align-items: center;
  gap: 8px;
  overflow: hidden;
  padding: 7px 24px 7px 10px;
  color: #f3ead8;
  border-color: rgba(224, 168, 102, .42);
  background: linear-gradient(180deg, rgba(66, 51, 36, .93), rgba(38, 29, 21, .96));
}
#sworddock .suit-move:hover:not(:disabled) {
  color: #fff3c4;
  border-color: #f0bd62;
  box-shadow: 0 0 16px rgba(240, 189, 98, .22), inset 0 0 13px rgba(240, 189, 98, .12);
}
#sworddock .suit-move:disabled { opacity: .48; filter: grayscale(.4); }
#sworddock .suit-move.ready-ping { animation: suit-ready-ping .7s ease-out; }
#sworddock .suit-glyph {
  display: grid;
  flex: 0 0 42px;
  width: 42px;
  height: 42px;
  place-items: center;
  overflow: hidden;
  border: 1px solid rgba(225, 184, 94, .52);
  border-radius: 7px;
  background: #170f20;
  box-shadow: 0 2px 7px rgba(0, 0, 0, .46), inset 0 0 7px rgba(214, 168, 82, .08);
}
#sworddock .suit-glyph img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  image-rendering: pixelated;
  filter: drop-shadow(0 0 4px rgba(224, 168, 102, .28));
}
#sworddock .suit-copy { display: grid; text-align: left; }
#sworddock b { font: 800 11px/1.1 var(--font-display, var(--font-body)); letter-spacing: .08em; }
#sworddock small { margin-top: 3px; color: var(--ui-muted); font: 600 9px/1 var(--font-body); }
#sworddock .suit-key {
  position: absolute;
  top: 4px;
  right: 5px;
  display: grid;
  place-items: center;
  width: 15px;
  height: 15px;
  color: #dfc19a;
  background: rgba(13, 8, 4, .72);
  border: 1px solid rgba(224, 187, 139, .28);
  border-radius: 4px;
  font: 700 8px/1 ui-monospace, monospace;
  box-shadow: inset 0 -1px 0 rgba(255, 255, 255, .06);
}
#sworddock .suit-cd { position: absolute; right: 0; bottom: 0; left: 0; height: 3px; background: #e0a866; transform-origin: left; }
@media (max-width: 560px), (max-height: 430px) and (orientation: landscape) {
  #sworddock { gap: 4px; padding: 4px; }
  #sworddock .suit-move { min-width: 110px; min-height: 48px; gap: 5px; padding: 4px 18px 4px 5px; }
  #sworddock .suit-glyph { flex-basis: 36px; width: 36px; height: 36px; }
  #sworddock .suit-copy small { display: none; }
}

body.sword-aiming canvas { cursor: crosshair; }

/* A promptless world (Ravel): active play only — the order composer, the
   Write/Speak summons, and the plan surfaces do not exist here. */
body.promptless #keybtn, body.promptless #micbtn, body.promptless #chat,
body.promptless #orders, body.promptless #planstrip { display: none !important; }
/* Clover is promptless but its bunny folk are LLM NPCs: the conversation composer must still open. */
body.promptless.convo #chat { display: flex !important; }
/* Ravel event chrome (Dan, 2026-08-25): the leaderboard is the hub, so the
   quest rail, wardrobe, bag, and emote wheel retire. Chat stays. */
body.event-chrome #questlog, body.event-chrome #gearbtn, body.event-chrome #bagbtn,
body.event-chrome #emotebtn, body.event-chrome #xpwrap, body.event-chrome #glimmerCt { display: none !important; }
/* The emote wheel is a world capability (theme.emoteWheel, Aster only): a world
   without authored emote clips shows no button for it. */
body.no-emotes #emotebtn { display: none !important; }

/* Ravel owns a soot-plum-and-antique-gold interface, not Aster's moss glass.
   Keep this world-scoped: the event's persistent chrome now shares the same
   material language as the gatehouse, banners, ward lines, and swordsman. */
body.event-chrome {
  --ui-ink: #f1e5c8;
  --ui-muted: #b9aabd;
  --ui-dim: #7d7183;
  --ui-well: #120d18;
  --ui-panel: #241a2c;
  --ui-raised: #35263f;
  --ui-hairline: rgba(204, 166, 83, .52);
  --ui-hairline-soft: rgba(204, 166, 83, .17);
  --ui-leaf: #aa8549;
  --ui-leaf-bright: #d6b968;
}

/* Ravel's one real-time opening. The broken orbit echoes the world's refusal
   of Bell's Seal; its gold arc drains against an authority clock, not the
   browser's editable wall time. It anchors the upper-right event stack:
   world clock, streak, leaderboard — directly below the top menu. */
#ravelwindow {
  --ravel-window-progress: 1;
  position: fixed;
  right: calc(12px + env(safe-area-inset-right, 0px));
  top: calc(76px + env(safe-area-inset-top, 0px));
  z-index: 9;
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr);
  align-items: center;
  gap: 9px;
  width: 218px;
  box-sizing: border-box;
  padding: 8px 10px 10px;
  color: #f2e5c8;
  pointer-events: none;
  overflow: hidden;
  background: radial-gradient(circle at 12% 25%, rgba(126, 79, 139, .25), transparent 44%),
    linear-gradient(145deg, rgba(48, 33, 53, .97), rgba(16, 11, 20, .98));
  border: 1px solid rgba(214, 185, 104, .6);
  border-radius: 13px;
  box-shadow: 0 10px 32px rgba(4, 2, 8, .62), inset 0 0 22px rgba(111, 72, 122, .09),
    0 0 20px rgba(165, 119, 62, .12);
}
#ravelwindow[hidden] { display: none; }
body.boot #ravelwindow, body.cine #ravelwindow, body.watch #ravelwindow,
body.world3card #ravelwindow { display: none !important; }
#ravelwindow::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 28%, rgba(255, 232, 174, .06) 48%, transparent 68%);
  translate: -75% 0;
  animation: rw-sheen 9s ease-in-out infinite;
}
.rw-orbit {
  position: relative;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: conic-gradient(from 34deg, #e0bd67 calc(var(--ravel-window-progress) * 330deg),
    rgba(108, 77, 116, .26) 0 330deg, transparent 330deg 360deg);
  filter: drop-shadow(0 0 7px rgba(209, 169, 84, .2));
}
.rw-orbit::after { content: ""; position: absolute; inset: 5px; border-radius: 50%; background: #1b1221; box-shadow: inset 0 0 9px #08040b; }
.rw-orbit i { position: absolute; z-index: 1; inset: 12px; rotate: 45deg; border: 1px solid #c69a53; background: #62456f; box-shadow: 0 0 8px rgba(180, 124, 202,.42); }
.rw-orbit b { position: absolute; z-index: 2; width: 5px; height: 5px; left: 15px; top: -1px; rotate: 45deg; background: #ffe29a; box-shadow: 0 0 7px #efbd55; }
.rw-copy { min-width: 0; }
.rw-kicker { overflow: hidden; color: #d7b864; font: 800 8px/1.1 var(--font-display, var(--font-body)); letter-spacing: .13em; text-overflow: ellipsis; white-space: nowrap; }
.rw-time { display: block; margin-top: 3px; color: #fff0bd; font: 850 19px/.95 ui-monospace, SFMono-Regular, Menlo, monospace; font-variant-numeric: tabular-nums; letter-spacing: .035em; text-shadow: 0 0 13px rgba(224, 185, 91, .18); }
.rw-note { margin-top: 4px; overflow: hidden; color: #8f8296; font: 700 7px/1.2 var(--font-body); letter-spacing: .07em; text-overflow: ellipsis; white-space: nowrap; }
.rw-rail { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: rgba(7, 4, 9, .75); }
.rw-rail i { display: block; width: calc(var(--ravel-window-progress) * 100%); height: 100%; background: linear-gradient(90deg, #765083, #d3aa56, #ffe5a0); box-shadow: 0 0 8px rgba(230, 189, 94, .45); transition: width .3s linear; }
#ravelwindow.urgent { border-color: rgba(242, 154, 88, .8); box-shadow: 0 10px 32px rgba(4, 2, 8, .62), 0 0 22px rgba(213, 99, 77, .22); }
#ravelwindow.urgent .rw-time { color: #ffba7d; animation: rw-urgent 1.2s ease-in-out infinite; }
#ravelwindow.closed { border-color: rgba(136, 106, 145, .45); filter: saturate(.6); }
#ravelwindow.closed .rw-orbit b { display: none; }
#ravelwindow.closed .rw-time { color: #b9aabd; }
#ravelwindow.upcoming .rw-time { color: #d5b8ed; }
@keyframes rw-sheen { 0%,70% { translate: -75% 0; } 90%,100% { translate: 90% 0; } }
@keyframes rw-urgent { 50% { opacity: .68; text-shadow: 0 0 18px rgba(255, 128, 85, .52); } }
@media (max-width: 560px) {
  #ravelwindow { left: calc(8px + env(safe-area-inset-left, 0px)); right:auto; top:calc(124px + env(safe-area-inset-top,0px)); width:calc(100vw - 76px - env(safe-area-inset-left,0px) - env(safe-area-inset-right,0px)); max-width:270px; }
}
@media (prefers-reduced-motion: reduce) {
  #ravelwindow::after, #ravelwindow.urgent .rw-time { animation: none; }
}
body.event-chrome #hud,
body.event-chrome #topbtns {
  background: linear-gradient(150deg, rgba(43, 30, 50, .96), rgba(18, 13, 24, .97));
  border-color: rgba(204, 166, 83, .5);
  box-shadow: 0 10px 32px rgba(4, 2, 8, .55), inset 0 0 20px rgba(111, 72, 122, .07);
}
body.event-chrome #face {
  background: radial-gradient(circle at 50% 28%, #5b4668, #201729 72%);
  border-color: rgba(219, 184, 103, .66);
  box-shadow: inset 0 0 0 2px rgba(8, 4, 12, .62), 0 3px 12px #0009;
}
body.event-chrome #hpwrap { background: #100a16; }
body.event-chrome #hpbar {
  background: linear-gradient(90deg, #60405c, #a96f76, #dfb36b);
  box-shadow: inset 0 1px 0 rgba(255, 242, 198, .22);
}
body.event-chrome #topbtns .btn,
body.event-chrome #chatlogbtn {
  --icon-leaf: #b18d4e;
  color: #f3e5bd;
  background: linear-gradient(155deg, #392a43, #1b1323);
  border-color: rgba(204, 166, 83, .42);
  box-shadow: 0 3px 0 #0c0710;
}
body.event-chrome #toast {
  color: #f1e5c8;
  background: linear-gradient(150deg, rgba(57, 39, 63, .98), rgba(20, 13, 24, .98));
  border-color: rgba(210, 166, 85, .72);
  box-shadow: 0 8px 28px rgba(3, 1, 6, .72), inset 0 0 18px rgba(119, 77, 133, .08);
}
body.event-chrome #topbtns .btn[aria-pressed="true"],
body.event-chrome #topbtns .btn[aria-expanded="true"],
body.event-chrome #topbtns .btn.open {
  --icon-leaf: #d2ae62;
  background: radial-gradient(circle at 50% 42%, rgba(189, 139, 78, .28), transparent 58%),
    linear-gradient(155deg, #5a3a59, #27192f 62%, #17101d);
  box-shadow: inset 0 0 12px rgba(224, 174, 93, .13), 0 0 18px rgba(125, 79, 139, .24);
}
body.event-chrome #sworddock {
  background: linear-gradient(150deg, rgba(43, 30, 46, .95), rgba(19, 13, 21, .98));
  border-color: rgba(210, 166, 85, .46);
  box-shadow: 0 8px 30px rgba(0, 0, 0, .52), inset 0 0 18px rgba(137, 84, 142, .08);
}
body.event-chrome #sworddock .suit-move {
  background: linear-gradient(180deg, rgba(69, 47, 65, .94), rgba(36, 24, 38, .97));
  border-color: rgba(210, 166, 85, .45);
}
body.event-chrome #streakmeter,
body.event-chrome #liveboard {
  background: linear-gradient(160deg, rgba(43, 30, 47, .94), rgba(18, 12, 21, .97));
  border-color: rgba(210, 166, 85, .43);
}
body.event-chrome #liveboard .lb-row { background: rgba(75, 51, 72, .54); }
body.event-chrome #liveboard .lb-row.self { background: rgba(165, 115, 65, .3); }
body.event-chrome #liveboard .lb-reward { background: rgba(20, 13, 23, .58); }

/* The streak meter: sits just above the leaderboard; heats up gold -> amber
   -> violet as the multiplier climbs, and its decay bar drains in real time. */
#streakmeter {
  position: fixed;
  top: calc(148px + env(safe-area-inset-top, 0px));
  right: calc(12px + env(safe-area-inset-right, 0px));
  z-index: 8;
  display: none;
  width: 218px;
  padding: 7px 9px 6px;
  background: linear-gradient(160deg, rgba(31, 26, 20, .92), rgba(18, 14, 11, .95));
  border: 1px solid rgba(224, 168, 102, .38);
  border-radius: 12px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .4);
  pointer-events: none;
  transition: border-color .3s, box-shadow .3s;
}
body.streakmeter #streakmeter { display: block; }
body.cine #streakmeter, body.watch #streakmeter, body.world3card #streakmeter,
body.boot #streakmeter, body.convo #streakmeter { display: none !important; }
#streakmeter .sm-row { display: flex; align-items: baseline; gap: 7px; }
#streakmeter .sm-mult { color: #ffd66b; font: 800 17px/1 ui-monospace, monospace; }
#streakmeter .sm-info { flex: 1; color: #cfc4ae; font: 600 10px/1.2 var(--font-body); }
#streakmeter .sm-seeds { color: #d2a8ff; font: 700 11px/1 ui-monospace, monospace; letter-spacing: .12em; }
#streakmeter .sm-decaywrap { height: 4px; margin-top: 5px; border-radius: 2px;
  background: rgba(15, 24, 19, .8); overflow: hidden; }
#streakmeter .sm-decay { height: 100%; width: 100%; border-radius: 2px;
  background: linear-gradient(90deg, #9a7436, #f0c76d);
  transition: width .62s linear, background .3s; }
#streakmeter.t2 { border-color: rgba(255, 179, 71, .6); }
#streakmeter.t2 .sm-mult { color: #ffb347; }
#streakmeter.t2 .sm-decay { background: linear-gradient(90deg, #b3691f, #ffb347); }
#streakmeter.t3 { border-color: rgba(210, 168, 255, .68); box-shadow: 0 0 18px rgba(160, 110, 255, .28); }
#streakmeter.t3 .sm-mult { color: #d2a8ff; }
#streakmeter.t3 .sm-decay { background: linear-gradient(90deg, #6b46b0, #d2a8ff); }
#streakmeter.pulse { animation: sm-pulse .55s ease-out; }
@keyframes sm-pulse {
  0% { transform: scale(1.06); box-shadow: 0 0 26px rgba(240, 199, 109, .55); }
  100% { transform: scale(1); }
}
@media (max-width: 900px) { #streakmeter { display: none !important; } }

/* The Watch board: the continuous event's live arcade leaderboard. */
#liveboard {
  position: fixed;
  top: calc(196px + env(safe-area-inset-top, 0px));
  right: calc(12px + env(safe-area-inset-right, 0px));
  z-index: 8;
  display: none;
  width: 218px;
  padding: 8px 8px 6px;
  background: linear-gradient(160deg, rgba(31, 26, 20, .92), rgba(18, 14, 11, .95));
  border: 1px solid rgba(224, 168, 102, .38);
  border-radius: 12px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .4);
  /* The whole board is one tap target: it opens the full public record. */
  pointer-events: auto;
  cursor: pointer;
}
#liveboard:hover { border-color: rgba(255, 214, 131, .7); }
body.liveboard #liveboard { display: block; }
body.cine #liveboard, body.watch #liveboard, body.world3card #liveboard, body.boot #liveboard,
body.convo #liveboard, body.promptopen #liveboard, body.menuopen #liveboard { display: none !important; }
/* The opening muster's leaderboard beats lift the letterbox veil so Sable can
   point at the real board, and pulse whichever part the line is about. */
body.cine.ravel-muster-board.liveboard #liveboard { display: block !important; }
#liveboard.lb-callout, #liveboard .lb-reward.lb-callout { animation: lbCallout .9s ease 4; }
@keyframes lbCallout {
  50% { border-color: #ffd683; box-shadow: 0 0 22px rgba(255, 214, 131, .8), 0 6px 24px rgba(0, 0, 0, .4); }
}
#liveboard .lb-title { display: flex; justify-content: space-between; align-items: baseline;
  margin: 0 2px 6px; color: #e0a866; font: 800 10px/1 var(--font-display, var(--font-body)); letter-spacing: .14em; }
#liveboard .lb-ward { color: #b9a68b; font: 700 9px/1 ui-monospace, monospace; letter-spacing: .04em; }
#liveboard .lb-rows { display: flex; flex-direction: column; gap: 3px; }
#liveboard .lb-row {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 6px;
  padding: 4px 7px;
  background: rgba(56, 44, 32, .55);
  border-radius: 7px;
  color: #e9e2d4;
  font: 600 11px/1.25 var(--font-body);
  transition: transform .45s cubic-bezier(.22, 1.2, .36, 1), background .3s;
  will-change: transform;
}
#liveboard .lb-row.self { background: rgba(201, 138, 75, .3); box-shadow: inset 0 0 0 1px rgba(240, 189, 98, .55); }
#liveboard .lb-row.p1 .lb-rank { color: #ffd66b; }
#liveboard .lb-row.p2 .lb-rank { color: #d8d8e2; }
#liveboard .lb-row.p3 .lb-rank { color: #d99e6a; }
#liveboard .lb-row.bump { animation: lb-bump .5s ease-out; }
@keyframes lb-bump {
  0% { background: rgba(240, 189, 98, .5); }
  100% { background: rgba(56, 44, 32, .55); }
}
#liveboard .lb-rank { width: 17px; color: #a99a86; font: 800 11px/1 ui-monospace, monospace; }
#liveboard .lb-name { flex: 1; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
#liveboard .lb-score { color: #ffe9c4; font: 700 12px/1 ui-monospace, monospace; font-variant-numeric: tabular-nums; }
#liveboard .lb-move { width: 10px; font: 800 9px/1 ui-monospace, monospace; }
#liveboard .lb-move.up { color: #8fdc7a; }
#liveboard .lb-move.down { color: #e08a7a; }
/* Ravel stealth states on the sword dock: while the ambush window is live the
   striking arts glow gold; while veiled the stealth key reads as spent. */
#sworddock.ambush #dashbtn:not(:disabled), #sworddock.ambush #spinbtn:not(:disabled) {
  border-color: #ffd66b; box-shadow: 0 0 12px rgba(255, 214, 107, .45); }
#sworddock.ambush #dashbtn:not(:disabled) small, #sworddock.ambush #spinbtn:not(:disabled) small,
#sworddock.veiled #dashbtn:not(:disabled) small, #sworddock.veiled #spinbtn:not(:disabled) small { color: #ffd66b; }
#sworddock.veiled #stealthbtn { opacity: .55; }
#liveboard .lb-gap { padding: 0 2px; color: #8a7a63; text-align: center;
  font: 700 9px/1.4 ui-monospace, monospace; letter-spacing: .18em; }
#liveboard .lb-more { margin-top: 2px; color: #c9a86a; text-align: center;
  font: 700 9px/1.6 var(--font-body); letter-spacing: .06em; }
#liveboard:hover .lb-more { color: #ffe09a; }
#liveboard .lb-delta {
  position: absolute;
  right: 6px;
  top: -7px;
  color: #ffe08a;
  font: 800 10px/1 ui-monospace, monospace;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .7);
  animation: lb-delta .9s ease-out forwards;
  pointer-events: none;
}
@keyframes lb-delta {
  0% { opacity: 0; transform: translateY(4px); }
  25% { opacity: 1; }
  100% { opacity: 0; transform: translateY(-10px); }
}
#liveboard .lb-reward { margin-top: 6px; padding: 6px 7px 5px; border-radius: 8px;
  background: rgba(15, 24, 19, .5); }
#liveboard .lb-reward.earned { background: rgba(201, 148, 67, .22);
  box-shadow: inset 0 0 0 1px rgba(240, 199, 109, .5); }
#liveboard .lb-reward-line { display: flex; justify-content: space-between; align-items: baseline; }
#liveboard .lb-reward-label { color: #cfc4ae; font: 700 9px/1 var(--font-display, var(--font-body));
  letter-spacing: .1em; }
#liveboard .lb-reward.earned .lb-reward-label { color: #ffe8a6; }
#liveboard .lb-reward-count { color: #e9e2d4; font: 700 10px/1 ui-monospace, monospace;
  font-variant-numeric: tabular-nums; }
#liveboard .lb-reward-barwrap { height: 4px; margin-top: 4px; border-radius: 2px;
  background: rgba(6, 10, 8, .7); overflow: hidden; }
#liveboard .lb-reward-bar { height: 100%; width: 0%; border-radius: 2px;
  background: linear-gradient(90deg, #6b46b0, #d2a8ff);
  transition: width .6s ease-out; }
#liveboard .lb-reward.earned .lb-reward-bar { background: linear-gradient(90deg, #9a7436, #f0c76d); }
#liveboard .lb-reward.pulse { animation: lb-reward-pulse .7s ease-out; }
@keyframes lb-reward-pulse {
  0% { box-shadow: inset 0 0 0 1px rgba(240, 199, 109, .9), 0 0 22px rgba(240, 199, 109, .5); }
  100% { box-shadow: inset 0 0 0 1px rgba(240, 199, 109, .5); }
}
@media (max-width: 900px) { #liveboard { display: none !important; } }

/* ---- Conversation header: action slot + icon-only audience toggle (Clover town pass, 2026-09-15) ---- */
/* The header wraps so #convoactions can take a full row under the names. */
#chathdr { flex-wrap: wrap; }
#convoactions { flex: 1 0 100%; display: none; flex-wrap: wrap; gap: 6px; align-items: center; min-width: 0; }
#convoactions:not(:empty) { display: flex; }
#convoactions .btn { flex: 0 1 auto; min-width: 0; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 12.5px; padding: 6px 11px; }
#convoactions .btn.primary { color: #1c1a0f; background: linear-gradient(180deg, #f0c76d, #c9a24a); border-color: #f5dd8e; font-weight: 700; }
/* the smith's next tunes as painted cards in the conversation (r5 Cairn) */
#convoactions .forge-strip { display: flex; gap: 8px; width: 100%; }
#convoactions .forge-strip-card { position: relative; flex: 0 0 auto; width: 76px; height: 76px; padding: 0; border-radius: 10px; cursor: pointer;
  border: 1px solid rgba(240, 189, 98, .55); background: radial-gradient(circle at 50% 40%, rgba(240, 189, 98, .18), rgba(10, 14, 10, .8) 70%); }
#convoactions .forge-strip-card:hover, #convoactions .forge-strip-card:focus-visible { border-color: #f5dd8e; box-shadow: 0 0 12px rgba(240, 189, 98, .45); }
#convoactions .forge-strip-card img { position: absolute; inset: 6px 6px 16px; width: calc(100% - 12px); height: calc(100% - 22px); object-fit: contain; image-rendering: pixelated; }
#convoactions .forge-strip-card .fsc-price { position: absolute; left: 0; right: 0; bottom: 3px; display: flex; align-items: center; justify-content: center; gap: 3px;
  color: #f5dd8e; font: 800 11px/1 ui-rounded, system-ui, sans-serif; }
#convoactions .forge-strip-card .fsc-price .ui-icon { width: 11px; height: 11px; }
/* The audience toggle is a lock glyph with a tooltip; the word "Private" is gone. */
#chathdr .npc-audience { min-width: 34px; width: 34px; height: 34px; padding: 0; justify-content: center; gap: 0; }
#chathdr .npc-audience .ui-icon { width: 16px; height: 16px; }
@media (max-width: 560px) {
  #chathdr .npc-audience { min-width: 44px; width: 44px; height: 44px; min-height: 44px; padding: 0; }
}
/* Sign text and other short reads: a larger toast that holds ~4 s. */
#toast.big { font-size: 17px; line-height: 1.4; padding: 12px 22px; max-width: min(72vw, 560px); text-align: center; }

/* ---- Clover HUD: the bunny's HP/XP panel and wardrobe/bag are bunny-only;
   Clover's pet mini-panel (#clover-party, viewer/clover.css) replaces them. ---- */
body.clover-world #hud, body.clover-world #gearbtn, body.clover-world #bagbtn, body.clover-world #wardrobe, body.clover-world #bag { display: none !important; }

/* ---- operator instant travel (2026-09-18) ----
   The map's tap-to-walk becomes tap-to-arrive while this is lit. It only ever
   exists for an allowlisted operator account (mmo.js reveals it on the /dev
   grant), so it is sized to sit quietly beside the panel's own buttons. */
.mapwarp {
  min-height: 26px;
  align-self: center;
  margin-right: 6px;
  padding: 0 10px;
  color: #0e1a12;
  background: linear-gradient(160deg, var(--ui-gold, #f2c94c), #c79a22);
  border: 1px solid var(--ui-brass-hi);
  border-radius: 999px;
  font: inherit;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .04em;
  cursor: pointer;
}
.mapwarp[aria-pressed="false"] {
  color: var(--ui-ink);
  background: linear-gradient(160deg, #2d533d, #162a20);
  border-color: var(--ui-hairline);
}

/* Stat chips are pictures (2026-09-22): heart = HP, claw = HIT, shield = DEF. */
.stat { display: inline-flex; align-items: center; gap: 3px; font-variant-numeric: tabular-nums; font-weight: 700; }
.stat .ui-icon { width: 12px; height: 12px; flex: none; }
.stat-max { margin-left: 3px; color: var(--ui-muted); font-size: 11px; text-transform: uppercase; letter-spacing: .06em; }
#bagdetail .dv-chips { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
#bagdetail .dv-chips .stat { padding: 1px 6px; border-radius: 6px; font-size: 12px; }
#bagdetail .worth { display: inline-flex; align-items: center; gap: 4px; padding: 1px 7px; border-radius: 6px; background: rgba(63, 185, 80, .12); color: var(--ui-leaf-bright); font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; }
#bagdetail .worth .ui-icon { width: 12px; height: 12px; }

/* The wardrobe doll is the real bunny in its real gear; the face is only the
   fallback while sprites load or while another form is worn. */
#dollwrap canvas.dollsprite { display: none; width: 108px; height: 108px; image-rendering: pixelated;
  border-radius: 18px; background: radial-gradient(circle at 50% 42%, #436847, #15241b 72%);
  box-shadow: inset 0 0 0 2px rgba(229, 204, 142, .55), 0 6px 18px #0008; }
#dollwrap.painted canvas.dollsprite { display: block; }
#dollwrap.painted img.doll { display: none; }
#dollstats:empty { min-height: 0; margin: 0 0 6px; }
#dollstats .stat { padding: 2px 7px; border-radius: 7px; font-size: 13px; }
#dollstats .stat .ui-icon { width: 14px; height: 14px; }

/* Stowed gear: a shelf of picture tiles, tap to wear */
#wbaglist { display: grid; grid-template-columns: repeat(auto-fill, minmax(68px, 1fr)); gap: 7px; }
#wbaglist:empty { display: none; }
#wbaglist .wtile {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 4px;
  min-height: 0; padding: 7px 3px 6px; border: 0; border-radius: 10px; background: var(--ui-raised);
  color: inherit; cursor: pointer; transition: transform .12s ease, background .12s ease;
}
#wbaglist .wtile:hover { background: #33473a; transform: translateY(-2px); }
#wbaglist .wtile-art { position: relative; display: grid; place-items: center; width: 44px; height: 44px; }
#wbaglist .wtile-art img, #wbaglist .wtile-art .ph { width: 40px; height: 40px; image-rendering: pixelated; object-fit: contain; filter: drop-shadow(0 3px 4px #0008); }
#wbaglist .wtile-slot { position: absolute; left: -6px; top: -4px; display: grid; place-items: center; width: 18px; height: 18px; border-radius: 50%; background: #15241b; color: #9fbf9a; }
#wbaglist .wtile-slot .ui-icon { width: 11px; height: 11px; }
#wbaglist .wtile-n { position: absolute; right: -6px; bottom: -4px; padding: 0 4px; border-radius: 7px; background: #15241b; color: #f2e6bd; font-size: 11px; font-weight: 700; }
#wbaglist .wtile-stats { display: flex; flex-wrap: wrap; justify-content: center; gap: 3px; }
#wbaglist .wtile-stats .stat { padding: 0 4px; border-radius: 5px; font-size: 11px; }
#bagdetail .stat { padding: 1px 6px; margin-right: 4px; border-radius: 6px; font-size: 12px; }

/* ============================================================ level-up stamp
   The celebration beat's headline (r2 polish): a big centred LEVEL N that
   slams in over the confetti and gold wash, then lifts away. Pointer-free. */
#lvstamp {
  position: fixed; left: 50%; top: 27%; z-index: 27; pointer-events: none;
  display: none; flex-direction: column; align-items: center; gap: 2px;
  padding: 14px 34px 18px; border-radius: 22px;
  background: radial-gradient(ellipse at center, rgba(40, 24, 6, .82) 0%, rgba(40, 24, 6, .55) 55%, rgba(40, 24, 6, 0) 75%);
  transform: translate(-50%, -50%);
  color: #fff3c4; text-shadow: 0 4px 0 #7a4a12, 0 0 26px rgba(255, 214, 107, .9), 0 8px 18px rgba(0, 0, 0, .6);
}
#lvstamp small { font: 800 clamp(16px, 4vw, 26px)/1 var(--font-display); letter-spacing: .32em; color: #ffd66b; }
#lvstamp b { font: 900 clamp(96px, 26vw, 160px)/.95 ui-rounded, "Avenir Next", "Trebuchet MS", system-ui, sans-serif; color: #ffe08a; -webkit-text-stroke: 3px #7a4a12; }
#lvstamp.show { display: flex; animation: lvstamp 2.2s cubic-bezier(.2, .9, .3, 1.2) both; }
@keyframes lvstamp {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(2.6) rotate(-8deg); }
  14% { opacity: 1; transform: translate(-50%, -50%) scale(.92) rotate(2deg); }
  22% { transform: translate(-50%, -50%) scale(1.06) rotate(-1deg); }
  30%, 78% { opacity: 1; transform: translate(-50%, -50%) scale(1) rotate(0); }
  100% { opacity: 0; transform: translate(-50%, -64%) scale(.94); }
}
@media (prefers-reduced-motion: reduce) { #lvstamp.show { animation: lvstamp-calm 2.2s ease both; } }
@keyframes lvstamp-calm { 0%, 100% { opacity: 0; } 15%, 80% { opacity: 1; } }
body.cine #lvstamp { display: none !important; }
/* Morel's and Basalt's moving prices (r2): the plain price struck through, and an arrow. */
.merchant-surge { display: block; margin-bottom: 4px; text-align: center; font: 800 14px/1 ui-rounded, "Avenir Next", system-ui, sans-serif; }
.merchant-surge s { color: var(--ui-muted); margin-right: 4px; }
.merchant-surge.down { color: #7ee787; }
.merchant-surge.up { color: #ff9b7a; }

/* r4: a counted plan hunt draws the favor tracker's pips under its title */
#orders .planpips { display: flex; flex-wrap: wrap; gap: 3px; margin: 3px 0 2px; }
#orders .planpips i { width: 9px; height: 9px; border-radius: 50%; background: #101a13; border: 1px solid #56705a; }
#orders .planpips i.on { background: #e4ce7f; border-color: #fff3c4; }
#orders.idle #planpips { display: none; }
/* the counted hunt's finish: pips pop into confetti (celebrateCountedHunt, r5) */
.pipconfetti { position: fixed; width: 6px; height: 4px; border-radius: 1px; pointer-events: none; z-index: 60; }

/* r4: the Lv badge pops as a new level lands in it */
#lvbadge.pop { animation: lvbadgepop .9s cubic-bezier(.2, .9, .3, 1.4) both; }
@keyframes lvbadgepop {
  0% { transform: scale(1); box-shadow: 0 2px 4px #0009; }
  30% { transform: scale(1.9); box-shadow: 0 0 18px #ffd66b, 0 2px 4px #0009; }
  100% { transform: scale(1); box-shadow: 0 2px 4px #0009; }
}
@media (prefers-reduced-motion: reduce) { #lvbadge.pop { animation: none; } }

/* r4: the hawk's tappable "Hide?" bubble, pinned over the bunny's head */
#hawkask { position: fixed; z-index: 44; display: none; transform: translate(-50%, -100%); align-items: center; gap: 6px;
  min-height: 44px; padding: 6px 12px 6px 6px; border: 2px solid #ffd66b; border-radius: 22px; background: #1d140be8;
  color: #fff3c4; font: 800 15px/1 var(--font-display, ui-rounded, system-ui, sans-serif); letter-spacing: .04em;
  box-shadow: 0 0 0 0 #ffd66b88, 0 4px 12px #000a; cursor: pointer; touch-action: manipulation; }
#hawkask.show { display: inline-flex; animation: hawkaskpulse .8s ease-in-out infinite; }
#hawkask img { width: 32px; height: 32px; border-radius: 50%; background: radial-gradient(circle, #9ccc63 0%, #6f9d3f 100%); box-shadow: inset 0 0 0 2px #3c5a22; }
#hawkask::after { content: ""; position: absolute; left: 50%; bottom: -8px; margin-left: -7px; border: 7px solid transparent; border-bottom: 0; border-top-color: #ffd66b; }
@keyframes hawkaskpulse { 0%, 100% { box-shadow: 0 0 0 0 #ffd66b88, 0 4px 12px #000a; } 50% { box-shadow: 0 0 0 9px #ffd66b00, 0 4px 12px #000a; } }
@media (prefers-reduced-motion: reduce) { #hawkask.show { animation: none; } }

/* r5: a snack reflex's save, said out loud: "⚡🥕 SAVED!" rising off the chip that fired */
.reflexsaved { position: fixed; z-index: 46; pointer-events: none; transform: translate(-50%, -100%); white-space: nowrap;
  color: #ffd66b; font: 800 20px/1 var(--font-display, ui-rounded, system-ui, sans-serif); letter-spacing: .04em;
  text-shadow: 0 2px 0 #3a2410, 0 0 12px #ffd66baa; animation: reflexsaved 1.3s cubic-bezier(.2, .9, .3, 1) forwards; }
@keyframes reflexsaved {
  0% { opacity: 0; transform: translate(-50%, -60%) scale(.6); }
  18% { opacity: 1; transform: translate(-50%, -110%) scale(1.25); }
  70% { opacity: 1; transform: translate(-50%, -170%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -210%) scale(1); }
}
/* the Descent's Foresight flare: the word the Keeper just named, in gold, while time slows */
.foresightflare { position: fixed; z-index: 46; left: 50%; top: 38%; pointer-events: none; transform: translate(-50%, -50%);
  color: #fff3c4; font: 800 38px/1 var(--font-display, ui-rounded, system-ui, sans-serif); letter-spacing: .18em;
  text-shadow: 0 0 18px #ffd66b, 0 0 42px #ffb347, 0 3px 0 #5a3a10; animation: foresightflare 1.6s ease-out forwards; }
@keyframes foresightflare {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(.7); letter-spacing: .02em; }
  20% { opacity: 1; transform: translate(-50%, -50%) scale(1.08); }
  75% { opacity: 1; transform: translate(-50%, -50%) scale(1); letter-spacing: .24em; }
  100% { opacity: 0; transform: translate(-50%, -54%) scale(1); letter-spacing: .28em; }
}
@media (max-width: 560px) { .foresightflare { font-size: 28px; } .reflexsaved { font-size: 17px; } }
@media (prefers-reduced-motion: reduce) { .reflexsaved, .foresightflare { animation: none; } }
/* THE STRIKE (r5 Cairn): the Tuning Fork is held, never tapped past. A big
   fork over the court, a ring that fills while it is held, then the note. */
#forkstrike { position: fixed; inset: 0; z-index: 36; display: grid; place-items: center; pointer-events: none; opacity: 0; transition: opacity .35s ease-out; }
#forkstrike.show { opacity: 1; }
#forkstrike.gone { opacity: 0; }
#forkstrike .fs-btn { pointer-events: auto; position: relative; width: 168px; height: 168px; border-radius: 50%; border: 0; padding: 0; cursor: pointer; touch-action: none;
  background: radial-gradient(circle, rgba(207, 232, 255, .22), rgba(12, 16, 28, .82) 68%); box-shadow: 0 0 36px rgba(160, 205, 255, .35);
  animation: fs-breathe 1.8s ease-in-out infinite; -webkit-user-select: none; user-select: none; }
#forkstrike .fs-btn:focus-visible { outline: 3px solid #fff3c4; outline-offset: 4px; }
#forkstrike .fs-btn img { position: absolute; left: 50%; top: 50%; width: 104px; height: 104px; transform: translate(-50%, -50%); image-rendering: pixelated; filter: drop-shadow(0 0 10px rgba(190, 228, 255, .8)); }
#forkstrike .fs-ring { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); }
#forkstrike .fs-track { fill: none; stroke: rgba(207, 232, 255, .22); stroke-width: 5; }
#forkstrike .fs-fill { fill: none; stroke: #eaf6ff; stroke-width: 6; stroke-linecap: round; stroke-dasharray: 100; stroke-dashoffset: 100; transition: stroke-dashoffset .18s ease-out; filter: drop-shadow(0 0 6px #9fd8ff); }
#forkstrike .fs-btn.holding { animation: fs-tremble .08s linear infinite; }
#forkstrike .fs-btn.holding .fs-fill { stroke-dashoffset: 0; transition: stroke-dashoffset var(--hold-ms, 1100ms) linear; }
#forkstrike.struck .fs-btn { animation: fs-struck .6s ease-out forwards; }
@keyframes fs-breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } }
@keyframes fs-tremble { 0% { transform: translate(0, 0); } 25% { transform: translate(1px, -1px); } 50% { transform: translate(-1px, 1px); } 75% { transform: translate(1px, 1px); } }
@keyframes fs-struck { 0% { transform: scale(1); filter: brightness(1); } 30% { transform: scale(1.18); filter: brightness(2.2); } 100% { transform: scale(1.35); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { #forkstrike .fs-btn, #forkstrike .fs-btn.holding { animation: none; } }
/* the note crossing the screen: one soft ring from the middle out */
.fork-ripple { position: fixed; left: 50%; top: 50%; width: 40px; height: 40px; margin: -20px 0 0 -20px; border-radius: 50%; z-index: 6; pointer-events: none;
  border: 3px solid rgba(220, 240, 255, .85); box-shadow: 0 0 30px rgba(160, 210, 255, .6), inset 0 0 24px rgba(160, 210, 255, .4); animation: fork-ripple 1.8s cubic-bezier(.2, .7, .3, 1) forwards; }
@keyframes fork-ripple { 0% { transform: scale(.4); opacity: .95; } 100% { transform: scale(48); opacity: 0; border-width: 1px; } }
@media (prefers-reduced-motion: reduce) { .fork-ripple { animation-duration: .6s; } }

/* ---- phone HUD (2026-09-26, lane phone-hud) ---------------------------------
   Dan: "the screen is too busy for mobile players". The Roblox / OSRS-mobile
   shape, collapsed by default. At rest a phone shows only: a small vitals pill
   (top left), ONE menu button (#guidebtn, top right) and, when a fight or a
   world needs it, ONE action cluster in the bottom-right thumb zone (Aster's
   moves, Cairn's suit dock, Clover's compass + menu). The plan dock, emotes and
   chat fold behind the menu and come back on their own when relevant (a live
   plan, an unread message). Objectives are a one-line chip that tucks to its
   icon (viewer/phone-hud.js); transients use one lane under the chip. Target:
   <= 8% of the screen covered at rest (research/phone-hud-2026-09-26/). The
   Descent and the Between (body.tut) keep their own guided layout. Desktop is
   untouched: everything here is inside max-width 560px. */
@media (max-width: 560px) {
  /* the vitals pill: face + level coin, health, a thin experience line */
  body:not(.tut) #hud {
    width: auto;
    max-width: calc(100vw - 88px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
    padding: 4px 12px 4px 4px;
    border-radius: 24px;
  }
  body:not(.tut) #hud .hudrow { gap: 10px; }
  body:not(.tut) #hud #face { width: 32px; height: 32px; border-radius: 50%; }
  body:not(.tut) #hud :is(#bunnyname, #glimmerCt, #xpline, #conn) { display: none; }
  body:not(.tut) #hud #hpwrap { width: 84px; height: 8px; margin-top: 0; }
  body:not(.tut) #hud #xpwrap { width: 84px; height: 4px; margin-top: 3px; }

  /* ONE menu button. The rail behind it is the existing field-guide disclosure. */
  body:not(.tut) #topbtns:not(.guide-open) { padding: 0; gap: 0; background: none; border-color: transparent; box-shadow: none; }
  body:not(.tut) #topbtns #guidebtn { display: inline-flex !important; }
  body:not(.tut) #topbtns:not(.guide-open) :is(#petbtn, #bugbtn, #mapbtn, #bagbtn, #gearbtn, #setbtn) { display: none !important; }

  /* The plan dock and the social dock live behind the menu. A live plan keeps
     its bar (body.planlive, above) and an unread message brings chat back. */
  body:not(.tut) #topbtns:not(.guide-open) ~ #orders.idle { display: none !important; }
  body:not(.tut) #topbtns.guide-open ~ #orders.idle {
    left: calc(66px + env(safe-area-inset-left, 0px));
    right: auto;
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
  }
  /* ...and above the action cluster whenever one is up, never on it */
  body:not(.tut):is(.stoneframe, .phone-fight) #topbtns.guide-open ~ #orders.idle { bottom: calc(68px + env(safe-area-inset-bottom, 0px)); }
  body:not(.tut):not(.clover-world) #topbtns:not(.guide-open) ~ #socialdock:not(:has(#chatlogbtn .ct:not([hidden]))) { display: none; }
  body:not(.tut):not(.clover-world) #topbtns:not(.guide-open) ~ #socialdock #emotebtn { display: none; }

  /* The objective chip: under the pill, never over it. One line; the hint
     only when the player opens it; after a few seconds, just the icon. */
  body:not(.tut) #objective {
    top: calc(64px + env(safe-area-inset-top, 0px));
    left: calc(14px + env(safe-area-inset-left, 0px));
    transform: none;
    width: auto;
    max-width: calc(100vw - 88px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
    padding: 4px 12px 4px 4px;
    gap: 8px;
    border-radius: 23px;
    pointer-events: auto;
    cursor: pointer;
  }
  body:not(.tut) #objective.cue { animation: phoneobjcue .38s cubic-bezier(.2, .9, .3, 1.15); }
  body:not(.tut) #objective .objvisual { width: 36px; height: 36px; flex-basis: 36px; border-radius: 50%; }
  body:not(.tut) #objective .objsprite { width: 30px; height: 30px; }
  body:not(.tut) #objective .objicon.solo { width: 28px; height: 28px; }
  body:not(.tut) #objective .objcopy { min-width: 0; overflow: hidden; }
  body:not(.tut) #objective .obj { font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  body:not(.tut) #objective:not(.obj-open) .objhint { display: none; }
  body:not(.tut) #objective.obj-open { border-radius: 16px; }
  body:not(.tut) #objective.obj-open .obj { white-space: normal; }
  body:not(.tut) #objective.obj-tucked { padding: 4px; gap: 0; }
  body:not(.tut) #objective.obj-tucked .objcopy { display: none; }

  /* One transient lane: under the chip, above the bunny, off the thumb zone. */
  body:not(.tut):not(.clover-world) #toast {
    top: calc(160px + env(safe-area-inset-top, 0px));
    bottom: auto;
    max-width: calc(100vw - 32px);
    z-index: 23;
  }
  body.boss:not(.tut):not(.clover-world) #toast { top: calc(226px + env(safe-area-inset-top, 0px)); }
  body:not(.tut) #lootchip { top: calc(112px + env(safe-area-inset-top, 0px)); }
  body:not(.tut) #stormchip { top: calc(66px + env(safe-area-inset-top, 0px)); right: calc(8px + env(safe-area-inset-right, 0px)); }
  body:not(.tut) :is(#megahud, #overhud) { top: calc(112px + env(safe-area-inset-top, 0px)); }

  /* Cairn's suit dock: the thumb zone, bottom right. Four slots (three moves
     and the heal slot) are 4 x 48px + 3 x 6px = 210px: from the right edge of
     a 375px screen that ends at x=155, clear of the social dock's one 45px
     chat clasp at the left (it ends at x=59) and of the plan chip, which a
     stoneframe body lifts to 68px above the bottom. */
  #suitdock {
    left: auto;
    right: calc(10px + env(safe-area-inset-right, 0px));
    bottom: calc(10px + env(safe-area-inset-bottom, 0px));
    transform: none;
    gap: 6px;
    max-width: none;
  }
  #suitdock .suit-move { width: 48px; height: 48px; }
  #suitdock .suit-tip { left: auto; right: 0; transform: none; }

  /* Cutscenes: a thin letterbox. The film is the world, not the bars. */
  body.cine #cinebars .bar, body.drama #cinebars .bar { height: 4.5vh; }
  body.watch #cinebars .bar { height: 4vh; }
  #cine { bottom: calc(4.5vh + 10px + env(safe-area-inset-bottom, 0px)); padding: 10px 12px; }
  #cine .crow { gap: 10px; }
  #cineface { width: 46px; height: 46px; }
  #cinetext { font-size: 14px; line-height: 1.5; min-height: 0; }
}
@keyframes phoneobjcue { from { transform: translateY(-8px) scale(.94); } to { transform: none; } }
/* Key badges are keyboard copy: a touch screen never shows them. */
@media (hover: none) and (pointer: coarse) {
  #suitdock .suit-key, .suit-tip kbd { display: none; }
}

/* ---- the Standings chip (2026-09-27, lane triage-leaderboard) ----------------
   viewer/standings-chip.js. A trophy to The Standings and, while it can still be
   earned, the Chalkhorn in a gold progress ring. It rides #hud, so every state
   that hides the HUD (menus, conversations, cutscenes, Clover) hides it too. */
#hud > #standchip {
  position: absolute; left: calc(100% + 8px); top: 0; z-index: 2;
  display: flex; align-items: center; gap: 4px; padding: 4px;
  border: 1px solid var(--ui-hairline); border-radius: 24px;
  background: linear-gradient(150deg, rgba(30, 48, 37, .95), rgba(16, 27, 20, .96));
  box-shadow: 0 8px 24px rgba(0, 0, 0, .4);
}
#hud > #standchip[hidden], body.tut #hud > #standchip { display: none; }
#standchip .sc-board {
  width: 36px; height: 36px; display: grid; place-items: center; border-radius: 50%;
  color: #f1d27d; background: var(--ui-raised); text-decoration: none;
}
#standchip .sc-board .ui-icon { width: 22px; height: 22px; --icon-leaf: #c99443; }
#standchip .sc-board:hover { background: #34493a; }
#standchip .sc-chalk {
  display: flex; align-items: center; gap: 0; min-height: 36px; padding: 0;
  border: 0; background: none; color: var(--ui-ink); cursor: pointer; font: inherit;
}
#standchip .sc-chalk[hidden] { display: none; }
#standchip .sc-ring {
  width: 36px; height: 36px; flex: 0 0 36px; display: grid; place-items: center; border-radius: 50%;
  background: conic-gradient(#f1d27d calc(var(--p, 0) * 1%), rgba(242, 230, 189, .16) 0);
}
#standchip .sc-ring img {
  width: 30px; height: 30px; border-radius: 50%; object-fit: cover; object-position: 50% 40%;
  background: radial-gradient(circle at 50% 35%, #3b5a40, #132019 72%); image-rendering: pixelated;
}
/* First sight, and the one earned moment: a word slides out, then tucks away. */
#standchip .sc-peek {
  max-width: 0; overflow: hidden; white-space: nowrap; opacity: 0;
  font: 700 12px/1 var(--font-body); letter-spacing: .02em; color: var(--ui-ink);
  transition: max-width .35s ease, opacity .25s ease, padding .35s ease;
}
#standchip.peeking .sc-peek { max-width: 160px; opacity: 1; padding: 0 8px 0 6px; }
#standchip[data-face="celebrate"] { border-color: #f1d27d; box-shadow: 0 0 0 1px rgba(241, 210, 125, .5), 0 0 22px rgba(241, 210, 125, .45); }
#standchip[data-face="celebrate"] .sc-ring { background: linear-gradient(#f1d27d, #c99443); animation: scearned 1.1s ease-in-out 3; }
#standchip[data-face="celebrate"] .sc-peek { color: #f1d27d; }
@keyframes scearned { 50% { transform: scale(1.12) rotate(-6deg); } }
/* The card: art first, one bar, one line, one gold button. */
#standchip .sc-card {
  position: absolute; top: calc(100% + 8px); left: 0; width: 236px; box-sizing: border-box;
  padding: 12px; border: 1px solid var(--ui-hairline); border-radius: 14px;
  background: linear-gradient(150deg, rgba(30, 48, 37, .98), rgba(16, 27, 20, .98));
  box-shadow: 0 14px 44px rgba(0, 0, 0, .48); color: var(--ui-ink); text-align: center;
}
#standchip .sc-card[hidden] { display: none; }
#standchip .sc-art { width: 88px; height: 88px; margin: -4px auto 2px; border-radius: 50%;
  background: radial-gradient(circle at 50% 40%, #3b5a40, #132019 70%); display: grid; place-items: center; }
#standchip .sc-art img { width: 80px; height: 80px; image-rendering: pixelated; }
/* Body face on purpose: the pixel display face draws this name's C like an O. */
#standchip .sc-title { display: block; font: 700 16px/1.2 var(--font-body); letter-spacing: .02em; color: #fff2c7; }
#standchip .sc-bar { height: 8px; margin: 8px 0 4px; border-radius: 4px; background: var(--ui-well); overflow: hidden; }
#standchip .sc-bar i { display: block; height: 100%; background: linear-gradient(90deg, #f1d27d, #c99443); }
#standchip .sc-count { margin: 0; font: 600 12px/1.3 var(--font-body); color: var(--ui-ink); font-variant-numeric: tabular-nums; }
#standchip .sc-line { margin: 6px 0 0; font: 500 12px/1.35 var(--font-body); color: var(--ui-muted); }
#standchip .sc-acts { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
#standchip .sc-cta, #standchip .sc-quiet {
  display: block; min-height: 36px; padding: 9px 10px; box-sizing: border-box; border-radius: 10px;
  font: 700 13px/1.2 var(--font-body); text-decoration: none; cursor: pointer; border: 0;
}
#standchip .sc-cta { background: linear-gradient(#f1d27d, #c99443); color: #22170e; }
#standchip .sc-quiet { background: var(--ui-raised); color: var(--ui-ink); }
@media (max-width: 560px) {
  /* The vitals pill is 44px tall on a phone: the chip matches it and sits right beside it. */
  body:not(.tut) #hud > #standchip { left: calc(100% + 6px); }
  /* No room beside the menu button: the word hangs under the chip instead, then tucks away. */
  #standchip .sc-peek { position: absolute; left: 0; top: calc(100% + 6px); padding: 0; border-radius: 12px;
    background: linear-gradient(150deg, rgba(30, 48, 37, .96), rgba(16, 27, 20, .97)); pointer-events: none; }
  #standchip.peeking .sc-peek { padding: 7px 10px; border: 1px solid var(--ui-hairline); }
  #standchip .sc-card { position: fixed; left: calc(14px + env(safe-area-inset-left, 0px)); top: calc(66px + env(safe-area-inset-top, 0px));
    width: min(236px, calc(100vw - 28px)); z-index: 30; }
}
