/* ==========================================================================
   LOOK BUSY — page shell, menus and HUD.
   Markup for everything inside #ui is built by js/ui.js (see template() there).
   Class names below match that markup one to one.

   Layers inside #ui, bottom to top (z-index):
     1 #lb-labels    floating name tags and popups pinned to the 3D anchors
     2 #lb-vignette  red edge glow while the boss is looking
     3 #lb-lids      nap "eyelids"
     4 #lb-glow      faint red pulse for a warning while napping
     5 #lb-hud       the in-game HUD
     6 #lb-countdown 3, 2, 1, GO!
     7 .screen       menu, lobby, results
     8 #lb-chat, #lb-toasts
     9 #lb-mute

   State lives on #ui:
     data-screen="none|menu|lobby|game|results"
     data-leaving / data-entering   the screen fading out / in, for a moment after a switch
     .is-tell .is-look .is-blind .is-stun .is-fired .is-spectating .is-danger .is-muted
     .is-rush (rush hour)  .is-busy (mash to look busy)  .is-laststrike  .has-busy  .has-touch
     .is-away (out of your chair)  .is-dash (dashing home)  .is-five (a high five is on)  .has-warn
     .is-unsafe (out of your chair and outside the safe circle: the dash pill shows)

   v4, "fewer words": during play the screen holds names, numbers and one short alert at most.
   Everything else is an icon, a key cap, a bar or a colour.

   Motion: things appear and go over --t; only transform and opacity are animated.
   ========================================================================== */

:root {
  --font: "Fredoka", "Baloo 2", "Nunito", "Arial Rounded MT Bold", "Segoe UI", system-ui,
          -apple-system, "Helvetica Neue", Arial, sans-serif;

  /* Light panels (menus) */
  --ink: #1c2437;
  --ink-soft: #5b6680;
  --paper: rgba(255, 255, 255, 0.9);        /* panel glass: the office stays visible, text stays readable */
  --line: rgba(28, 36, 55, 0.13);
  --tint: rgba(28, 36, 55, 0.06);

  /* Brand colours */
  --sun: #ffc533;
  --sun-deep: #e39a00;
  --teal: #14b8a6;
  --teal-deep: #0b8d80;
  --blue: #3a86ff;
  --blue-deep: #2460d1;
  --gold: #ffd43b;            /* points */
  --amber: #ffab2e;           /* hiding */
  --hot: #ff6a1f;             /* heat: pay multipliers, hot activity, streak */
  --mint: #7dffcf;            /* a close call, a mission done */
  --red: #ff3b30;             /* danger only: the boss, strikes, busted */
  --red-deep: #c4201a;

  /* One scale of corner radii and soft shadows, used everywhere */
  --r-xs: 6px;                /* key caps, badges, bar ends */
  --r-s: 10px;                /* chips, small rows */
  --r-m: 16px;                /* inputs, list rows, toasts */
  --r-l: 22px;                /* cards */
  --r-pill: 999px;
  --shadow-s: 0 2px 8px rgba(8, 20, 40, 0.2);
  --shadow-m: 0 8px 22px rgba(8, 20, 40, 0.24);
  --shadow-l: 0 18px 50px rgba(8, 30, 50, 0.3);

  /* Everything that appears or goes eases over this long. Only transform and opacity move. */
  --t: 0.18s;
  --ease: cubic-bezier(0.25, 0.8, 0.3, 1);

  /* HUD (white text floating over the 3D scene) */
  /* Soft, but dark enough close in that white text still reads over a white wall or ceiling */
  --hud-shadow: 0 0 2px rgba(8, 12, 22, 0.85), 0 1px 3px rgba(8, 12, 22, 0.7), 0 0 12px rgba(8, 12, 22, 0.4);
  --glass: rgba(16, 21, 32, 0.6);
  --glass-line: rgba(255, 255, 255, 0.18);

  --edge: clamp(8px, 1.6vmin, 18px);          /* distance from the screen edge */
  --stick: clamp(96px, 26vmin, 132px);        /* the touch stick (and the room the chat leaves for it) */
  --card-yellow: #ffd60a;                     /* a warning: the yellow card */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --pop: cubic-bezier(0.2, 1.5, 0.4, 1);
}

/* ---------------------------------------------------------------- page shell */

*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  position: fixed;
  inset: 0;
  /* Shown until WebGL draws (and if it never does): mint wall over a warm floor. */
  background: linear-gradient(#9be3d6 0%, #62cdbd 58%, #e8c48c 58%, #d9ae72 100%);
  color: var(--ink);
  font-family: var(--font);
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

#scene {
  position: fixed;
  inset: 0;
  z-index: 0;
  display: block;
  width: 100%;
  height: 100%;
  outline: none;
  touch-action: none;
}

#ui {
  position: fixed;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  pointer-events: none;               /* only real controls take the pointer */
  color: #fff;
  font-family: var(--font);
  font-weight: 500;
  line-height: 1.2;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

#ui [hidden] { display: none !important; }
/* Element-level reset on purpose: low specificity, so every class below can override it. */
button, input, textarea { margin: 0; font: inherit; color: inherit; }
button { -webkit-appearance: none; appearance: none; }

#ui :focus-visible { outline: 3px solid var(--focus, #fff); outline-offset: 3px; }
#ui :focus:not(:focus-visible) { outline: none; }
#ui .screen-in:focus-visible { outline: none; }      /* focus is parked here when a screen opens */

.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.noscript {
  position: fixed; left: 0; right: 0; bottom: 20%;
  z-index: 5; margin: 0; padding: 0 16px;
  text-align: center; font: 600 18px var(--font); color: #fff;
  text-shadow: var(--hud-shadow);
}

/* Loading splash (static markup in index.html, removed by js/ui.js) */
.boot {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; text-align: center;
}
.boot-logo {
  font-weight: 700; font-size: clamp(44px, 11vmin, 118px); line-height: 1; letter-spacing: 0.02em;
  color: #fff;
  text-shadow: 0 0.06em 0 rgba(20, 30, 50, 0.3), 0 0.12em 0.3em rgba(0, 0, 0, 0.3);
}
.boot-text {
  font-weight: 600; font-size: 18px; text-shadow: var(--hud-shadow);
  animation: lb-breathe 1.1s ease-in-out infinite alternate;
}
@keyframes lb-breathe { from { opacity: 0.45; } to { opacity: 1; } }

/* ---------------------------------------------------------------- shared bits */

.key {
  display: inline-grid; place-items: center;
  min-width: 1.75em; height: 1.75em; padding: 0 0.35em;
  border: 2px solid var(--ink); border-radius: 0.45em;
  background: #fff; color: var(--ink);
  box-shadow: 0 2px 0 var(--ink);
  font-size: 0.82em; font-weight: 700; line-height: 1; font-style: normal;
}

.dot {
  flex: none;
  width: 0.8em; height: 0.8em; border-radius: 50%;
  background: var(--c, #9aa3b5);
  box-shadow: 0 0 0 2px #fff, 0 1px 3px rgba(0, 0, 0, 0.3);
}

/* Strike pips: three slots, red when used */
.pips { display: inline-flex; align-items: center; gap: 3px; }
.pips i { display: block; width: 10px; height: 10px; border-radius: 50%; background: rgba(28, 36, 55, 0.14); }
.pips i.on { background: var(--red); }

/* ---------------------------------------------------------------- buttons, inputs */

.btn {
  --btn: var(--teal);
  --btn-deep: var(--teal-deep);
  --btn-ink: #fff;
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5em;
  min-height: 48px; padding: 0.5em 1.3em 0.56em;
  border: 0; border-radius: 999px;
  background: var(--btn); color: var(--btn-ink);
  box-shadow: 0 5px 0 var(--btn-deep), 0 10px 18px rgba(10, 30, 50, 0.2);
  font-weight: 600; font-size: clamp(16px, 1.2vmin + 10px, 20px); line-height: 1.1; letter-spacing: 0.01em;
  text-align: center; text-decoration: none; white-space: nowrap;
  cursor: pointer;
  pointer-events: auto;
  touch-action: manipulation;
  transition: transform 0.08s ease;
}
.btn:hover { filter: brightness(1.07); }
.btn:active { transform: translateY(4px); box-shadow: 0 1px 0 var(--btn-deep), 0 3px 6px rgba(10, 30, 50, 0.2); }
.btn:disabled {
  cursor: not-allowed; filter: grayscale(1); opacity: 0.5;
  transform: none; box-shadow: 0 5px 0 var(--btn-deep);
}
.btn-primary { --btn: var(--sun); --btn-deep: var(--sun-deep); --btn-ink: #3a2500; }
.btn-blue { --btn: var(--blue); --btn-deep: var(--blue-deep); }
.btn-ghost { --btn: #fff; --btn-deep: #c5cddc; --btn-ink: var(--ink); }
.btn-big { min-height: 58px; font-weight: 700; font-size: clamp(19px, 1.6vmin + 12px, 26px); }
.btn-small { min-height: 42px; padding: 0.4em 1em 0.46em; font-size: 15px; box-shadow: 0 4px 0 var(--btn-deep); }
.btn-small:active { transform: translateY(3px); box-shadow: 0 1px 0 var(--btn-deep); }
/* A button that is only an icon (copy link, copy result) */
.btn-ico { flex: none; min-width: 52px; padding-left: 0.7em; padding-right: 0.7em; font-size: 22px; }
.btn-small.btn-ico { min-width: 46px; font-size: 18px; }

.input {
  display: block; width: 100%; min-height: 48px; padding: 0.35em 0.9em;
  border: 2px solid rgba(28, 36, 55, 0.18); border-radius: var(--r-m);
  background: #fff; color: var(--ink);
  font-weight: 600; font-size: clamp(16px, 1.2vmin + 10px, 20px); line-height: 1.2;
  outline: none;
  pointer-events: auto;
  -webkit-user-select: text; user-select: text;
}
.input::placeholder { color: #a6aec0; font-weight: 500; opacity: 1; }
.input:focus, #ui .input:focus-visible { outline: none; border-color: var(--blue); box-shadow: 0 0 0 4px rgba(58, 134, 255, 0.22); }
.input:disabled { background: #eef1f6; color: #9aa3b5; cursor: not-allowed; }
.input-code { padding-left: 0.5em; padding-right: 0.2em; text-align: center; font-weight: 700; letter-spacing: 0.3em; text-transform: uppercase; }
.input-code::placeholder { letter-spacing: 0.12em; }
.input.is-wrong { border-color: var(--red); animation: lb-nudge 0.3s ease; }
@keyframes lb-nudge {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-6px); }
  75% { transform: translateX(6px); }
}

/* ---------------------------------------------------------------- screens and panels */

.screen {
  position: absolute; inset: 0; z-index: 7;
  display: none;
  flex-direction: column; align-items: center;
  padding: calc(var(--edge) + var(--safe-t)) calc(var(--edge) + var(--safe-r))
           calc(var(--edge) + var(--safe-b)) calc(var(--edge) + var(--safe-l));
  overflow-x: hidden; overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  pointer-events: auto;
  touch-action: pan-y;
}
#ui[data-screen="menu"] #lb-menu,
#ui[data-screen="lobby"] #lb-lobby,
#ui[data-screen="results"] #lb-results { display: flex; }

/* A screen that was just left stays up for a moment and fades out under the new one
   (js/ui.js sets data-leaving for 240 ms). The game HUD does the same, further down. */
#ui[data-leaving="menu"] #lb-menu,
#ui[data-leaving="lobby"] #lb-lobby,
#ui[data-leaving="results"] #lb-results { display: flex; pointer-events: none; animation: lb-out var(--t) ease both; }
@keyframes lb-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes lb-in { from { opacity: 0; } to { opacity: 1; } }

/* margin:auto centres the content and still lets a tall screen scroll from the top.
   flex:none: the content keeps its own height; when it is taller than the screen, the screen scrolls. */
.screen-in { flex: none; margin: auto; width: 100%; outline: none; animation: lb-screen-in 0.26s var(--ease) both; }
@keyframes lb-screen-in {
  from { opacity: 0; transform: translateY(12px) scale(0.985); }
  to { opacity: 1; transform: none; }
}

.panel {
  --focus: var(--ink);
  padding: clamp(14px, 2.6vmin, 28px);
  border: 2px solid rgba(255, 255, 255, 0.8); border-radius: clamp(20px, 3.4vmin, 34px);
  background: var(--paper); color: var(--ink);
  box-shadow: var(--shadow-l);
  -webkit-backdrop-filter: blur(12px) saturate(1.1);
  backdrop-filter: blur(12px) saturate(1.1);
}

.actions { display: flex; flex-direction: column; align-items: stretch; gap: 10px; }
.actions-row { display: flex; gap: 10px; }
.actions-row > .btn { flex: 1 1 0; min-width: 0; }
.waiting {                                           /* an hourglass: waiting for the host */
  margin: 0; padding: 9px 12px; border-radius: var(--r-m);
  background: var(--tint); color: var(--ink-soft);
  font-size: 24px; line-height: 1.2; text-align: center;
}

/* XP bar: the career card on the menu and the results screen */
.xp-bar { position: relative; height: 10px; border-radius: var(--r-pill); background: rgba(28, 36, 55, 0.12); overflow: hidden; }
.xp-bar i {
  position: absolute; inset: 0; border-radius: inherit;
  background: linear-gradient(90deg, var(--teal), #5fe0c2);
  transform-origin: 0 50%; transform: scaleX(0);
  transition: transform 0.8s var(--ease);
}
.xp-bar i.is-snap { transition: none; }

/* Missions on the results screen, the one place their words are shown: icon, text, XP, tick */
.mission-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; }
.mission { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; column-gap: 7px; align-items: center; line-height: 1.25; }
.mission-ico { font-size: 1.2em; line-height: 1; }
.mission-box {
  position: relative; display: block; width: 0.95em; height: 0.95em;
  border: 2px solid currentColor; border-radius: 4px; opacity: 0.85;
}
.mission-box::after {                                  /* the tick */
  content: ""; position: absolute; left: 22%; top: -2%; width: 36%; height: 68%;
  border: solid #fff; border-width: 0 2px 2px 0;
  transform: rotate(42deg) scale(0); transition: transform var(--t) var(--pop);
}
.mission.is-done .mission-box { border-color: var(--teal); background: var(--teal); opacity: 1; }
.mission.is-done .mission-box::after { transform: rotate(42deg) scale(1); }
.mission:not(.is-done) .mission-text, .mission:not(.is-done) .mission-ico { opacity: 0.62; }
.mission-prog { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---------------------------------------------------------------- logo */

.logo {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 0 0.3em;
  margin: 0;
  /* 11.5vw keeps a one-line logo clear of the sound button on a 360px phone */
  font-weight: 700; font-size: clamp(38px, min(12vmin, 11.5vw), 124px); line-height: 1.02; letter-spacing: 0.01em;
  filter: drop-shadow(0 0.055em 0 rgba(20, 30, 50, 0.32)) drop-shadow(0 0.1em 0.14em rgba(0, 0, 0, 0.22));
}
.logo-word { display: inline-flex; white-space: nowrap; }
/* One letter = a white, fattened copy (.ll-b) under a copy filled with paint splats (.ll-f). */
.ll { position: relative; display: inline-block; padding: 0 0.015em; transform: rotate(var(--r, 0deg)) translateY(var(--y, 0em)); }
.ll-b, .ll-f { display: block; }
.ll-b {
  position: absolute; left: 0.015em; top: 0;
  color: #fff;
  text-shadow:
     0.075em 0 #fff, -0.075em 0 #fff, 0 0.075em #fff, 0 -0.075em #fff,
     0.053em 0.053em #fff, -0.053em 0.053em #fff, 0.053em -0.053em #fff, -0.053em -0.053em #fff,
     0.069em 0.029em #fff, -0.069em 0.029em #fff, 0.069em -0.029em #fff, -0.069em -0.029em #fff,
     0.029em 0.069em #fff, -0.029em 0.069em #fff, 0.029em -0.069em #fff, -0.029em -0.069em #fff;
}
.ll-f {
  position: relative;
  color: transparent;
  -webkit-text-fill-color: transparent;
  background-color: #ff8a3d;
  background-image:
    radial-gradient(circle at 20% 22%, #ff4d8d 0 0.2em, transparent calc(0.2em + 1px)),
    radial-gradient(circle at 76% 14%, #ffd23f 0 0.18em, transparent calc(0.18em + 1px)),
    radial-gradient(circle at 46% 56%, #2ec4b6 0 0.25em, transparent calc(0.25em + 1px)),
    radial-gradient(circle at 90% 68%, #9b5de5 0 0.2em, transparent calc(0.2em + 1px)),
    radial-gradient(circle at 10% 80%, #3a86ff 0 0.19em, transparent calc(0.19em + 1px)),
    radial-gradient(circle at 60% 98%, #8ac926 0 0.16em, transparent calc(0.16em + 1px));
  background-size: 1.05em 1.2em;
  background-position: var(--bx, 0em) var(--by, 0em);
  -webkit-background-clip: text;
  background-clip: text;
}

/* ---------------------------------------------------------------- menu */

/* No sentences (v4): the play column, the career card beside it when there is one, and
   under both one row of key-cap chips that says how to play. */
.menu-in { max-width: 520px; display: flex; flex-direction: column; align-items: center; gap: clamp(8px, 2vmin, 20px); }
#lb-menu.has-career .menu-in { max-width: 860px; }
.brand { text-align: center; }
.menu-panel {
  width: 100%;
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: clamp(12px, 2.2vmin, 22px) clamp(14px, 3vmin, 32px);
}
#lb-menu.has-career .menu-panel { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.menu-play { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.or { height: 2px; margin: 4px 0; border-radius: 2px; background: var(--line); }
.join-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: center; }
#lb-menu.has-code #lb-join { --btn: var(--sun); --btn-deep: var(--sun-deep); --btn-ink: #3a2500; }
.note { margin: 0; font-size: 14px; line-height: 1.3; color: var(--ink-soft); }

/* How to play: [W][A][S][D] 🚶   [J][K][L] 📱🎮😴   [Space] ⌨️↩️   [C] ✋   [E] 📣 */
.menu-how {
  grid-column: 1 / -1;
  list-style: none; margin: 0; padding: clamp(10px, 1.8vmin, 16px) 0 0;
  border-top: 2px dashed var(--line);
  display: flex; flex-wrap: wrap; justify-content: center; gap: 8px;
}
.how { display: inline-flex; align-items: center; gap: 3px; min-height: 40px; padding: 4px 11px 5px 8px; border-radius: var(--r-pill); background: var(--tint); white-space: nowrap; }
.how .key { font-size: 13px; }
.how-ico { margin-left: 5px; font-size: 20px; line-height: 1; }

/* Career card (LB.UI.setCareer): level badge, XP bar, four numbers with icons, the hats */
.menu-career {
  display: flex; flex-direction: column; gap: 10px; min-width: 0;
  padding-left: clamp(14px, 3vmin, 32px);
  border-left: 2px dashed var(--line);
}
.career-top { display: flex; align-items: center; gap: 12px; min-width: 0; }
.lvl {
  flex: none; display: grid; place-items: center; align-content: center;
  width: 62px; height: 62px; border-radius: 50%;
  background: var(--sun); color: #3a2500;
  box-shadow: inset 0 -4px 0 var(--sun-deep), var(--shadow-s);
  font-size: 28px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums;
}
.lvl-small { width: 40px; height: 40px; font-size: 19px; box-shadow: inset 0 -3px 0 var(--sun-deep), var(--shadow-s); }
.career-id { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.career-xp { font-size: 13px; font-weight: 600; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.career-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; margin: 0; }
.career-stats div { display: flex; flex-direction: column; align-items: center; gap: 1px; padding: 6px 4px 7px; border-radius: var(--r-s); background: var(--tint); }
.career-stats i { font-style: normal; font-size: 17px; line-height: 1.15; }
.career-stats b { font-size: 17px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.hats { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; }
/* A hat is its icon; a locked one is greyed, with a lock and the level that opens it */
.hat {
  position: relative; min-width: 0;
  display: grid; grid-template-columns: auto auto; justify-content: center; align-content: center; align-items: center; column-gap: 2px;
  min-height: 58px; padding: 5px 2px;
  border: 0; border-radius: var(--r-s);
  background: var(--tint); color: var(--ink);
  cursor: pointer; pointer-events: auto; touch-action: manipulation;
  transition: transform 0.08s ease;
}
.hat::after {                                          /* the ring round the hat being worn */
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  box-shadow: inset 0 0 0 3px var(--teal);
  opacity: 0; transition: opacity var(--t) ease;
}
.hat.is-on { background: #fff; }
.hat.is-on::after { opacity: 1; }
.hat:hover { background: #fff; }
.hat:active { transform: translateY(2px); }
.hat-ico { grid-column: 1 / -1; justify-self: center; font-size: 26px; line-height: 1.15; }
.hat-lock { font-size: 10px; line-height: 1.2; }
.hat-need { font-size: 11.5px; font-weight: 700; line-height: 1.2; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.hat.is-locked { cursor: default; }
.hat.is-locked .hat-ico { font-size: 21px; opacity: 0.35; filter: grayscale(1); }
.hat.is-wrong { animation: lb-nudge 0.3s ease; }

/* ---------------------------------------------------------------- lobby */

.lobby-panel { max-width: 560px; display: flex; flex-direction: column; gap: 12px; text-align: center; }
.room-code {
  margin: -4px 0 0; padding-left: 0.14em;
  font-weight: 700; font-size: clamp(58px, 17vmin, 124px); line-height: 1; letter-spacing: 0.14em;
  -webkit-user-select: text; user-select: text;
}
.link-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: center; }
.input-link { min-height: 42px; font-size: 16px; font-weight: 500; text-overflow: ellipsis; }
.lobby-head { display: flex; align-items: center; gap: 8px; margin-top: 2px; text-align: left; font-size: 18px; line-height: 1.2; }
.count { font-weight: 600; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.plist { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(138px, 1fr)); gap: 6px; text-align: left; }
.prow { display: flex; align-items: center; gap: 8px; min-width: 0; padding: 8px 10px; border-radius: var(--r-m); background: var(--tint); font-weight: 600; }
.prow.is-local { grid-column: 1 / -1; background: #fff; box-shadow: inset 0 0 0 2px var(--teal); }   /* listed first, full width */
.prow-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.crown { flex: none; font-size: 1.1em; line-height: 1; }
.bots-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 6px 8px 6px 12px; border-radius: var(--r-m); background: var(--tint); text-align: left; font-weight: 600; }
.bots-ico { font-size: 26px; line-height: 1; }
.stepper { display: inline-flex; align-items: center; gap: 6px; }
.step {
  display: grid; place-items: center;
  width: 40px; height: 40px; padding: 0 0 2px;
  border: 0; border-radius: 50%;
  background: var(--ink); color: #fff;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.35);
  font-size: 24px; font-weight: 700; line-height: 1;
  cursor: pointer; pointer-events: auto; touch-action: manipulation;
  transition: transform 0.08s ease;
}
.step:active { transform: translateY(2px); box-shadow: 0 1px 0 rgba(0, 0, 0, 0.35); }
.step:disabled { opacity: 0.28; cursor: not-allowed; transform: none; }
.step-val { min-width: 1.5em; text-align: center; font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------- results */

.results-panel { max-width: 640px; max-height: 100%; min-height: 0; display: flex; flex-direction: column; gap: 12px; }
.res-title { margin: 0; text-align: center; font-size: clamp(24px, 3vmin + 12px, 42px); font-weight: 700; line-height: 1.05; }
/* The ranking, then everything about you. Side by side when there is XP to show (.has-xp). */
.res-body { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; gap: 12px; }
.res-side { flex: none; min-width: 0; display: flex; flex-direction: column; gap: 10px; }
.results-panel.has-xp { max-width: 1010px; }
.results-panel.has-xp .res-body {
  display: grid; grid-template-columns: minmax(0, 11fr) minmax(0, 9fr); grid-template-rows: minmax(0, 1fr);
  gap: clamp(14px, 2.4vmin, 26px);
}
/* Both columns take the row's height; whichever is too tall for the screen scrolls by itself. */
.results-panel.has-xp .res-side { min-height: 0; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; padding: 3px 3px 20px; }   /* room for the buttons' shadows */
.results-panel.has-xp .res-side .actions { margin-top: auto; }
.res-list {
  list-style: none; margin: 0; padding: 3px;
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; gap: 6px;
  overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y;
}

/* XP earned today: the level badge, a bar that runs from where the career stood to where it
   stands now, and "+70" */
.xp { display: flex; flex-direction: column; gap: 8px; padding: 10px 14px 11px; border-radius: var(--r-m); background: var(--tint); }
.xp-head { display: flex; align-items: center; gap: 10px; }
.xp-head .xp-bar { flex: 1 1 auto; min-width: 0; }
.xp-gain { font-size: clamp(20px, 1.6vmin + 12px, 28px); font-weight: 700; color: var(--teal-deep); font-variant-numeric: tabular-nums; white-space: nowrap; }
.levelup {
  padding: 7px 12px 8px; border-radius: var(--r-s);
  background: var(--sun); color: #3a2500;
  box-shadow: inset 0 -3px 0 var(--sun-deep);
  font-weight: 700; text-align: center;
  animation: lb-levelup 0.5s var(--pop) both;
}
.levelup > b { letter-spacing: 0.06em; }
.unlocks { margin-left: 0.5em; font-size: 1.35em; line-height: 1; vertical-align: -0.1em; }
@keyframes lb-levelup { from { opacity: 0; transform: scale(0.7); } to { opacity: 1; transform: none; } }
.res-missions { padding: 10px 14px 11px; border-radius: var(--r-m); background: var(--tint); font-size: 15px; font-weight: 600; }
.res-missions .mission-prog { color: var(--teal-deep); }
.res-missions .mission-box { color: var(--ink-soft); }
.res-row {
  flex: none;
  display: grid; grid-template-columns: 2.1em auto minmax(0, 1fr) auto auto; align-items: center; column-gap: 10px;
  padding: 7px 12px; border-radius: var(--r-m);
  background: var(--tint);
}
.res-row.is-local { background: #fff; box-shadow: inset 0 0 0 3px var(--gold), var(--shadow-s); }
.res-rank { text-align: center; font-size: 1.15em; font-weight: 700; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.res-row.is-first .res-rank { color: #b97b00; font-size: 1.35em; }
.res-who { min-width: 0; display: flex; align-items: center; gap: 6px; }
.res-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 700; }
.res-bot { flex: none; font-size: 0.95em; line-height: 1; opacity: 0.75; }
.res-score { text-align: right; font-size: 1.25em; font-weight: 700; font-variant-numeric: tabular-nums; }
.res-row.is-fired .res-name { text-decoration: line-through; text-decoration-color: var(--red); text-decoration-thickness: 2px; }
.res-row.is-fired .res-score, .res-row.is-gone .res-score { color: var(--ink-soft); }
.res-row.is-gone { opacity: 0.6; }
.best { margin: 0; text-align: center; font-size: 1.15em; font-weight: 700; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.best.is-new { color: #a85d00; font-weight: 700; animation: lb-best 0.7s var(--pop) both; }
@keyframes lb-best { from { transform: scale(0.6); opacity: 0; } to { transform: none; opacity: 1; } }
.share {
  display: block; width: 100%; min-height: 84px; padding: 8px 10px;
  border: 2px solid var(--line); border-radius: var(--r-s); background: #fff; color: var(--ink);
  font-weight: 500; font-size: 16px; line-height: 1.3; resize: none;
  pointer-events: auto; -webkit-user-select: text; user-select: text;
}

/* ==========================================================================
   Game HUD. White text with a soft shadow over the scene, as few boxes as possible.
   ========================================================================== */

.hud {
  position: absolute; inset: 0; z-index: 5;
  display: none;
  touch-action: none;
}
#ui[data-screen="game"] .hud { display: block; }
/* The HUD and the labels fade in when a game opens and out when it is left (see .screen) */
#ui[data-entering="game"] .hud, #ui[data-entering="game"] .labels { animation: lb-in var(--t) ease both; }
#ui[data-leaving="game"] .hud, #ui[data-leaving="game"] .labels { display: block; animation: lb-out var(--t) ease both; }
#ui[data-leaving="game"] .hud button { pointer-events: none; }

.hud .key {
  border-color: #fff; background: rgba(255, 255, 255, 0.16); color: #fff;
  box-shadow: none; text-shadow: none;
}

/* ---------------------------------------------------------------- top centre */

.hud-top {
  position: absolute; left: 50%; top: calc(var(--edge) + var(--safe-t));
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: clamp(3px, 0.8vmin, 8px);
  width: max-content; max-width: calc(100% - 2 * var(--edge));
  text-shadow: var(--hud-shadow);
}

/* Row of little people, one per player, in desk order */
.pl-row { display: flex; align-items: flex-end; justify-content: center; gap: clamp(3px, 0.9vmin, 9px); min-height: clamp(32px, 5.4vmin, 50px); }
.pi {
  --c: #fff;
  position: relative; flex: none;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  width: clamp(19px, 3.2vmin, 29px);
  transition: opacity 0.2s ease;
}
.pi.is-local { width: clamp(25px, 4.3vmin, 39px); }
/* Two shadows: a thin dark rim so a white figure still shows against a white ceiling light */
.pi-fig { display: block; width: 100%; color: #fff; filter: drop-shadow(0 0 1px rgba(8, 12, 22, 0.8)) drop-shadow(0 1px 2px rgba(8, 12, 22, 0.5)); }
.pi-fig svg { display: block; width: 100%; height: auto; overflow: visible; }
.pi-base { fill: var(--c); stroke: rgba(0, 0, 0, 0.25); stroke-width: 0.6; }
.pi-body { fill: currentColor; }
.pi-face { fill: none; stroke: #1c2437; stroke-width: 1; stroke-linecap: round; }
.pi-eye { fill: #1c2437; }
.pi-x { display: none; fill: none; stroke: #fff; stroke-width: 3; stroke-linecap: round; }
.pi.is-fired .pi-fig { color: var(--red); }
.pi.is-fired .pi-x { display: block; }
.pi.is-gone { opacity: 0.32; }
.pi.is-hit .pi-fig { color: var(--red); animation: lb-hit 0.5s ease; }
@keyframes lb-hit {
  0%, 100% { transform: none; }
  20% { transform: translateY(-4px) scale(1.15); }
}
.pi-pips { display: flex; justify-content: center; gap: 2px; height: 5px; }
.pi-pips i { display: block; width: 5px; height: 5px; border-radius: 50%; background: var(--red); box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.4); opacity: 0; }
.pi-pips i.on { opacity: 1; }
/* A yellow card on the little figure of a player with a warning */
.pi::after {
  content: ""; position: absolute; right: -3px; top: -1px; width: 6px; height: 8px; border-radius: 1.5px;
  background: var(--card-yellow); box-shadow: 0 0 0 1px rgba(43, 26, 0, 0.7);
  opacity: 0; transform: rotate(10deg) scale(0.4); transition: opacity var(--t) ease, transform var(--t) var(--pop);
}
.pi.has-warn::after { opacity: 1; transform: rotate(10deg); }

/* Clock and day progress */
.clock { position: relative; display: flex; align-items: center; gap: 6px; font-weight: 600; font-size: clamp(14px, 1.3vmin + 9px, 22px); }
.clock-ico { display: block; width: 0.9em; height: 0.9em; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.55)); }
.clock-ico svg { display: block; width: 100%; height: 100%; fill: #fff; }
.clock-text { min-width: 4.7em; font-variant-numeric: tabular-nums; }
.day { position: relative; width: clamp(64px, 13vmin, 150px); height: 5px; border-radius: 3px; background: rgba(255, 255, 255, 0.32); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45); overflow: hidden; }
.day i { position: absolute; inset: 0; border-radius: inherit; background: #fff; transform-origin: 0 50%; transform: scaleX(0); }

/* Rush hour (the last 20 s): the clock goes gold and beats until 5 PM */
#ui.is-rush .clock { color: var(--gold); animation: lb-rush 0.5s ease-in-out infinite alternate; }
#ui.is-rush .clock-ico svg { fill: var(--gold); }
#ui.is-rush .day i { background: var(--gold); }
@keyframes lb-rush { from { transform: scale(1); } to { transform: scale(1.09); } }

/* The last ten seconds: one digit a second, to the right of the clock (never over the boss) */
.final {
  position: absolute; left: 100%; top: 50%; margin-left: 0.5em;
  color: var(--gold); font-size: 1.9em; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums;
  opacity: 0; transform: translateY(-50%);
}
.final.is-on { animation: lb-final 0.95s ease both; }
@keyframes lb-final {
  0% { opacity: 0; transform: translateY(-50%) scale(2.2); }
  18% { opacity: 1; transform: translateY(-50%) scale(1); }
  70% { opacity: 1; transform: translateY(-50%) scale(1); }
  100% { opacity: 0; transform: translateY(-50%) scale(0.8); }
}

/* Boss suspicion: the main thing players read */
.sus {
  display: flex; flex-direction: column; gap: 3px;
  width: clamp(230px, 34vw, 470px); max-width: 100%; margin-top: 2px;
  transition: opacity var(--t) ease, visibility 0s;
}
.sus-label { display: flex; align-items: flex-end; justify-content: space-between; gap: 8px; font-size: clamp(11px, 0.7vmin + 7px, 14px); font-weight: 700; line-height: 1.15; }
.sus-eye { font-size: 1.9em; line-height: 1; text-shadow: none; filter: drop-shadow(0 1px 2px rgba(8, 12, 22, 0.6)); }
.sus-bar {
  position: relative; height: clamp(14px, 2.2vmin, 22px);
  border: 2px solid #fff; border-radius: var(--r-pill);
  background: rgba(12, 16, 26, 0.62);
  box-shadow: 0 0 0 1.5px rgba(8, 12, 22, 0.5), 0 2px 8px rgba(0, 0, 0, 0.35);
}
.sus-clip { position: absolute; inset: 0; border-radius: inherit; overflow: hidden; }
.sus-fill { position: absolute; inset: 0; background: #fff; transform-origin: 0 50%; transform: scaleX(0); will-change: transform; }
/* Danger zone [susZone, 1]: hatched red, drawn over the fill. js/ui.js sets `left`. */
.sus-zone {
  position: absolute; top: 0; bottom: 0; right: 0; left: 72%;
  border-left: 2px solid var(--red);
  background: repeating-linear-gradient(-45deg, rgba(255, 59, 48, 0.95) 0 5px, rgba(255, 59, 48, 0.3) 5px 10px);
}
/* In the danger zone the bar beats and a red glow breathes round it (a layer that only fades) */
.sus-bar::after {
  content: ""; position: absolute; inset: -2px; border-radius: inherit;
  box-shadow: 0 0 0 4px rgba(255, 59, 48, 0.55), 0 0 26px 4px rgba(255, 59, 48, 0.85);
  opacity: 0; transition: opacity var(--t) ease;
}
#ui.is-danger .sus-bar { animation: lb-beat 0.42s ease-in-out infinite alternate; }
#ui.is-danger .sus-bar::after { opacity: 1; animation: lb-breathe 0.42s ease-in-out infinite alternate; }
@keyframes lb-beat { from { transform: scale(1); } to { transform: scale(1.03); } }

/* Heat: a coin and "×2.4" at the end of the meter. The hot-coloured copy fades in over the white
   one as the multiplier rises, and the readout grows a little (both set by js/ui.js). */
.heat {
  display: inline-flex; align-items: baseline; gap: 0.4em;
  letter-spacing: 0.02em; white-space: nowrap;
  transform-origin: 100% 100%;
  opacity: 0; transition: opacity var(--t) ease;
}
.heat.is-on { opacity: 1; }
.heat-coin { font-style: normal; font-size: 1.15em; line-height: 1; text-shadow: none; }
.heat-n { position: relative; display: inline-block; font-size: 1.45em; line-height: 1; font-variant-numeric: tabular-nums; }
.heat-hot { position: absolute; left: 0; top: 0; color: var(--hot); opacity: 0; }
#ui.is-danger .heat-n { animation: lb-beat 0.42s ease-in-out infinite alternate; }

/* Napping: you cannot read the boss. Looking: the meter means nothing (alerts cover it). */
#ui.is-blind .sus, #ui.is-look .sus {
  opacity: 0; visibility: hidden;
  transition: opacity var(--t) ease, visibility 0s linear var(--t);
}

/* Alerts (the tell "!", "LOOK BUSY!", "PHEW!") grow upward from the bottom edge of
   the meter, so they cover the meter and never the boss, who stands just below it. */
.alerts { position: relative; width: 100%; height: 0; margin-top: 0; }
.banner, .tell, .falsealarm { position: absolute; left: 50%; top: auto; bottom: 0; pointer-events: none; }

/* Announcements (rush hour, a hot activity, a mission done) drop in over the row of players:
   the top edge is the one place that covers neither the meter nor the boss. */
.announce { position: absolute; left: 50%; top: 0; z-index: 3; width: max-content; max-width: calc(100vw - 110px); pointer-events: none; transform: translateX(-50%); }
.announce-in {
  display: block; padding: 0.4em 1.1em 0.46em; border-radius: var(--r-pill);
  background: var(--ink); color: #fff;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.92), var(--shadow-m);
  font-weight: 700; font-size: clamp(17px, 1.6vmin + 10px, 28px); line-height: 1.15; letter-spacing: 0.04em; font-variant-numeric: tabular-nums;
  text-align: center; text-shadow: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  opacity: 0; transform: translateY(-140%);
}
.announce[data-kind="rush"] .announce-in { background: var(--gold); color: #3a2500; }
.announce[data-kind="hot"] .announce-in { background: var(--hot); }
.announce[data-kind="mission"] .announce-in { background: var(--teal-deep); }
.announce.is-on .announce-in { animation: lb-announce 2.7s var(--ease) both; }
@keyframes lb-announce {
  0% { opacity: 0; transform: translateY(-140%); }
  8% { opacity: 1; transform: translateY(6%); }
  12%, 88% { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(-60%); }
}
.banner {
  max-width: calc(100vw - 16px);
  padding: 0.34em 1em 0.4em; border-radius: 999px;
  background: var(--red); color: #fff;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.92), 0 8px 24px rgba(150, 10, 0, 0.5);
  font-weight: 700; font-size: clamp(14px, 1.5vmin + 8px, 26px); line-height: 1.1; letter-spacing: 0.07em;
  text-shadow: none; white-space: nowrap;
  opacity: 0; transform: translate(-50%, -8px) scale(0.9);
  transition: opacity 0.1s ease, transform 0.16s var(--pop);
}
#ui.is-look .banner { opacity: 1; transform: translate(-50%, 0) scale(1); }
#ui.is-look.is-stun .banner, #ui.is-look.is-fired .banner { opacity: 0; }      /* "BUSTED!" is the one alert then */
.tell {
  display: grid; place-items: center;
  width: 1.25em; height: 1.25em; border-radius: 50%;
  background: var(--red); color: #fff;
  box-shadow: 0 0 0 0.07em #fff, 0 0.08em 0.3em rgba(0, 0, 0, 0.45);
  font-weight: 700; font-size: clamp(44px, 8vmin, 96px); line-height: 1; text-shadow: none;
  opacity: 0; transform: translate(-50%, 0) scale(0.4);
}
.tell.is-on { opacity: 1; transform: translate(-50%, 0) scale(1); animation: lb-tell 0.3s var(--pop) both; }
@keyframes lb-tell {
  0% { opacity: 0; transform: translate(-50%, 0) scale(0.2) rotate(-14deg); }
  55% { opacity: 1; transform: translate(-50%, 0) scale(1.22) rotate(5deg); }
  100% { opacity: 1; transform: translate(-50%, 0) scale(1) rotate(0deg); }
}
.falsealarm {
  padding: 0.25em 0.8em 0.3em; border-radius: 999px;
  background: rgba(16, 21, 32, 0.6);
  font-weight: 600; font-size: clamp(13px, 1vmin + 8px, 19px); white-space: nowrap; text-shadow: none;
  opacity: 0; transform: translate(-50%, 0);
}
.falsealarm.is-on { animation: lb-false 1.3s ease both; }
@keyframes lb-false {
  0% { opacity: 0; transform: translate(-50%, 8px); }
  15%, 70% { opacity: 1; transform: translate(-50%, 0); }
  100% { opacity: 0; transform: translate(-50%, -6px); }
}
#ui.is-blind .tell, #ui.is-blind .banner, #ui.is-blind .falsealarm { visibility: hidden; }

/* ---------------------------------------------------------------- scoreboard and missions */

/* The scoreboard sits top-left over an empty wall, the mission chips under it. */
.side {
  position: absolute; left: calc(var(--edge) + var(--safe-l)); top: calc(var(--edge) + var(--safe-t));
  display: flex; flex-direction: column; align-items: flex-start; gap: clamp(8px, 1.6vmin, 16px);
  text-shadow: var(--hud-shadow);
}
/* Scoreboard: rows are stacked with translateY so a rank change slides (js/ui.js) */
.board {
  --row: clamp(20px, 1.2vmin + 13px, 27px);
  position: relative; width: clamp(150px, 15vw, 215px); height: calc(var(--n, 0) * var(--row));
  font-size: clamp(12px, 0.7vmin + 8px, 16px); font-weight: 600;
}
.brow {
  position: absolute; left: 0; right: 0; top: 0; height: var(--row);
  display: grid; grid-template-columns: 1.3em auto minmax(0, 1fr) auto; align-items: center; column-gap: 6px;
  padding: 0 7px; border-radius: var(--r-xs);
  transition: transform 0.3s var(--ease), opacity var(--t) ease;
}
.brow .dot { width: 0.62em; height: 0.62em; box-shadow: 0 0 0 1.5px #fff, 0 1px 3px rgba(0, 0, 0, 0.5); }
.brow-rank { text-align: right; opacity: 0.85; font-variant-numeric: tabular-nums; }
.brow-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.brow-score { font-weight: 700; font-variant-numeric: tabular-nums; }
.brow.is-local { background: rgba(255, 255, 255, 0.2); }
.brow.is-fired, .brow.is-gone { opacity: 0.45; }
.brow.is-fired .brow-name { text-decoration: line-through; }

/* Missions for this run, under the scoreboard: a chip each, an icon over a progress bar,
   ticked when done. What it asks is in the tooltip (and in full on the results screen). */
.missions { font-size: clamp(12px, 0.7vmin + 8px, 15px); }
.mission-chips { list-style: none; margin: 0; padding: 0; display: flex; gap: 6px; }
.mchip {
  position: relative; flex: none;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  width: 2.9em; padding: 4px 5px 5px; border-radius: var(--r-s);
  background: var(--glass); box-shadow: inset 0 0 0 1.5px var(--glass-line);
  text-shadow: none; pointer-events: auto;
}
.mchip-ico { font-size: 1.45em; line-height: 1.15; }
.mchip-bar { position: relative; display: block; width: 100%; height: 4px; border-radius: 2px; background: rgba(255, 255, 255, 0.22); overflow: hidden; }
.mchip-bar i { position: absolute; inset: 0; border-radius: inherit; background: var(--gold); transform-origin: 0 50%; transform: scaleX(0); transition: transform 0.25s var(--ease); }
.mchip.is-done { background: rgba(11, 141, 128, 0.82); }
.mchip.is-done .mchip-bar i { background: var(--mint); }
.mchip-tick {
  position: absolute; right: -4px; top: -4px; width: 15px; height: 15px; border-radius: 50%;
  background: var(--mint); box-shadow: 0 0 0 1.5px rgba(8, 12, 22, 0.55);
  opacity: 0; transform: scale(0.3); transition: opacity var(--t) ease, transform var(--t) var(--pop);
}
.mchip-tick::after { content: ""; position: absolute; left: 35%; top: 15%; width: 30%; height: 52%; border: solid #064d3c; border-width: 0 2px 2px 0; transform: rotate(42deg); }
.mchip.is-done .mchip-tick { opacity: 1; transform: none; }
.mchip.is-flash { animation: lb-mission 1s ease; }
@keyframes lb-mission {
  0% { transform: scale(1); }
  18% { transform: scale(1.3); }
  36%, 100% { transform: scale(1); }
}

/* ---------------------------------------------------------------- touch stick */

/* The stick that walks you round the office: bottom left, just above the dock. Shown for
   coarse pointers and for anyone who has touched the screen. js/ui.js moves the knob. */
.stick {
  position: absolute; z-index: 2;
  left: calc(var(--edge) + var(--safe-l)); bottom: calc(var(--dock-h, 190px) + 2 * var(--edge) + var(--safe-b));
  display: none; width: var(--stick); height: var(--stick); border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.85); background: rgba(16, 21, 32, 0.4);
  box-shadow: var(--shadow-s);
  pointer-events: auto; touch-action: none;
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
  transition: opacity var(--t) ease;
}
.stick-knob {
  position: absolute; left: 29%; top: 29%; width: 42%; height: 42%; border-radius: 50%;
  background: #fff; box-shadow: 0 3px 0 rgba(0, 0, 0, 0.35), var(--shadow-s);
  will-change: transform;
}
.stick:not(.is-held) .stick-knob { transition: transform 0.12s var(--ease); }
#ui.has-touch[data-screen="game"] .stick { display: block; }
@media (pointer: coarse) { #ui[data-screen="game"] .stick { display: block; } }
#ui.is-stun .stick, #ui.is-fired .stick { opacity: 0.35; pointer-events: none; }
#ui[data-screen].is-spectating .stick { display: none; }

/* ---------------------------------------------------------------- bottom dock */

.dock {
  position: absolute; left: 50%; bottom: calc(var(--edge) + var(--safe-b));
  transform: translateX(-50%);
  display: flex; flex-direction: column; gap: clamp(4px, 1vmin, 10px);
  /* 880px on a laptop, up to 1100px on a big monitor, never wider than the screen */
  width: min(clamp(880px, 30vw + 500px, 1100px), calc(100% - 2 * var(--edge) - var(--safe-l) - var(--safe-r)));
}
.dock-top {
  display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: end; gap: 8px;
  padding: 0 4px;
  text-shadow: var(--hud-shadow);
}
.stat-score { position: relative; justify-self: start; min-width: 0; max-width: 100%; display: flex; flex-direction: column; align-items: flex-start; line-height: 1.05; }
.stat-label { display: flex; align-items: center; gap: 0.7em; min-height: 1.9em; margin-bottom: 2px; font-size: clamp(10px, 0.6vmin + 7px, 13px); font-weight: 700; }
.score { display: block; font-size: clamp(22px, 2.4vmin + 12px, 40px); font-weight: 700; font-variant-numeric: tabular-nums; transform-origin: 0 60%; }
.score.is-bump { animation: lb-bump 0.4s var(--pop); }
@keyframes lb-bump { 0% { transform: scale(1); } 40% { transform: scale(1.28); } 100% { transform: scale(1); } }
/* "#4": where the local player stands, as a badge over the score */
.rank {
  display: inline-block; min-width: 2.3em; padding: 0.08em 0.5em 0.14em; border-radius: var(--r-pill);
  background: #fff; color: var(--ink);
  box-shadow: var(--shadow-s);
  font-size: clamp(12px, 0.8vmin + 8px, 16px); font-weight: 700; line-height: 1.25; letter-spacing: 0;
  font-variant-numeric: tabular-nums; text-align: center; text-shadow: none;
}
.rank:empty { visibility: hidden; }

/* Streak: a flame and what it adds to every pot, beside the rank badge */
.streak {
  display: inline-flex; align-items: center; gap: 2px;
  color: var(--gold); font-size: 1.3em; line-height: 1; letter-spacing: 0;
  opacity: 0; transform: scale(0.5); transform-origin: 0 50%;
  transition: opacity var(--t) ease, transform var(--t) var(--pop);
}
.streak.is-on { opacity: 1; transform: none; }
.streak i { display: inline-block; font-style: normal; text-shadow: none; transform-origin: 50% 90%; transition: transform var(--t) var(--pop); }
.streak b { font-variant-numeric: tabular-nums; }
.streak.is-bump { animation: lb-streak 0.5s var(--pop); }
@keyframes lb-streak { 0% { transform: scale(1); } 35% { transform: scale(1.7) rotate(-8deg); } 100% { transform: scale(1); } }
/* The streak is lost: a crossed-out flame where it stood */
.streak-lost {
  position: absolute; left: 3.6em; top: -0.1em;
  font-size: clamp(15px, 1vmin + 9px, 20px); line-height: 1.2; text-shadow: none; white-space: nowrap;
  opacity: 0; pointer-events: none;
}
.streak-lost::after { content: "✕"; position: absolute; inset: 0; display: grid; place-items: center; color: var(--red); font-size: 1.25em; font-weight: 700; text-shadow: 0 0 2px #fff, 0 0 2px #fff; }
.streak-lost.is-on { animation: lb-streak-lost 1.5s ease both; }
@keyframes lb-streak-lost {
  0% { opacity: 0; transform: scale(1.5); }
  10% { opacity: 1; transform: scale(1) rotate(-3deg); }
  60% { opacity: 1; transform: translateY(0) rotate(-3deg); }
  100% { opacity: 0; transform: translateY(16px) rotate(9deg); }
}

/* "▲ #2" pops above the score when the local player overtakes someone */
.rankup {
  position: absolute; left: 0; bottom: 100%; margin-bottom: 5px;
  padding: 0.2em 0.7em 0.26em; border-radius: var(--r-pill);
  background: var(--teal); color: #fff;
  box-shadow: var(--shadow-s);
  font-size: clamp(13px, 1vmin + 8px, 19px); font-weight: 700; letter-spacing: 0.04em; white-space: nowrap; text-shadow: none;
  opacity: 0; pointer-events: none; transform-origin: 0 100%;
}
.rankup.is-on { animation: lb-rankup 1.5s ease both; }
@keyframes lb-rankup {
  0% { opacity: 0; transform: translateY(10px) scale(0.6); }
  12% { opacity: 1; transform: translateY(0) scale(1.12); }
  20%, 78% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: translateY(-10px); }
}

/* Docked pay: a red "−480" above the score while it counts down */
.docked {
  position: absolute; left: 0; bottom: 100%; margin-bottom: 6px;
  display: block; white-space: nowrap; pointer-events: none;
  opacity: 0; transform-origin: 0 100%;
}
.docked b {
  display: inline-block; padding: 0.14em 0.62em 0.2em; border-radius: var(--r-pill);
  background: var(--red); color: #fff;
  box-shadow: var(--shadow-s);
  font-size: clamp(15px, 1.5vmin + 9px, 26px); line-height: 1.1; letter-spacing: 0.04em; text-shadow: none;
}
.docked.is-on { animation: lb-docked 2.4s ease both; }
@keyframes lb-docked {
  0% { opacity: 0; transform: scale(1.6) rotate(-4deg); }
  8% { opacity: 1; transform: scale(0.96) rotate(-4deg); }
  12%, 82% { opacity: 1; transform: rotate(-4deg); }
  100% { opacity: 0; transform: translateY(14px) rotate(-4deg); }
}
.score.is-dock { color: #ff8f86; animation: lb-dock-score 0.5s ease; }
@keyframes lb-dock-score {
  0%, 100% { transform: none; }
  20% { transform: translateX(-5px); }
  40% { transform: translateX(5px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(3px); }
}

/* The middle of the dock has a fixed width (room for "+9,999"), so the strike dots and the
   columns beside it never move by a pixel as the pot's digits change; a longer number
   overhangs evenly on both sides. */
.stat-pot {
  --pot: clamp(32px, 4.6vmin + 14px, 66px);
  position: relative; display: flex; flex-direction: column; align-items: center; gap: clamp(2px, 0.6vmin, 6px);
  width: calc(var(--pot) * 3.2);
}
/* The pending pot. .pot-box swells as it grows (js/ui.js sets transform: scale); .pot-in
   throbs while the pay is hot; .pot-hot is the same number in the hot colour, faded in by js. */
.pot-box { position: relative; display: block; transform-origin: 50% 100%; transition: transform 0.12s ease-out; }
.pot-in { position: relative; display: block; }
.pot-box.is-hot .pot-in { animation: lb-throb 0.26s ease-in-out infinite alternate; }
@keyframes lb-throb { from { transform: scale(1); } to { transform: scale(1.07) rotate(-1.2deg); } }
.pot {
  display: block;
  color: var(--gold);
  font-size: var(--pot); font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; white-space: nowrap;
  text-shadow: 0 2px 0 rgba(110, 62, 0, 0.6), 0 0 14px rgba(0, 0, 0, 0.45);
}
.pot.is-zero { color: rgba(255, 255, 255, 0.6); text-shadow: var(--hud-shadow); }
.pot-hot {
  position: absolute; left: 0; top: 0;
  color: var(--hot); text-shadow: 0 2px 0 rgba(120, 30, 0, 0.65), 0 0 16px rgba(255, 90, 20, 0.5);
  opacity: 0; transition: opacity 0.2s ease;
}
/* What the local player's activity pays right now, as a chip at the pot's shoulder */
.mult {
  position: absolute; left: 100%; top: 0; margin-left: 0.3em;
  padding: 0.12em 0.5em 0.18em; border-radius: var(--r-pill);
  background: var(--hot); color: #fff;
  box-shadow: var(--shadow-s);
  font-size: clamp(12px, 1vmin + 7px, 18px); font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums;
  white-space: nowrap; text-shadow: none;
  opacity: 0; transform: scale(0.6); transform-origin: 0 50%;
  transition: opacity var(--t) ease, transform var(--t) var(--pop);
}
.mult.is-on { opacity: 1; transform: none; }

/* Just above the pot: "😅 +75" (a close call), "🔥 ×3" (a streak) */
.callout {
  position: absolute; left: 50%; bottom: 100%; margin-bottom: clamp(20px, 5vmin, 52px);
  color: var(--mint); font-size: clamp(20px, 2.6vmin + 10px, 44px); font-weight: 700; line-height: 1; letter-spacing: 0.02em;
  white-space: nowrap; text-shadow: 0 2px 0 rgba(0, 62, 52, 0.75), 0 0 14px rgba(0, 0, 0, 0.5);
  opacity: 0; pointer-events: none; transform: translateX(-50%);
}
.callout[data-kind="streak"] { color: var(--gold); font-size: clamp(17px, 2vmin + 9px, 34px); text-shadow: 0 2px 0 rgba(110, 62, 0, 0.6), 0 0 14px rgba(0, 0, 0, 0.45); }
.callout.is-on { animation: lb-callout 1.5s ease both; }
@keyframes lb-callout {
  0% { opacity: 0; transform: translateX(-50%) scale(0.4) rotate(-6deg); }
  12% { opacity: 1; transform: translateX(-50%) scale(1.2) rotate(-3deg); }
  20%, 75% { opacity: 1; transform: translateX(-50%) scale(1) rotate(-3deg); }
  100% { opacity: 0; transform: translateX(-50%) translateY(-24px) rotate(-3deg); }
}
/* High five, above the pot. A prompt while a coworker is in reach ([C] ✋ Greg), then a ring
   that closes on the target circle for the clap, then how it went: ✋ +2,625, a red hand with
   the docked amount, or a crossed-out hand. It is a button: on a touch screen it is what you
   tap. js/ui.js sets data-state (hint | go | ok | fail), data-why (fumble | miss), the ring's
   scale every frame and --w, the width of the band that counts. */
.five {
  --d: clamp(54px, 9vmin, 84px);
  position: absolute; left: 50%; bottom: 100%; z-index: 4; margin-bottom: clamp(20px, 5vmin, 52px);       /* clear of the pot, which swells upward */
  display: flex; flex-direction: column; align-items: center; gap: calc(var(--d) * 0.42);
  padding: 0; border: 0; background: none; color: #fff;
  text-shadow: var(--hud-shadow); white-space: nowrap;
  cursor: pointer; pointer-events: none; touch-action: none;
  -webkit-user-select: none; user-select: none;
  opacity: 0; visibility: hidden; transform: translateX(-50%) scale(0.9);
  transition: opacity var(--t) ease, transform var(--t) var(--pop), visibility 0s linear var(--t);
}
.five[data-state] {
  opacity: 1; visibility: visible; transform: translateX(-50%);
  transition: opacity var(--t) ease, transform var(--t) var(--pop), visibility 0s;
}
.five[data-state="hint"], .five[data-state="go"] { pointer-events: auto; }
#ui .five.is-press { transform: translateX(-50%) scale(0.94); }
.five-text { display: flex; align-items: center; gap: 8px; }
.five-text b { font-size: clamp(17px, 2vmin + 10px, 34px); line-height: 1; letter-spacing: 0.02em; font-variant-numeric: tabular-nums; }
.five-text b:empty { display: none; }
.five-ico { position: relative; z-index: 0; display: block; font-size: clamp(22px, 2.4vmin + 12px, 40px); line-height: 1; text-shadow: none; }
/* The prompt: a pill with the key (none on touch screens: the pill is what you tap) */
.five[data-state="hint"] .five-text {
  min-height: 40px; padding: 4px 16px 5px 8px;
  border: 2px solid #fff; border-radius: var(--r-pill);
  background: var(--glass); box-shadow: 0 3px 0 rgba(0, 0, 0, 0.4); text-shadow: none;
}
.five[data-state="hint"] .five-text b { font-size: clamp(14px, 1vmin + 9px, 19px); }
.five[data-state="hint"] .five-ico { font-size: clamp(18px, 1.2vmin + 11px, 24px); }
/* The ring, and under it the key and who it is with */
.five-box { --w: 0.308; position: relative; display: none; width: var(--d); height: var(--d); margin-top: calc(var(--d) * 0.42); }
.five[data-state="go"] .five-box { display: block; }
.five[data-state="go"] .five-ico { display: none; }                  /* the hand is in the ring */
.five[data-state="go"] .five-text b { font-size: clamp(13px, 1vmin + 8px, 18px); font-weight: 600; }
.five-band, .five-target, .five-ring { position: absolute; border-radius: 50%; }
.five-band { inset: calc(var(--d) * var(--w) * -0.5); border: calc(var(--d) * var(--w)) solid rgba(255, 255, 255, 0.24); }
.five-target { inset: 0; border: 3px solid #fff; background: rgba(16, 21, 32, 0.45); box-shadow: 0 0 0 1.5px rgba(8, 12, 22, 0.5); }
.five-ring { inset: 0; border: 4px solid var(--gold); box-shadow: 0 0 10px rgba(255, 200, 60, 0.85); transform: scale(2.4); will-change: transform; }
.five-hand { position: absolute; inset: 0; display: grid; place-items: center; font-size: calc(var(--d) * 0.5); line-height: 1; text-shadow: none; }
.five.is-now .five-band { border-color: rgba(125, 255, 207, 0.62); }
.five.is-clapped .five-ring { border-color: var(--mint); box-shadow: 0 0 12px var(--mint); }
.five.is-clapped .five-hand { animation: lb-clap 0.3s var(--pop); }
.five.is-clapped .five-key { visibility: hidden; }                    /* clapped: nothing left to press */
@keyframes lb-clap { 0% { transform: scale(1); } 40% { transform: scale(1.5) rotate(-12deg); } 100% { transform: scale(1); } }
/* How it went */
.five[data-state="ok"] .five-key, .five[data-state="fail"] .five-key { display: none; }
.five[data-state="ok"] .five-text, .five[data-state="fail"] .five-text { animation: lb-five-res 0.36s var(--pop); }
@keyframes lb-five-res { 0% { opacity: 0; transform: scale(0.5) rotate(-5deg); } 100% { opacity: 1; transform: none; } }
.five[data-state="ok"] .five-text b { color: var(--mint); text-shadow: 0 2px 0 rgba(0, 62, 52, 0.75), 0 0 14px rgba(0, 0, 0, 0.5); }
.five[data-state="fail"] .five-text b { color: #ff9a92; text-shadow: 0 2px 0 rgba(90, 10, 5, 0.75), 0 0 14px rgba(0, 0, 0, 0.5); }
.five[data-state="fail"] .five-ico::before {                          /* the hand on a disc: red when you were off the beat */
  content: ""; position: absolute; inset: -0.2em; z-index: -1; border-radius: 50%;
  background: var(--glass); box-shadow: 0 0 0 2px #fff;
}
.five[data-state="fail"][data-why="fumble"] .five-ico::before { background: var(--red); }
.five[data-state="fail"][data-why="miss"] .five-ico::after {          /* left hanging, or no clap: crossed out */
  content: "✕"; position: absolute; inset: 0; display: grid; place-items: center;
  color: var(--red); font-size: 1.3em; font-weight: 700; text-shadow: 0 0 2px #fff, 0 0 2px #fff;
}
#ui.has-touch .five-key { display: none; }
#ui.has-touch .five[data-state="hint"] .five-text { min-height: 52px; padding: 4px 20px 5px 14px; }
@media (pointer: coarse) {
  .five-key { display: none; }
  .five[data-state="hint"] .five-text { min-height: 52px; padding: 4px 20px 5px 14px; }
}

/* The local player's three strike slots */
.strikes { position: relative; display: flex; align-items: center; gap: 5px; }
/* ... and since v3 a slot for the yellow card: one warning. The second one is a strike. */
.warn-slot {
  position: relative; display: none; flex: none;
  width: clamp(10px, 1vmin + 5px, 15px); height: clamp(14px, 1.4vmin + 7px, 22px); margin-left: 3px;
  border: 2px dashed rgba(255, 255, 255, 0.8); border-radius: 3px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}
#ui.has-warn .warn-slot { display: block; }
.warn-slot::after {
  content: ""; position: absolute; inset: -2px; border-radius: 3px;
  background: var(--card-yellow); box-shadow: inset 0 0 0 1.5px rgba(120, 80, 0, 0.4), 0 1px 4px rgba(0, 0, 0, 0.4);
  opacity: 0; transform: scale(0.4); transition: opacity var(--t) ease, transform var(--t) var(--pop);
}
.warn-slot.is-on::after { opacity: 1; transform: rotate(9deg); }
.strikes i {
  position: relative; display: block;
  width: clamp(14px, 1.4vmin + 7px, 22px); height: clamp(14px, 1.4vmin + 7px, 22px);
  border: 2px solid #fff; border-radius: 50%;
  background: rgba(12, 16, 26, 0.4);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}
.strikes i.on { background: var(--red); animation: lb-pip 0.3s var(--pop); }
@keyframes lb-pip { from { transform: scale(1.7); } to { transform: scale(1); } }
.strikes i.on::before, .strikes i.on::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 62%; height: 2px; margin: -1px 0 0 -31%; border-radius: 2px;
  background: #fff; transform: rotate(45deg);
}
.strikes i.on::after { transform: rotate(-45deg); }
/* Last strike: the one dot that is left goes red at the rim and breathes */
#ui.is-laststrike .strikes i:not(.on) { border-color: var(--red); animation: lb-breathe 0.7s ease-in-out infinite alternate; }

/* Call the boss: a megaphone, the E key and how many are left */
.snitch {
  justify-self: end;
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 44px; padding: 5px 14px 6px 9px;
  border: 2px solid #fff; border-radius: 999px;
  background: var(--glass); color: #fff;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.4);
  font-weight: 700; font-size: clamp(13px, 0.9vmin + 8px, 17px); line-height: 1; letter-spacing: 0.04em;
  text-shadow: none; white-space: nowrap;
  cursor: pointer; pointer-events: auto; touch-action: manipulation;
  transition: transform 0.08s ease, opacity var(--t) ease;
}
.snitch:hover { background: rgba(44, 54, 76, 0.82); }
.snitch:active { transform: translateY(2px); box-shadow: 0 1px 0 rgba(0, 0, 0, 0.4); }
.snitch:disabled { opacity: 0.42; cursor: not-allowed; transform: none; box-shadow: 0 3px 0 rgba(0, 0, 0, 0.4); }
.snitch-left { font-weight: 600; font-variant-numeric: tabular-nums; opacity: 0.9; }

/* ---------------------------------------------------------------- activity cards */

.cards { --gap: clamp(6px, 1.2vmin, 12px); position: relative; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--gap); }
/* A card is an icon, a key cap and what it pays (v4: no words); a thin bar under them shows
   how slowly it is put away. It never changes size or reflows during play: every state is a
   layer that fades (the ring, the red tint, the strips along its top and bottom edges) or a
   transform. */
.card {
  --ac: #fff;
  --strip: 14px;                       /* room kept at the top for the hot / company strip */
  position: relative; min-width: 0;
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center;
  column-gap: clamp(6px, 1vmin, 12px); row-gap: clamp(4px, 0.7vmin, 7px);
  padding: calc(var(--strip) + 4px) clamp(8px, 1.4vmin, 14px) clamp(9px, 1.4vmin, 13px);
  border: 2px solid var(--glass-line); border-radius: var(--r-l);
  background: var(--glass); color: #fff;
  box-shadow: 0 4px 0 rgba(0, 0, 0, 0.35);
  text-align: left;
  cursor: pointer; pointer-events: auto;
  touch-action: none;
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
  transition: transform 0.07s ease, opacity var(--t) ease;
}
.card[data-action="scroll"] { --ac: #5cc8ff; }
.card[data-action="game"] { --ac: #c59bff; }
.card[data-action="nap"] { --ac: #7fe7c4; }
.card[data-action="skive"] { --ac: #ff9ecf; }

/* Rings. Each state has its own layer in its own colour and only its opacity moves, so a
   ring never changes colour while it fades: the card's colour while it is the active one
   (::after), amber while it is being hidden (::before), orange while it is hot and red
   while the boss looks (two layers inside .card-clip). */
.card::before, .card::after {
  content: ""; position: absolute; inset: -2px; border-radius: inherit;
  opacity: 0; transition: opacity var(--t) ease; pointer-events: none;
}
.card::after { border: 2px solid var(--ac); box-shadow: 0 0 22px -2px var(--ac), inset 0 0 30px -8px var(--ac); }
.card::before { border: 2px solid var(--amber); box-shadow: 0 0 16px -4px var(--amber); }
.card:hover::after { opacity: 0.35; }
.card.is-active::after { opacity: 1; }
.card.is-hiding::before { opacity: 1; }

/* Layers clipped to the rounded corners (the clip covers the border too) */
.card-clip { position: absolute; inset: -2px; border-radius: inherit; overflow: hidden; pointer-events: none; }
.card-tint, .card-hotring { position: absolute; inset: 0; border-radius: inherit; opacity: 0; transition: opacity var(--t) ease; }
.card-tint { background: rgba(150, 18, 10, 0.6); box-shadow: inset 0 0 0 2px var(--red), inset 0 0 26px -6px var(--red); }
.card-hotring { box-shadow: inset 0 0 0 2px var(--hot), inset 0 0 26px -6px var(--hot); }
#ui.is-look .card-tint { opacity: 1; }
.card.is-hot .card-hotring { opacity: 1; }
/* Top edge: a flame with a bar that drains as the hot window runs out, or 👥 for company */
.card-hot { position: absolute; left: 0; right: 0; top: 0; height: var(--strip); background: rgba(0, 0, 0, 0.35); opacity: 0; transition: opacity var(--t) ease; }
.card-hot i { position: absolute; inset: 0; background: linear-gradient(90deg, #ffb020, var(--hot)); transform-origin: 0 50%; }
.card-hot b { position: relative; display: block; font-size: 10px; font-weight: 400; line-height: var(--strip); text-align: center; white-space: nowrap; }
.card.is-hot .card-hot, .card.is-gossip .card-hot { opacity: 1; }
.card.is-gossip:not(.is-hot) .card-hot i { background: #d9569f; }
/* Bottom edge: drains while this activity is being hidden */
.card-drain { position: absolute; left: 0; right: 0; bottom: 0; height: 6px; background: rgba(0, 0, 0, 0.4); opacity: 0; transition: opacity var(--t) ease; }
.card-drain i { position: absolute; inset: 0; background: var(--amber); transform-origin: 0 50%; }
.card.is-hiding .card-drain { opacity: 1; }

.card-ico { position: relative; font-size: clamp(26px, 2.4vmin + 14px, 42px); line-height: 1; }
.card > .key { position: relative; grid-column: 3; grid-row: 1; }
/* "+12": what it pays a second right now. Room for "+1,250" (zone multipliers reach ×25). */
.card-rate { position: relative; grid-column: 2; grid-row: 1; min-width: 0; color: var(--gold); font-weight: 700; font-size: clamp(17px, 1.4vmin + 10px, 27px); line-height: 1; font-variant-numeric: tabular-nums; white-space: nowrap; transition: opacity var(--t) ease; }
.card.is-nopay .card-rate { opacity: 0; }             /* on foot inside the safe circle: nothing is earned, nothing is shown */
/* "×3.1", "×25": what the activity pays right now when that is more than ×1, as a tag on
   the card's top right corner (outside the row, so a long number never pushes anything) */
.card-mult {
  position: absolute; right: -5px; top: -9px; z-index: 1;
  padding: 0.08em 0.5em 0.14em; border-radius: var(--r-pill);
  background: #fff; color: var(--ink);
  box-shadow: var(--shadow-s);
  font-size: clamp(12px, 0.8vmin + 8px, 16.5px); font-weight: 700; line-height: 1.2; font-variant-numeric: tabular-nums;
  opacity: 0; transform: scale(0.6); transform-origin: 100% 100%;
  transition: opacity var(--t) ease, transform var(--t) var(--pop);
}
.card-mult.is-on { opacity: 1; transform: none; }
.card-mult[data-h="1"] { background: var(--amber); color: #3a2500; }
.card-mult[data-h="2"] { background: var(--hot); color: #fff; }
/* Hide time as a bar: longer = slower to put away (the walk panel: how far the dash home is) */
.card-bar { position: relative; grid-column: 1 / -1; height: 4px; border-radius: 2px; background: rgba(255, 255, 255, 0.2); overflow: hidden; }
.card-bar i { position: absolute; inset: 0; border-radius: inherit; background: var(--amber); transform-origin: 0 50%; transform: scaleX(0); }

.card.is-held, .card.is-active { transform: translateY(3px); }
.card.is-active .card-ico { animation: lb-wiggle 0.36s ease-in-out infinite alternate; }
@keyframes lb-wiggle { from { transform: rotate(-9deg) scale(1.08); } to { transform: rotate(9deg) scale(1.08); } }

/* Stunned or fired: the cards look switched off (they still report presses) */
#ui.is-stun .card, #ui.is-fired .card { opacity: 0.42; cursor: not-allowed; }
#ui.is-stun .card-ico, #ui.is-fired .card-ico { filter: grayscale(1); }

/* Walking. Not pressed like the others: it shows what being out of your chair pays right
   now, and its bar how far the dash home is. */
.card-walk { cursor: default; pointer-events: none; }
.card-walk.is-active { transform: none; }
#ui.has-touch .walk-keys { display: none; }            /* the stick walks there */
@media (pointer: coarse) { .walk-keys { display: none; } }
/* Out of your chair: the desk activities are out of reach */
#ui.is-away .card:not(.card-walk) { opacity: 0.42; cursor: not-allowed; }
#ui.is-away .card:not(.card-walk) .card-ico { filter: grayscale(1); }

/* The dash pill (v4). Out of your chair AND outside the safe circle: [Space] ↩ 1.2, the
   seconds a dash takes to get you safe. It lies over the desk cards, which are out of reach
   then. It is a button: on a touch screen (no key cap, bigger) it is how you dash. */
.desk-btn {
  position: absolute; left: 37.5%; top: 50%; z-index: 3;
  display: flex; align-items: center; justify-content: center; gap: 0.45em;
  min-height: 44px; padding: 4px 1em 5px 0.7em;
  border: 0; border-radius: var(--r-pill);
  background: var(--amber); color: #2b1a00;
  box-shadow: 0 4px 0 rgba(90, 55, 0, 0.6), var(--shadow-m);
  font-weight: 700; font-size: clamp(17px, 1.6vmin + 10px, 28px); line-height: 1; white-space: nowrap;
  cursor: pointer; pointer-events: none; touch-action: none;
  -webkit-user-select: none; user-select: none;
  opacity: 0; visibility: hidden; transform: translate(-50%, -50%) scale(0.8);
  transition: opacity var(--t) ease, transform var(--t) var(--pop), visibility 0s linear var(--t);
}
#ui .desk-btn .key { border-color: #2b1a00; background: rgba(43, 26, 0, 0.1); color: #2b1a00; font-size: 0.62em; }
.desk-arrow { font-size: 1.15em; line-height: 0.9; }
.desk-time { min-width: 1.9em; font-variant-numeric: tabular-nums; text-align: left; }
#ui.is-unsafe .desk-btn {
  opacity: 1; visibility: visible; pointer-events: auto; transform: translate(-50%, -50%);
  transition: opacity var(--t) ease, transform var(--t) var(--pop), visibility 0s;
}
#ui.has-touch .desk-btn { min-width: min(40%, 230px); min-height: clamp(50px, 10vmin, 72px); font-size: clamp(20px, 3vmin + 8px, 32px); box-shadow: 0 6px 0 rgba(90, 55, 0, 0.6), var(--shadow-m); }
#ui.has-touch .desk-btn .key { display: none; }
@media (pointer: coarse) {
  .desk-btn { min-width: min(40%, 230px); min-height: clamp(50px, 10vmin, 72px); font-size: clamp(20px, 3vmin + 8px, 32px); box-shadow: 0 6px 0 rgba(90, 55, 0, 0.6), var(--shadow-m); }
  #ui .desk-btn .key { display: none; }
}
#ui.is-unsafe.is-look .desk-btn, #ui.is-unsafe.is-stun .desk-btn, #ui.is-unsafe.is-fired .desk-btn {
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity var(--t) ease, visibility 0s linear var(--t);
}
#ui .desk-btn.is-press { transform: translate(-50%, -50%) translateY(4px) scale(0.97); box-shadow: 0 1px 0 rgba(90, 55, 0, 0.6); }

/* The strip across the cards while the boss is looking at a player at their desk: the
   Space key cap, one segment per tap and how many more taps it takes, then a tick. No words. */
.cards-warn {
  position: absolute; left: 0; right: 0; top: 50%; z-index: 2;
  display: flex; align-items: center; justify-content: center; gap: 0.7em;
  min-height: 2em; padding: 0.3em 0.7em 0.36em; border-radius: var(--r-s);
  background: var(--red); color: #fff;
  box-shadow: var(--shadow-m);
  font-weight: 700; font-size: clamp(14px, 1.6vmin + 8px, 26px); line-height: 1.1; text-align: center;
  white-space: nowrap; pointer-events: none;
  opacity: 0; transform: translateY(-50%) scale(0.92);
  transition: opacity var(--t) ease, transform var(--t) var(--pop);
}
#ui.is-busy .cards-warn { opacity: 1; transform: translateY(-50%) rotate(-1.5deg); }
#ui.is-stun .cards-warn, #ui.is-fired .cards-warn { opacity: 0; }
.busy-key { flex: none; font-size: 0.6em; }
#ui.has-touch .busy-key { display: none; }             /* the keyboard button under the strip does it */
@media (pointer: coarse) { .busy-key { display: none; } }
.busy-bar { --seg: clamp(9px, 1.2vmin + 4px, 20px); position: relative; display: flex; gap: 3px; align-items: center; }
.busy-bar i {
  display: block; width: var(--seg); height: 0.62em; border-radius: 3px;
  background: #fff; opacity: 0.3; transform: scaleY(0.6);
  transition: opacity 0.1s ease, transform 0.12s var(--pop);
}
.busy-bar i.on { opacity: 1; transform: none; }
/* A look asks for a minimum (js/ui.js sets --need on the bar). The segments up to the
   marker are the ones needed (tall); the ones after it are a bonus (short, gold when lit). */
.busy-bar i.need { height: 0.8em; }
.busy-bar i.bonus { height: 0.46em; }
.busy-bar i.bonus.on { background: var(--gold); }
.busy-bar i.edge { margin-right: 8px; }
.cards-warn.has-need .busy-bar::after {
  content: ""; position: absolute; left: calc(var(--need, 0) * (var(--seg) + 3px) + 1.5px); top: -0.22em; bottom: -0.22em;
  width: 2px; border-radius: 1px; background: #fff;
}
/* How many more taps: a number, then a tick */
.busy-left {
  display: none; flex: none; min-width: 1.9em; padding: 0.1em 0.4em 0.16em; border-radius: var(--r-pill);
  background: #fff; color: var(--red-deep);
  font-size: 0.8em; font-variant-numeric: tabular-nums; text-align: center;
}
.cards-warn.has-need .busy-left { display: block; }
.cards-warn.is-enough .busy-left { background: var(--mint); color: #064d3c; }
.cards-warn.is-full { animation: lb-full 0.5s ease; }
@keyframes lb-full {
  0% { transform: translateY(-50%) rotate(-1.5deg) scale(1); }
  30% { transform: translateY(-50%) rotate(-1.5deg) scale(1.08); }
  100% { transform: translateY(-50%) rotate(-1.5deg) scale(1); }
}
.cards-warn.is-full .busy-bar i { background: var(--gold); }
/* "+3" for every tap */
.busy-pop {
  position: absolute; left: 50%; bottom: 100%;
  color: var(--gold); font-size: 0.95em; letter-spacing: 0; text-shadow: var(--hud-shadow);
  opacity: 0;
}
.busy-pop.is-on { animation: lb-busy-pop 0.6s ease-out both; }
@keyframes lb-busy-pop {
  0% { opacity: 0; transform: translate(var(--x, 0px), 6px) scale(0.6); }
  20% { opacity: 1; transform: translate(var(--x, 0px), -4px) scale(1.15); }
  100% { opacity: 0; transform: translate(var(--x, 0px), -34px) scale(1); }
}

/* Touch: a keyboard button at the right end of the strip does what Space does (the strip
   makes room for it). Shown for coarse pointers and for anyone who has touched the screen
   (#ui.has-touch). */
.type-btn {
  position: absolute; right: 0; top: 50%; z-index: 3;
  display: flex; align-items: center; justify-content: center;
  width: 32%; min-height: clamp(54px, 11vmin, 84px); padding: 0;
  border: 0; border-radius: var(--r-pill);
  background: #fff; color: var(--red-deep);
  box-shadow: 0 6px 0 rgba(90, 10, 5, 0.55), var(--shadow-m);
  font-size: clamp(26px, 4vmin + 10px, 42px); line-height: 1;
  cursor: pointer; pointer-events: none; touch-action: none;
  -webkit-user-select: none; user-select: none;
  opacity: 0; visibility: hidden; transform: translateY(-50%) scale(0.8);
  transition: opacity var(--t) ease, transform var(--t) var(--pop), visibility 0s linear var(--t);
}
#ui.has-touch.is-busy .type-btn {
  opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(-50%);
  transition: opacity var(--t) ease, transform var(--t) var(--pop), visibility 0s;
}
#ui.has-touch .cards-warn { right: calc(32% + 10px); }
@media (pointer: coarse) {
  #ui.is-busy .type-btn {
    opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(-50%);
    transition: opacity var(--t) ease, transform var(--t) var(--pop), visibility 0s;
  }
  .cards-warn { right: calc(32% + 10px); }
}
#ui .type-btn.is-press { transform: translateY(-50%) translateY(5px) scale(0.97); box-shadow: 0 1px 0 rgba(90, 10, 5, 0.55); }

/* Spectating (view.me is null): no personal HUD */
#ui.is-spectating .dock { display: none; }

/* ---------------------------------------------------------------- big event feedback */

/* "BUSTED!" and nothing else */
.stamp {
  position: absolute; left: 50%; top: 42%;
  padding: 0.16em 0.5em 0.2em;
  border: 0.09em solid var(--red); border-radius: 0.22em;
  background: rgba(255, 255, 255, 0.94); color: var(--red);
  box-shadow: var(--shadow-l);
  font-weight: 700; font-size: clamp(30px, 6vmin + 10px, 92px); line-height: 1; letter-spacing: 0.03em;
  text-align: center; white-space: nowrap;
  pointer-events: none;
  opacity: 0; visibility: hidden;
  transform: translate(-50%, -50%) rotate(-7deg);
}
.stamp.is-on { visibility: visible; animation: lb-stamp 1.9s ease both; }
@keyframes lb-stamp {
  0% { opacity: 0; transform: translate(-50%, -50%) rotate(-7deg) scale(2.4); }
  8% { opacity: 1; transform: translate(-50%, -50%) rotate(-7deg) scale(0.93); }
  13%, 82% { opacity: 1; transform: translate(-50%, -50%) rotate(-7deg) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -58%) rotate(-7deg) scale(1); }
}

/* A yellow card: not busy enough while he watched. A card and "1/3" */
.warncard {
  position: absolute; left: 50%; top: 36%;
  display: flex; align-items: center; gap: 0.7em;
  padding: 0.5em 1em 0.55em 0.8em; border-radius: var(--r-m);
  background: var(--card-yellow); color: #2b1a00;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.92), var(--shadow-l);
  font-size: clamp(15px, 1.8vmin + 9px, 30px); line-height: 1.1; text-align: left; white-space: nowrap;
  pointer-events: none;
  opacity: 0; visibility: hidden;
  transform: translate(-50%, -50%) rotate(-3deg);
}
.warncard b { display: block; font-size: 2em; letter-spacing: 0.04em; font-variant-numeric: tabular-nums; }
.ycard {
  flex: none; display: block; width: 1.5em; height: 2.1em; border-radius: 0.2em;
  background: #fff3a6; box-shadow: inset 0 0 0 0.14em #2b1a00;
  transform: rotate(-10deg);
}
.warncard.is-on { visibility: visible; animation: lb-warncard 2.2s ease both; }
@keyframes lb-warncard {
  0% { opacity: 0; transform: translate(-50%, -50%) rotate(-3deg) scale(1.9); }
  8% { opacity: 1; transform: translate(-50%, -50%) rotate(-3deg) scale(0.94); }
  13%, 84% { opacity: 1; transform: translate(-50%, -50%) rotate(-3deg) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -58%) rotate(-3deg) scale(1); }
}

/* "FIRED!": the stamp slams in, then shrinks and drops out of the way so the rest of the
   day can be watched. */
.fired {
  position: absolute; left: 50%; top: 42%;
  display: none; flex-direction: column; align-items: center; gap: 0.4em;
  text-align: center; pointer-events: none;
  transform: translate(-50%, -50%) translateY(13vh);                     /* where it rests */
}
#ui.is-fired .fired { display: flex; animation: lb-fired-move 3.2s ease both; }
.fired b {
  display: block; padding: 0.1em 0.45em 0.15em;
  border: 0.09em solid var(--red); border-radius: 0.2em;
  background: rgba(255, 255, 255, 0.95); color: var(--red);
  box-shadow: var(--shadow-l);
  font-size: clamp(34px, 8vmin + 8px, 118px); font-weight: 700; line-height: 1; letter-spacing: 0.03em; white-space: nowrap;
  transform-origin: 50% 100%;
  transform: rotate(-5deg) scale(0.5);                                   /* its resting size */
}
#ui.is-fired .fired b { animation: lb-fired-stamp 3.2s ease both; }
@keyframes lb-fired-move {
  0%, 72% { transform: translate(-50%, -50%); }
  100% { transform: translate(-50%, -50%) translateY(13vh); }
}
@keyframes lb-fired-stamp {
  0% { opacity: 0; transform: rotate(-5deg) scale(2.2); }
  7% { opacity: 1; transform: rotate(-5deg) scale(0.95); }
  11%, 72% { opacity: 1; transform: rotate(-5deg) scale(1); }
  100% { opacity: 1; transform: rotate(-5deg) scale(0.5); }
}

/* "+123" flying from the pot to the score. js/ui.js sets --x0/--y0/--x1/--y1 (px). */
.fly {
  position: absolute; left: 0; top: 0;
  color: var(--gold); font-weight: 700; font-size: clamp(16px, 1.6vmin + 10px, 30px); white-space: nowrap;
  text-shadow: var(--hud-shadow); pointer-events: none;
  opacity: 0;
}
.fly.is-on { animation: lb-fly 0.8s cubic-bezier(0.5, 0, 0.6, 1) both; }
@keyframes lb-fly {
  0% { opacity: 0; transform: translate(var(--x0, 0px), var(--y0, 0px)) translate(-50%, -50%) scale(1.3); }
  14%, 70% { opacity: 1; }
  30% { transform: translate(var(--x0, 0px), var(--y0, 0px)) translate(-50%, -80%) scale(1.15); }
  100% { opacity: 0; transform: translate(var(--x1, 0px), var(--y1, 0px)) translate(-50%, -50%) scale(0.6); }
}

/* A quick screen flash with the tell */
.flash { position: absolute; inset: 0; background: #fff; opacity: 0; pointer-events: none; }
.flash.is-on { animation: lb-flash 0.22s ease-out both; }
@keyframes lb-flash { 0% { opacity: 0.32; } 100% { opacity: 0; } }

/* Shake when the local player is caught */
.hud.is-shake { animation: lb-shake 0.4s ease; }
@keyframes lb-shake {
  0%, 100% { transform: translate(0, 0); }
  15% { transform: translate(-9px, 3px); }
  30% { transform: translate(8px, -4px); }
  45% { transform: translate(-6px, -2px); }
  60% { transform: translate(5px, 3px); }
  80% { transform: translate(-2px, -1px); }
}

/* ---------------------------------------------------------------- full-screen effects */

.fx { position: absolute; inset: 0; display: none; pointer-events: none; }
#ui[data-screen="game"] .fx { display: block; }

/* Boss is looking */
.fx-vignette {
  z-index: 2; opacity: 0; transition: opacity 0.18s ease;
  background: radial-gradient(ellipse at 50% 50%, rgba(255, 40, 30, 0) 50%, rgba(255, 40, 30, 0.26) 78%, rgba(215, 20, 10, 0.6) 100%);
  box-shadow: inset 0 0 0 clamp(4px, 0.9vmin, 9px) rgba(255, 59, 48, 0.92);
}
#ui.is-look .fx-vignette { opacity: 1; }

/* Last strike (one more and you are fired): a slow red pulse at the screen edges, much
   weaker than the look vignette. The layer fades in and out; the pulse is on its inside. */
.fx-last { z-index: 2; opacity: 0; transition: opacity 0.4s ease; }
.fx-last::before {
  content: ""; position: absolute; inset: 0;
  box-shadow: inset 0 0 clamp(36px, 9vmin, 110px) 0 rgba(255, 59, 48, 0.42);
  animation: lb-last 1.7s ease-in-out infinite alternate paused;
}
#ui.is-laststrike .fx-last { opacity: 1; }
#ui.is-laststrike .fx-last::before { animation-play-state: running; }
@keyframes lb-last { from { opacity: 0.25; } to { opacity: 1; } }

/* Nap blindness: two eyelids, about 93% opaque. They open faster than they close. */
.fx-lids { z-index: 3; overflow: hidden; }
.lid { position: absolute; left: 0; right: 0; height: 50%; background: rgba(6, 7, 12, 0.93); transition: transform 0.1s ease-out; will-change: transform; }
.lid-top { top: 0; transform: translateY(-101%); }
.lid-bot { top: 50%; transform: translateY(101%); }
#ui.is-blind .lid { transform: translateY(0); transition: transform 0.24s cubic-bezier(0.3, 0, 0.2, 1); }
.lid-text {
  position: absolute; left: 50%; top: 42%; transform: translate(-50%, -50%);
  color: #c9d3ff; font-weight: 600; font-size: clamp(17px, 2.2vmin + 10px, 38px); text-align: center; white-space: nowrap;
  opacity: 0; transition: opacity 0.08s ease;
}
.lid-text b { display: block; font-size: 1.7em; letter-spacing: 0.08em; }
#ui.is-blind .lid-text { opacity: 1; transition: opacity 0.2s ease 0.14s; }
#ui.is-blind .lid-text b { animation: lb-zzz 1.6s ease-in-out infinite alternate; }
@keyframes lb-zzz { from { transform: translateY(0.08em) rotate(-3deg); } to { transform: translateY(-0.08em) rotate(3deg); } }

/* A warning while napping: faint red glow at the screen edges (for players with sound off) */
.fx-glow { z-index: 4; opacity: 0; box-shadow: inset 0 0 clamp(50px, 14vmin, 170px) clamp(8px, 2.2vmin, 26px) rgba(255, 59, 48, 0.55); }
.fx-glow.is-on { animation: lb-glow 0.9s ease-out both; }
@keyframes lb-glow { 0% { opacity: 0; } 14% { opacity: 1; } 40% { opacity: 0.3; } 62% { opacity: 1; } 100% { opacity: 0; } }

/* ---------------------------------------------------------------- floating labels */

.labels { position: absolute; inset: 0; z-index: 1; display: none; overflow: hidden; pointer-events: none; }
#ui[data-screen="game"] .labels { display: block; }

/* .tag and .pop are zero-size points moved with transform: translate(x, y) only. */
.tag, .pop { position: absolute; left: 0; top: 0; width: 0; height: 0; }
.tag { will-change: transform; }
/* The inner part fades: a label never pops in or out. The name sits at the bottom, so the
   pot and the icons coming and going beside it do not move it sideways or up. */
.tag-in {
  position: absolute; left: 0; bottom: 3px; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  white-space: nowrap; text-shadow: var(--hud-shadow);
  opacity: 0; visibility: hidden;
  transition: opacity var(--t) ease, visibility 0s linear var(--t);
}
.tag.is-on .tag-in { opacity: 1; visibility: visible; transition: opacity var(--t) ease, visibility 0s; }
.tag-pot {
  color: var(--gold); font-weight: 700; font-size: clamp(13px, 0.9vmin + 8px, 19px); line-height: 1.05; font-variant-numeric: tabular-nums;
  opacity: 0; transform: scale(0.6); transform-origin: 50% 100%;
  transition: opacity var(--t) ease, transform var(--t) var(--pop);
}
.tag.has-pot .tag-pot { opacity: 1; transform: none; }
.tag-name { position: relative; display: block; font-weight: 600; font-size: clamp(11px, 0.7vmin + 7px, 15px); line-height: 1.2; }
/* The activity icon hangs off the left of the name and the streak flame off the right */
.tag-ico, .tag-streak {
  position: absolute; top: 50%; line-height: 1; text-shadow: none;
  opacity: 0; transition: opacity var(--t) ease, transform var(--t) var(--pop);
}
.tag-ico { right: 100%; margin-right: 4px; font-size: 1.15em; transform: translateY(-50%) scale(0.5); }
.tag-streak { left: 100%; margin-left: 4px; color: var(--gold); font-size: 0.95em; font-weight: 700; text-shadow: var(--hud-shadow); transform: translateY(-50%) scale(0.5); }
.tag.has-ico .tag-ico, .tag.has-streak .tag-streak { opacity: 1; transform: translateY(-50%); }
.tag.is-local .tag-name {
  padding: 1px 8px 2px; border-radius: 999px;
  background: #fff; color: var(--ink);
  box-shadow: var(--shadow-s);
  font-weight: 700; letter-spacing: 0.06em; text-shadow: none;
}
.tag.is-fired .tag-name { color: #ffb8b3; text-decoration: line-through; }
.tag.is-local.is-fired .tag-name { color: var(--red-deep); }

/* Popups at a player's anchor */
.pop-in {
  position: absolute; left: 0; bottom: 34px; transform: translateX(-50%);
  font-weight: 700; font-size: clamp(15px, 1.4vmin + 9px, 26px); line-height: 1.1; white-space: nowrap;
  text-shadow: var(--hud-shadow);
  animation: lb-pop-up 1.1s ease-out both;
}
.pop-bank .pop-in, .pop-bonus .pop-in { color: var(--gold); }
.pop-bonus .pop-in { bottom: 60px; }                 /* clear of a "+N" banked at the same moment */
.pop-caught .pop-in {                                 /* a white cross on red: a strike */
  padding: 0.05em 0.4em 0.1em; border-radius: 0.3em;
  background: var(--red); color: #fff; text-shadow: none;
  box-shadow: var(--shadow-s);
  animation-name: lb-pop-stamp;
}
.pop-snitch .pop-in {                                 /* a megaphone in a speech bubble */
  padding: 0.2em 0.6em 0.25em; border-radius: 1em;
  background: #fff; color: var(--ink); text-shadow: none;
  box-shadow: var(--shadow-s);
  font-size: clamp(16px, 1.2vmin + 10px, 24px);
  animation-name: lb-pop-bubble; animation-duration: 1.6s;
}
.pop-snitch .pop-in::after, .pop-chat .pop-in::after {
  content: ""; position: absolute; left: 50%; top: 100%; margin-left: -6px;
  border: 6px solid transparent; border-bottom: 0; border-top-color: #fff;
}
/* What a player says in the chat: the same bubble, for about four seconds, wrapping */
.pop-chat .pop-in {
  width: max-content; max-width: min(230px, 46vw);
  padding: 0.3em 0.75em 0.36em; border-radius: var(--r-m);
  background: #fff; color: var(--ink); text-shadow: none;
  box-shadow: var(--shadow-s);
  font-size: clamp(12.5px, 0.8vmin + 8px, 17px); font-weight: 600; line-height: 1.2;
  white-space: normal; overflow-wrap: anywhere; text-align: center;
  animation: lb-pop-chat 4.2s ease both;
}
/* A bubble held back from a screen edge keeps its tail on the speaker (js/ui.js sets --tail) */
.pop-chat .pop-in::after { margin-left: calc(var(--tail, 0px) - 6px); }
@keyframes lb-pop-chat {
  0% { opacity: 0; transform: translate(-50%, 6px) scale(0.5); }
  4% { opacity: 1; transform: translate(-50%, 0) scale(1.06); }
  7%, 93% { opacity: 1; transform: translate(-50%, 0) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -8px) scale(1); }
}
/* Other players, as icons: a close call 😅, a yellow card, docked pay "−480", a high five
   that landed 🙌 or did not (a crossed-out hand) */
.pop-close .pop-in, .pop-five .pop-in, .pop-hang .pop-in { font-size: clamp(18px, 1.4vmin + 11px, 28px); text-shadow: none; }
.pop-warn .pop-in::before {
  content: ""; display: block; width: 0.8em; height: 1.1em; border-radius: 0.14em;
  background: var(--card-yellow); box-shadow: 0 0 0 1.5px rgba(43, 26, 0, 0.65), 0 1px 3px rgba(0, 0, 0, 0.4);
  transform: rotate(-10deg);
}
.pop-dock .pop-in { bottom: 60px; color: #ff9a92; }      /* clear of the cross it comes with */
.pop-hang .pop-in::after {
  content: "✕"; position: absolute; inset: 0; display: grid; place-items: center;
  color: var(--red); font-size: 1.25em; font-weight: 700; text-shadow: 0 0 2px #fff, 0 0 2px #fff;
}
@keyframes lb-pop-up {
  0% { opacity: 0; transform: translate(-50%, 10px) scale(0.6); }
  14% { opacity: 1; transform: translate(-50%, 0) scale(1.18); }
  28% { opacity: 1; transform: translate(-50%, -6px) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -56px) scale(1); }
}
@keyframes lb-pop-stamp {
  0% { opacity: 0; transform: translate(-50%, 0) rotate(-6deg) scale(2); }
  12% { opacity: 1; transform: translate(-50%, 0) rotate(-6deg) scale(0.92); }
  20%, 80% { opacity: 1; transform: translate(-50%, 0) rotate(-6deg) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -10px) rotate(-6deg) scale(1); }
}
@keyframes lb-pop-bubble {
  0% { opacity: 0; transform: translate(-50%, 6px) scale(0.5); }
  10% { opacity: 1; transform: translate(-50%, 0) scale(1.1); }
  18%, 82% { opacity: 1; transform: translate(-50%, 0) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -8px) scale(1); }
}
/* Used when motion is reduced: no movement, just appear, hold, fade */
@keyframes lb-hold { 0% { opacity: 0; } 8%, 80% { opacity: 1; } 100% { opacity: 0; } }

/* ---------------------------------------------------------------- countdown */

.countdown { position: absolute; inset: 0; z-index: 6; display: none; align-items: center; justify-content: center; text-align: center; pointer-events: none; }
.countdown.is-on { display: flex; }
.count-num {
  color: #fff; font-weight: 700; font-size: clamp(120px, 44vmin, 440px); line-height: 1;
  text-shadow: 0 0.04em 0 rgba(20, 30, 50, 0.45), 0 0.08em 0.25em rgba(0, 0, 0, 0.4);
  animation: lb-count 0.95s cubic-bezier(0.2, 0.9, 0.3, 1) both;
}
.count-go { padding: 0 0.2em; color: var(--gold); font-size: clamp(44px, 15vmin, 190px); letter-spacing: 0.02em; white-space: nowrap; animation-name: lb-go; }
@keyframes lb-count {
  0% { opacity: 0; transform: scale(2.1); }
  22% { opacity: 1; transform: scale(1); }
  78% { opacity: 1; transform: scale(0.96); }
  100% { opacity: 0; transform: scale(0.8); }
}
@keyframes lb-go {
  0% { opacity: 0; transform: scale(0.4) rotate(-6deg); }
  20% { opacity: 1; transform: scale(1.15) rotate(-3deg); }
  32%, 74% { opacity: 1; transform: scale(1) rotate(-3deg); }
  100% { opacity: 0; transform: scale(1.5) rotate(-3deg); }
}

/* ---------------------------------------------------------------- chat */

/* Lobby, game and results. Bottom-left: in a game it sits just above the dock (js/ui.js
   keeps the dock's height in --dock-h), clear of the hero, the boss, the cards and the pantry. */
.chat {
  position: absolute; z-index: 8;
  left: calc(var(--edge) + var(--safe-l)); bottom: calc(var(--edge) + var(--safe-b));
  width: min(340px, calc(100% - 2 * var(--edge)));
  display: none; flex-direction: column; align-items: flex-start; gap: 6px;
  pointer-events: none;
}
#ui[data-screen="lobby"] .chat, #ui[data-screen="game"] .chat, #ui[data-screen="results"] .chat { display: flex; }
#ui[data-screen="game"] .chat { bottom: calc(var(--dock-h, 190px) + 2 * var(--edge) + var(--safe-b)); width: min(320px, 46%); }
/* With the touch stick in that corner (v3) the chat starts beside it */
#ui.has-touch[data-screen="game"] .chat {
  left: calc(var(--edge) + var(--safe-l) + var(--stick) + 10px);
  width: min(320px, 46%, calc(100% - var(--stick) - 3 * var(--edge) - 10px));
}
@media (pointer: coarse) {
  #ui[data-screen="game"] .chat {
    left: calc(var(--edge) + var(--safe-l) + var(--stick) + 10px);
    width: min(320px, 46%, calc(100% - var(--stick) - 3 * var(--edge) - 10px));
  }
}

/* The log: the last three lines at most, newest at the bottom. A line fades after about
   five seconds (.is-old) and comes back while the field is open. */
.chat-log { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; width: 100%; }
/* In a game the log has a fixed box between the missions (top-left) and its own button: lines
   stack up from the bottom edge, and whatever does not fit fades out at the top, so a busy
   chat never runs over the missions or the scoreboard. (On a phone those are hidden and the
   log is two short rows: see the end of this file.) */
@media (min-width: 701px) {
  #ui[data-screen="game"] .chat-log {
    justify-content: flex-end;
    height: max(56px, calc(100vh - var(--dock-h, 190px) - max(41vh, 262px) - 60px));
    overflow: hidden;
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 24px);
    mask-image: linear-gradient(to bottom, transparent, #000 24px);
  }
}
.chat-line {
  flex: none;
  max-width: 100%; padding: 3px 10px 4px; border-radius: 13px;
  background: rgba(16, 21, 32, 0.66); color: #fff;
  font-size: clamp(12.5px, 0.6vmin + 9px, 15px); font-weight: 500; line-height: 1.25;
  overflow-wrap: anywhere;
  transition: opacity 0.25s ease;
  animation: lb-chat-in var(--t) var(--ease);     /* no fill: a held last keyframe would beat .is-old below */
}
@keyframes lb-chat-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.chat-who { margin-right: 0.4em; color: var(--c, #fff); font-weight: 700; }
.chat-line.is-bot { background: rgba(16, 21, 32, 0.54); color: rgba(255, 255, 255, 0.84); font-weight: 400; }   /* AI coworkers: lighter */
.chat-line.is-bot .chat-who { font-weight: 600; }
.chat-line.is-old { opacity: 0; }
.chat.is-open .chat-line.is-old { opacity: 1; }
#ui .chat-line.is-gone { opacity: 0; }               /* pushed out by a newer line: fades, then is removed */

.chat-row { position: relative; width: 100%; min-height: 38px; }
.chat-btn {
  display: inline-flex; align-items: center; gap: 6px;
  height: 38px; padding: 0 12px 0 10px;
  border: 2px solid rgba(255, 255, 255, 0.9); border-radius: var(--r-pill);
  background: var(--glass); color: #fff;
  box-shadow: var(--shadow-s);
  font-weight: 600; font-size: 14px; line-height: 1; white-space: nowrap;
  cursor: pointer; pointer-events: auto; touch-action: manipulation;
  transition: opacity var(--t) ease, transform 0.08s ease, visibility 0s;
}
.chat-btn:hover { background: rgba(44, 54, 76, 0.85); }
.chat-btn:active { transform: translateY(2px); }
.chat-btn .key { border-color: #fff; background: rgba(255, 255, 255, 0.16); color: #fff; box-shadow: none; }
.chat-input {
  position: absolute; left: 0; top: 0; width: 100%; height: 38px; padding: 0 14px;
  border: 2px solid #fff; border-radius: var(--r-pill);
  background: rgba(16, 21, 32, 0.86); color: #fff;
  box-shadow: var(--shadow-m);
  font-weight: 500; font-size: 16px; line-height: 1.2;
  outline: none; pointer-events: none;
  -webkit-user-select: text; user-select: text;
  opacity: 0; visibility: hidden; transform: translateY(6px);
  transition: opacity var(--t) ease, transform var(--t) var(--ease), visibility 0s linear var(--t);
}
.chat-input::placeholder { color: rgba(255, 255, 255, 0.6); opacity: 1; }
#ui .chat-input:focus-visible { outline: none; border-color: var(--gold); }
.chat.is-open .chat-input {
  opacity: 1; visibility: visible; transform: none; pointer-events: auto;
  transition: opacity var(--t) ease, transform var(--t) var(--ease), visibility 0s;
}
.chat.is-open .chat-btn { opacity: 0; visibility: hidden; pointer-events: none; transition: opacity var(--t) ease, visibility 0s linear var(--t); }
/* In a game the button is small and quiet for a mouse (T does the same); bigger for touch. */
#ui[data-screen="game"] .chat-btn { opacity: 0.7; }
#ui[data-screen="game"] .chat-btn .key { display: none; }
#ui[data-screen="game"].has-touch .chat-btn { height: 44px; opacity: 0.95; }
@media (pointer: coarse) {
  #ui[data-screen="game"] .chat-btn { height: 44px; opacity: 0.95; }
  .chat-btn .key { display: none; }
}
#ui[data-screen="game"] .chat.is-open .chat-btn { opacity: 0; }

/* ---------------------------------------------------------------- toasts, sound toggle */

.toasts {
  position: absolute; z-index: 8; left: 50%; top: calc(var(--edge) + var(--safe-t));
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  width: max-content; max-width: calc(100% - 128px);
  pointer-events: none;
}
/* In a game the top centre is the HUD's, the left edge the scoreboard's and the chat's:
   toasts sit in the top-right corner, beside the sound button. */
#ui[data-screen="game"] .toasts {
  left: auto; right: calc(var(--edge) + var(--safe-r) + 50px); transform: none;
  align-items: flex-end; max-width: min(300px, 62%);
}
.toast {
  padding: 9px 16px 10px; border-radius: var(--r-m);
  background: rgba(16, 21, 32, 0.88); color: #fff;
  box-shadow: var(--shadow-m);
  font-weight: 600; font-size: clamp(14px, 0.8vmin + 9px, 17px); line-height: 1.25; text-align: center;
  animation: lb-toast-in 0.26s var(--pop) both;
}
.toast-good { background: #0c9a6b; }
.toast-bad { background: var(--red-deep); }
.toast.is-out { animation: lb-toast-out 0.25s ease both; }
@keyframes lb-toast-in { from { opacity: 0; transform: translateY(-10px) scale(0.9); } to { opacity: 1; transform: none; } }
@keyframes lb-toast-out { from { opacity: 1; } to { opacity: 0; transform: translateY(-6px); } }

.mute {
  position: absolute; z-index: 9; top: calc(var(--edge) + var(--safe-t)); right: calc(var(--edge) + var(--safe-r));
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-width: 44px; height: 44px; padding: 0 14px 0 11px;
  border: 2px solid rgba(255, 255, 255, 0.92); border-radius: 999px;
  background: var(--glass); color: #fff;
  box-shadow: var(--shadow-s);
  font-weight: 600; font-size: 15px; line-height: 1; white-space: nowrap;
  cursor: pointer; pointer-events: auto; touch-action: manipulation;
  transition: transform 0.08s ease, opacity var(--t) ease;
}
.mute:hover { background: rgba(44, 54, 76, 0.85); }
.mute:active { transform: translateY(2px); }
.mute svg { display: block; flex: none; width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.mute .spk { fill: currentColor; }
.mute .ico-off { display: none; }
#ui.is-muted .mute .ico-on { display: none; }
#ui.is-muted .mute .ico-off { display: block; }
#ui[data-screen="none"] .mute { display: none; }
#ui[data-screen="game"] .mute { width: 40px; min-width: 0; height: 40px; padding: 0; opacity: 0.88; }

/* ==========================================================================
   v5: the work week, perks, the daily office. Icons, numbers, stars and colour;
   the only words are the day's name (intro, results) and a perk's name on its pick card.
   ========================================================================== */

/* ---------------------------------------------------------------- menu: week record, daily office */

.btn-solo { flex-wrap: wrap; gap: 4px 14px; }
.week-rec { display: inline-flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums; }
.week-rec .rec { display: inline-flex; align-items: center; gap: 3px; padding: 3px 9px 4px 7px; border-radius: var(--r-pill); background: rgba(58, 37, 0, 0.13); }
.week-rec i { font-style: normal; font-size: 15px; line-height: 1; }

.btn-daily {
  --btn: #9b5de5; --btn-deep: #6c34b8;
  flex-wrap: wrap; gap: 4px 12px; min-height: 52px; padding-left: 1em; padding-right: 1em;
  font-weight: 700; font-size: clamp(15px, 0.9vmin + 10px, 18px);
}
.btn-daily i { font-style: normal; line-height: 1; }
.daily-name b { margin-left: 0.15em; font-variant-numeric: tabular-nums; }
.daily-ico { display: inline-flex; align-items: center; gap: 4px; font-size: 1.2em; }
.daily-perk { display: inline-grid; place-items: center; width: 1.5em; height: 1.5em; border-radius: 50%; background: rgba(255, 255, 255, 0.26); font-size: 0.8em; }
.daily-target, .daily-streak, .daily-done { display: inline-flex; align-items: center; gap: 3px; font-variant-numeric: tabular-nums; }
.daily-done { padding: 2px 9px 3px 7px; border-radius: var(--r-pill); background: rgba(255, 255, 255, 0.24); }
.daily-done i { font-weight: 700; color: var(--mint); }
.btn-daily.is-played { --btn: #8a55cf; }

/* ---------------------------------------------------------------- stars and the week strip */

.stars { display: inline-flex; letter-spacing: -0.06em; line-height: 1; }
.stars i { font-style: normal; color: var(--star-off, rgba(255, 255, 255, 0.38)); }
.stars i.on { color: var(--gold); text-shadow: 0 0 1px #8a5a00, 0 1px 2px rgba(120, 70, 0, 0.6); }

.wk { list-style: none; margin: 0; padding: 0; display: flex; justify-content: center; gap: 4px; }
.wk-day {
  position: relative; flex: none;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  min-width: 2.2em; height: 2.2em; padding: 0 3px; border-radius: var(--r-s);
  background: var(--glass); box-shadow: inset 0 0 0 1.5px var(--glass-line);
  line-height: 1;
}
.wk-ico { font-size: 1.1em; }
.wk-day .stars { font-size: 0.72em; }
.wk-x { color: var(--red); font-weight: 700; font-size: 1.1em; }
.wk-day.is-pass { background: rgba(20, 184, 166, 0.55); }
.wk-day.is-fail { background: rgba(196, 32, 26, 0.55); }
.wk-day.is-now { box-shadow: inset 0 0 0 2.5px #fff, 0 0 10px rgba(255, 255, 255, 0.45); }
.wk-day.is-next { box-shadow: inset 0 0 0 2.5px var(--sun); }
.wk-name { font-size: 0.6em; font-weight: 700; letter-spacing: 0.02em; }

/* In a game: top left, above the scoreboard */
.wk-hud { justify-content: flex-start; font-size: clamp(12px, 0.7vmin + 8px, 16px); text-shadow: none; }
.wk-hud .wk-day:not(.is-now):not(.is-pass):not(.is-fail) .wk-ico { opacity: 0.6; }

/* ---------------------------------------------------------------- in a game: target bar, perks */

.goal { display: flex; align-items: center; gap: 8px; margin-top: 5px; }
.goal-bar {
  position: relative; flex: none;
  width: clamp(120px, 15vw, 230px); height: 10px;
  border: 2px solid #fff; border-radius: var(--r-pill);
  background: rgba(16, 21, 32, 0.38); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}
.goal-clip { position: absolute; inset: 0; border-radius: inherit; overflow: hidden; }
.goal-fill { position: absolute; inset: 0; background: #fff; transform-origin: 0 50%; transform: scaleX(0); transition: transform 0.25s var(--ease), background var(--t) ease; }
.goal.is-met .goal-fill { background: var(--gold); }
.goal-notch { position: absolute; top: 50%; width: 0; height: 0; font-style: normal; }
.goal-notch b {
  position: absolute; left: 0; top: 0; transform: translate(-50%, -54%);
  color: rgba(255, 255, 255, 0.72); font-size: clamp(14px, 0.8vmin + 10px, 19px); line-height: 1;
  text-shadow: 0 0 2px rgba(8, 12, 22, 0.9), 0 1px 3px rgba(8, 12, 22, 0.6);
  transition: color var(--t) ease, transform var(--t) var(--pop);
}
.goal-notch.is-on b { color: var(--gold); transform: translate(-50%, -54%) scale(1.25); text-shadow: 0 0 1px #6b4300, 0 0 8px rgba(255, 212, 59, 0.85); }
.goal-notch.is-pop b { animation: lb-star 0.8s var(--pop) both; }
@keyframes lb-star {
  0% { transform: translate(-50%, -54%) scale(0.6) rotate(-30deg); }
  35% { transform: translate(-50%, -54%) scale(2.3) rotate(12deg); }
  100% { transform: translate(-50%, -54%) scale(1.25) rotate(0deg); }
}
.goal-n { font-size: clamp(11px, 0.6vmin + 8px, 15px); font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.goal.is-bump .goal-bar { animation: lb-goal-bump 0.6s var(--pop); }
@keyframes lb-goal-bump { 0%, 100% { transform: none; } 30% { transform: scale(1.08); } }

.perks { display: inline-flex; align-items: center; gap: 2px; text-shadow: none; }
.perk-ico { display: inline-block; font-style: normal; font-size: clamp(16px, 1vmin + 10px, 22px); line-height: 1; filter: drop-shadow(0 1px 2px rgba(8, 12, 22, 0.65)); }
.perk-ico.is-used { filter: grayscale(1); opacity: 0.38; }
.perk-ico.is-pop { animation: lb-perk-pop 0.7s var(--pop); }
@keyframes lb-perk-pop { 0% { transform: scale(1); } 30% { transform: scale(1.9) rotate(-12deg); } 100% { transform: scale(1); } }

/* The jacket took the blame: the stamp is teal and says "🧥 SAVED" */
.stamp.is-saved { border-color: var(--teal); color: var(--teal-deep); }
.announce[data-kind="star"] .announce-in { background: var(--gold); color: #3a2500; }

/* ---------------------------------------------------------------- in a game: the day intro */

.intro {
  position: absolute; left: 50%; top: 34%; z-index: 4;
  display: flex; flex-direction: column; align-items: center; gap: clamp(8px, 1.4vmin, 14px);
  width: max-content; max-width: calc(100% - 2 * var(--edge));
  transform: translate(-50%, -50%);
  pointer-events: none;
  opacity: 0; visibility: hidden;
  transition: opacity 0.3s ease, visibility 0s linear 0.3s;
}
.intro.is-on { opacity: 1; visibility: visible; transition: opacity 0.2s ease, visibility 0s; }
.intro-card {
  display: flex; align-items: center; gap: 0.32em;
  padding: 0.14em 0.6em 0.2em; border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.95); color: var(--ink);
  box-shadow: 0 0.06em 0 rgba(28, 36, 55, 0.25), var(--shadow-l);
  font-size: clamp(30px, 6vmin + 6px, 76px); font-weight: 700; line-height: 1.1; white-space: nowrap;
}
.intro.is-on .intro-card { animation: lb-intro 0.55s var(--pop) both; }
@keyframes lb-intro { from { opacity: 0; transform: scale(0.5) rotate(-6deg); } to { opacity: 1; transform: none; } }
.intro-trick { font-size: 0.95em; line-height: 1; }
.intro-target { display: inline-flex; align-items: center; gap: 0.1em; font-size: 0.72em; font-variant-numeric: tabular-nums; }
.intro-target i { font-style: normal; font-size: 0.85em; }
.wk-intro { font-size: clamp(15px, 1.2vmin + 10px, 24px); text-shadow: none; }
.wk-intro .wk-day { min-width: 2.8em; height: 2.8em; color: #fff; }
.intro.is-on .wk-intro .wk-day { animation: lb-intro-chip 0.4s var(--pop) both; }
.intro.is-on .wk-intro .wk-day:nth-child(2) { animation-delay: 0.06s; }
.intro.is-on .wk-intro .wk-day:nth-child(3) { animation-delay: 0.12s; }
.intro.is-on .wk-intro .wk-day:nth-child(4) { animation-delay: 0.18s; }
.intro.is-on .wk-intro .wk-day:nth-child(5) { animation-delay: 0.24s; }
@keyframes lb-intro-chip { from { opacity: 0; transform: translateY(10px) scale(0.7); } to { opacity: 1; transform: none; } }
.wk-intro .wk-day.is-now { transform: scale(1.12); }
.intro-perks { display: flex; gap: 6px; font-size: clamp(20px, 1.6vmin + 12px, 30px); }
/* The countdown number moves down and shrinks a little to make room for the intro */
#ui.has-intro .countdown { padding-top: clamp(150px, 30vmin, 330px); }
#ui.has-intro .count-num { font-size: clamp(90px, 26vmin, 280px); }

/* ---------------------------------------------------------------- results: the run */

.res-title { display: flex; align-items: center; justify-content: center; gap: 0.35em; }
.res-stars { --star-off: rgba(28, 36, 55, 0.16); font-size: 0.85em; }
.res-stars i.on { color: #ffb000; text-shadow: 0 2px 0 #c77f00; }
.res-x { color: var(--red); }
.run { flex: none; display: flex; flex-direction: column; align-items: center; gap: clamp(8px, 1.4vmin, 14px); }
.wk-res { --star-off: rgba(28, 36, 55, 0.16); font-size: clamp(14px, 0.8vmin + 10px, 18px); }
.wk-res .wk-day { min-width: 3.1em; height: auto; padding: 6px 6px 5px; gap: 3px; background: var(--tint); box-shadow: none; color: var(--ink); }
.wk-res .wk-day .stars { font-size: 0.85em; }
.wk-res .wk-day .stars i.on { color: #ffb000; text-shadow: 0 1px 0 #c77f00; }
.wk-res .wk-name { font-size: 0.68em; color: var(--ink-soft); }
.wk-res .wk-day.is-pass { background: #fff; box-shadow: inset 0 0 0 2px rgba(20, 184, 166, 0.55); }
.wk-res .wk-day.is-fail { background: rgba(255, 59, 48, 0.12); box-shadow: inset 0 0 0 2px rgba(255, 59, 48, 0.5); }
.wk-res .wk-day.is-now, .wk-res .wk-day.is-next { background: #fff; box-shadow: inset 0 0 0 3px var(--sun); }
.wk-res .wk-day.is-next { animation: lb-next 1.1s ease-in-out infinite alternate; }
@keyframes lb-next { from { transform: none; } to { transform: translateY(-3px); } }
.run-hero { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px 12px; }
.run-stat {
  display: inline-flex; align-items: center; gap: 0.3em;
  padding: 0.2em 0.7em 0.26em; border-radius: var(--r-pill);
  background: var(--tint);
  font-size: clamp(20px, 1.4vmin + 13px, 30px); font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.run-stat i { font-style: normal; font-size: 0.85em; }
.run-stat.is-short { background: rgba(255, 59, 48, 0.12); color: var(--red-deep); font-size: clamp(26px, 2.4vmin + 14px, 42px); animation: lb-short 0.5s var(--pop) both; }
@keyframes lb-short { from { opacity: 0; transform: scale(1.6) rotate(-4deg); } to { opacity: 1; transform: none; } }

/* The week is won: a trophy that bounces in, with confetti */
.run-trophy { position: relative; flex-basis: 100%; text-align: center; font-size: clamp(60px, 11vmin, 120px); line-height: 1; animation: lb-trophy 0.9s var(--pop) both; }
@keyframes lb-trophy { 0% { opacity: 0; transform: scale(0.2) rotate(-25deg); } 60% { opacity: 1; transform: scale(1.15) rotate(6deg); } 100% { transform: none; } }
.confetti {
  position: absolute; left: 50%; top: 45%; width: 0.11em; height: 0.2em; border-radius: 2px;
  background: var(--sun);
  transform: rotate(calc(var(--k) * 25.7deg)) translateY(-0.2em);
  opacity: 0;
  animation: lb-confetti 1.4s cubic-bezier(0.15, 0.7, 0.3, 1) 0.25s both;
}
.confetti:nth-child(3n) { background: var(--teal); }
.confetti:nth-child(3n + 1) { background: #f15bb5; }
.confetti:nth-child(4n) { background: var(--blue); }
@keyframes lb-confetti {
  0% { opacity: 1; transform: rotate(calc(var(--k) * 25.7deg)) translateY(-0.2em) scale(0.4); }
  70% { opacity: 1; }
  100% { opacity: 0; transform: rotate(calc(var(--k) * 25.7deg)) translateY(-1.1em) rotate(200deg) scale(1); }
}

/* Pick a perk: three cards dealt in, each an icon, a name and one line. This is the reward. */
.perk-pick { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(8px, 1.6vmin, 16px); width: 100%; max-width: 720px; padding: 4px 2px 10px; }
.perk-card {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  min-width: 0; padding: clamp(10px, 1.6vmin, 16px) 10px clamp(12px, 1.8vmin, 18px);
  border: 0; border-radius: var(--r-l);
  background: #fff; color: var(--ink);
  box-shadow: 0 6px 0 #d3dae8, 0 12px 24px rgba(10, 30, 50, 0.18);
  font-family: inherit; text-align: center;
  cursor: pointer; pointer-events: auto; touch-action: manipulation;
  animation: lb-deal 0.55s var(--pop) both; animation-delay: calc(var(--i, 0) * 0.12s + 0.15s);
  transition: transform 0.14s var(--pop), box-shadow 0.14s ease, opacity 0.2s ease;
}
@keyframes lb-deal { from { opacity: 0; transform: translateY(40px) rotate(-8deg) scale(0.7); } to { opacity: 1; transform: none; } }
.perk-card::before {                                /* a shine that sweeps across now and then */
  content: ""; position: absolute; top: -20%; bottom: -20%; left: -60%; width: 40%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.85), transparent);
  transform: skewX(-18deg); pointer-events: none;
  animation: lb-shine 3.2s ease-in-out infinite; animation-delay: calc(var(--i, 0) * 0.35s + 0.9s);
}
@keyframes lb-shine { 0%, 70% { left: -60%; } 100% { left: 130%; } }
.perk-card:hover, .perk-card:focus-visible {
  transform: translateY(-6px) rotate(-1.5deg);
  box-shadow: 0 0 0 4px var(--sun), 0 10px 0 #d3dae8, 0 18px 30px rgba(10, 30, 50, 0.25);
}
#ui .perk-card:focus-visible { outline: none; }
.perk-card:active { transform: translateY(2px); box-shadow: 0 0 0 4px var(--sun), 0 2px 0 #d3dae8; }
.perk-key { position: absolute; left: 8px; top: 8px; font-size: 12px; }
.perk-ico-big { font-size: clamp(38px, 5vmin + 14px, 64px); line-height: 1.1; filter: drop-shadow(0 3px 0 rgba(28, 36, 55, 0.12)); }
.perk-name { font-size: clamp(15px, 0.6vmin + 12px, 19px); font-weight: 700; line-height: 1.15; white-space: normal; }
.perk-desc { font-size: clamp(12px, 0.4vmin + 10px, 14px); font-weight: 500; line-height: 1.25; color: var(--ink-soft); white-space: normal; }
.perk-pick.is-picked .perk-card { pointer-events: none; }
.perk-pick.is-picked .perk-card:not(.is-picked) { opacity: 0.2; transform: scale(0.88) translateY(10px); }
.perk-card.is-picked { animation: lb-picked 0.6s var(--pop) both; box-shadow: 0 0 0 5px var(--sun), 0 0 30px rgba(255, 197, 51, 0.9); }
@keyframes lb-picked { 0% { transform: none; } 40% { transform: scale(1.14) rotate(2deg); } 100% { transform: scale(1.08) translateY(-8px); } }

/* In a run the day's ranking against the coworkers matters less: it steps back a little */
.results-panel.is-run .res-row { padding-top: 5px; padding-bottom: 5px; }
.results-panel[data-run="pick"] .res-list, .results-panel[data-run="pick"] .res-missions { opacity: 0.75; }

/* Narrow: the perk cards stack, icon on the left */
@media (max-width: 560px) {
  .perk-pick { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .perk-card {
    display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto auto; column-gap: 12px; row-gap: 1px;
    align-items: center; padding: 8px 14px 9px; text-align: left;
  }
  .perk-ico-big { grid-row: 1 / span 2; font-size: 38px; }
  .perk-key { left: auto; right: 8px; top: 8px; }
  .perk-desc { grid-column: 2; }
  .wk-res .wk-day { min-width: 2.7em; }
  .run-stat { font-size: 20px; }
}
@media (pointer: coarse) { .perk-key { display: none; } }
/* A phone: the score column is narrow. The bar is shorter and the target number goes (the stars on
   the bar still say how far; the number is in the label and in the day intro). */
@media (max-width: 700px) {
  .goal { margin-top: 3px; }
  .goal-bar { width: 96px; height: 9px; }
  .goal-n { display: none; }
  .goal-notch b { font-size: 13px; }
}

@media (prefers-reduced-motion: reduce) {
  .perk-card, .perk-card::before, .perk-card.is-picked, .intro.is-on .intro-card, .intro.is-on .wk-intro .wk-day,
  .run-trophy, .confetti, .run-stat.is-short, .goal.is-bump .goal-bar, .goal-notch.is-pop b, .perk-ico.is-pop,
  .wk-res .wk-day.is-next { animation: none; }
  .confetti { display: none; }
  .perk-card { transition: none; }
}

/* ==========================================================================
   v6: the art (art/*.webp). Pictures take the place of the emoji and are sized from the
   font-size the emoji had, so every layout keeps its proportions. A picture that fails to
   load is replaced by its emoji (.is-emoji) by js/ui.js.
   ========================================================================== */

.art-img {
  display: inline-block; width: 1.2em; height: 1.2em; object-fit: contain; vertical-align: -0.24em;
  -webkit-user-drag: none; user-select: none; pointer-events: none;
}
.card-ico .art-img { width: 1.4em; height: 1.4em; vertical-align: middle; filter: drop-shadow(0 2px 2px rgba(8, 12, 22, 0.35)); }
.how-ico .art-img { width: 1.3em; height: 1.3em; }
.how-ico .art + .art { margin-left: 1px; }
.five-ico .art-img, .five-hand .art-img { width: 1.25em; height: 1.25em; vertical-align: middle; }
.snitch-ico { display: inline-flex; font-size: 1.45em; line-height: 1; }
.snitch-ico .art-img { vertical-align: middle; filter: drop-shadow(0 1px 2px rgba(8, 12, 22, 0.4)); }
.perk-ico .art-img { width: 1.25em; height: 1.25em; vertical-align: middle; }
.perk-ico-big .art-img { width: 1.45em; height: 1.45em; vertical-align: middle; }
.intro-trick .art-img { width: 1.15em; height: 1.15em; vertical-align: middle; }
.intro-perks .art-img { width: 1.4em; height: 1.4em; }
.wk-ico .art-img { width: 1.25em; height: 1.25em; vertical-align: middle; }
.wk-intro .wk-ico .art-img { width: 1.4em; height: 1.4em; }
.daily-ico .art-img { width: 1.3em; height: 1.3em; vertical-align: middle; }
.daily-perk .art-img { width: 1.6em; height: 1.6em; }
.week-rec .art-img { width: 1.35em; height: 1.35em; }
.announce-art .art-img { width: 1.35em; height: 1.35em; margin-right: 0.2em; vertical-align: -0.3em; }
.run-stat .art-img { width: 1.2em; height: 1.2em; vertical-align: middle; }
.trophy-art { display: inline-block; line-height: 1; }
.trophy-art .art-img { width: 1.5em; height: 1.5em; vertical-align: top; filter: drop-shadow(0 6px 10px rgba(150, 100, 0, 0.35)); }
.perk-ico.is-used .art-img { filter: grayscale(1); }

/* The title: the picture. (The CSS letters come back if it fails to load.) */
.logo.has-art { display: block; font-size: 0; line-height: 0; filter: drop-shadow(0 6px 10px rgba(20, 30, 50, 0.25)); }
.logo-img { display: block; margin: 0 auto; width: auto; height: clamp(84px, 17vmin, 200px); max-width: min(92vw, 520px); object-fit: contain; }

/* The loading screen: the office illustration, softly, with the logo; it fades out when the
   menu is ready (js/ui.js adds .is-out, then removes it). */
.boot {
  z-index: 10;
  background: #8fdacb url("../art/splash.webp") center / cover no-repeat;
  transition: opacity 0.42s ease;
}
.boot::before { content: ""; position: absolute; inset: 0; background: rgba(255, 255, 255, 0.28); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.boot > * { position: relative; }
.boot-art { display: block; width: auto; height: clamp(110px, 26vmin, 260px); max-width: 88vw; object-fit: contain; filter: drop-shadow(0 8px 16px rgba(20, 30, 50, 0.3)); }
.boot.is-out { opacity: 0; pointer-events: none; }

/* second batch (section 30): hats, missions, career stats, the target and the briefcase */
.hat-ico .art-img { width: 1.35em; height: 1.35em; vertical-align: middle; }
.career-stats .art-img { width: 1.4em; height: 1.4em; }
.unlocks .art-img { width: 1.25em; height: 1.25em; }
.mchip-ico .art-img, .mission-ico .art-img { width: 1.3em; height: 1.3em; vertical-align: middle; }
.goal-ico .art-img { width: 1.35em; height: 1.35em; vertical-align: -0.35em; margin-right: 1px; }
.intro-target .art-img, .daily-target .art-img { width: 1.25em; height: 1.25em; vertical-align: middle; }

/* ==========================================================================
   Responsive: from a 360x640 phone to 1920x1080
   ========================================================================== */

/* Results with XP: one column, and what matters for "one more day" comes first
   (XP, then Play again, then the ranking, then the missions). */
@media (max-width: 900px) {
  .results-panel.has-xp { max-width: 640px; max-height: none; }
  .results-panel.has-xp .res-body { display: flex; flex-direction: column; }
  .results-panel.has-xp .res-side { display: contents; }
  .results-panel.has-xp .xp, .results-panel.has-xp .best { order: 1; }
  .results-panel.has-xp .share, .results-panel.has-xp .res-side .actions { order: 2; margin-top: 0; }
  .results-panel.has-xp .res-list { order: 3; flex: none; overflow: visible; }
  .results-panel.has-xp .res-missions { order: 4; }
}

@media (max-width: 760px) {
  #lb-menu.has-career .menu-in { max-width: 520px; }
  .menu-panel, #lb-menu.has-career .menu-panel { grid-template-columns: minmax(0, 1fr); }
  .menu-career { padding: 12px 0 0; border-left: 0; border-top: 2px dashed var(--line); }
  .mute { width: 40px; min-width: 0; height: 40px; padding: 0; }
  /* The panels reach the screen edge here: keep a strip free at the bottom for the chat button,
     and make the button a small round one. */
  #lb-lobby, #lb-results { padding-bottom: calc(var(--edge) + var(--safe-b) + 46px); }
  .chat-btn .key { display: none; }
}

/* Narrow: the four cards become a 2x2 grid; the scoreboard and the missions go */
@media (max-width: 700px) {
  .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .side { display: none; }
  .snitch { min-height: 40px; padding: 4px 10px 5px 7px; gap: 5px; }
  .mult { left: auto; right: -0.7em; top: auto; bottom: 80%; margin-left: 0; transform-origin: 100% 100%; }     /* on the pot's shoulder: the snitch button is right beside it */
  /* Cards two by two: the dash pill sits across the top row (the desk cards scroll and games) */
  .desk-btn { left: 50%; top: 25%; }
  #ui.has-touch .desk-btn { min-width: 56%; }
  #ui[data-screen="game"] .chat { width: min(250px, 66%, calc(100% - var(--stick) - 3 * var(--edge) - 10px)); }
  /* Touch on a phone: the stick has the left, the high five the middle, so the chat goes right */
  #ui.has-touch[data-screen="game"] .chat { left: auto; right: calc(var(--edge) + var(--safe-r)); align-items: flex-end; }
  #ui.has-touch[data-screen="game"] .chat-log { align-items: flex-end; }
  #ui.has-touch[data-screen="game"] .chat-row { display: flex; justify-content: flex-end; }
  #ui.has-touch .five { left: 58%; }                     /* a little to the right, off the stick */
  /* The boss stands just above the log here: two lines, one row each (the bubble over the speaker has the whole line) */
  #ui[data-screen="game"] .chat-line:nth-last-child(n + 3) { display: none; }
  #ui[data-screen="game"] .chat-line { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .pop-chat.is-mine { display: none; }           /* your own line is in the log, right beside your desk */
}

@media (max-width: 700px) and (pointer: coarse) {
  #ui[data-screen="game"] .chat { left: auto; right: calc(var(--edge) + var(--safe-r)); align-items: flex-end; }
  #ui[data-screen="game"] .chat-log { align-items: flex-end; }
  #ui[data-screen="game"] .chat-row { display: flex; justify-content: flex-end; }
  .five { left: 58%; }
}

@media (max-width: 400px) {
  .res-row { column-gap: 7px; padding: 6px 9px; }
  .hats { gap: 4px; }
  .how { padding: 3px 8px 4px 6px; }
  .how .key { font-size: 12px; }
}

/* Short (phones on their side): compact cards */
@media (max-height: 560px) {
  .card { row-gap: 3px; --strip: 12px; }
  .card-hot b { font-size: 8.5px; }
  .card-ico { font-size: clamp(22px, 2vmin + 12px, 30px); }
  #ui[data-screen="game"] .chat-line:nth-last-child(n + 4) { display: none; }
}
/* Too short to give the ranking its own scroll area: the whole results screen scrolls instead */
@media (max-height: 520px) {
  .results-panel { max-height: none; }
  .res-list { flex: none; overflow: visible; }
  .results-panel.has-xp .res-side { overflow: visible; }
}
@media (max-height: 430px) {
  .side { display: none; }
  .card-bar { display: none; }
  .room-code { font-size: clamp(44px, 14vmin, 72px); }
}

/* ==========================================================================
   Reduced motion: no shakes, flashes, wiggles, beats or flying. Information that
   an animation carried is kept as a plain fade.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .screen-in, .boot-text, .input.is-wrong, .hat.is-wrong, .best.is-new, .levelup, .toast, .chat-line,
  .hud.is-shake, .flash.is-on, .pi.is-hit .pi-fig, .score.is-bump, .streak.is-bump, .strikes i.on,
  .card.is-active .card-ico, .pot-box.is-hot .pot-in, .mchip.is-flash, .cards-warn.is-full, #ui.is-laststrike .strikes i:not(.on),
  #ui.is-rush .clock, #ui.is-danger .heat-n, #ui.is-blind .lid-text b { animation: none; }

  .btn, .card, .snitch, .step, .mute, .brow, .pot-box, .hat, .xp-bar i, .busy-bar i, .mchip-bar i { transition: none; }
  .lid, #ui.is-blind .lid, .banner, .cards-warn, .fx-vignette { transition: none; }

  #ui.is-danger .sus-bar { animation: none; }
  #ui.is-danger .sus-bar::after { animation: none; }
  #ui.is-laststrike .fx-last::before { animation: none; opacity: 0.6; }      /* a steady glow instead of a pulse */

  .tell.is-on { animation: none; }
  .falsealarm.is-on { animation: lb-hold 1.3s linear both; transform: translate(-50%, 0); }
  .stamp.is-on { animation: lb-hold 1.9s linear both; }
  .pop-in, .pop-caught .pop-in, .pop-snitch .pop-in, .pop-chat .pop-in { animation-name: lb-hold; animation-timing-function: linear; }
  .fly.is-on { animation: lb-hold 0.9s linear both; transform: translate(var(--x1, 0px), var(--y1, 0px)) translate(-50%, -160%); }
  .fx-glow.is-on { animation: lb-hold 1.2s linear both; }
  .count-num, .count-go { animation: lb-hold 0.95s linear both; }
  .announce.is-on .announce-in { animation: lb-hold 2.7s linear both; transform: none; }
  .callout.is-on, .rankup.is-on, .streak-lost.is-on { animation: lb-hold 1.5s linear both; }
  .final.is-on { animation: lb-hold 0.95s linear both; }
  .warncard.is-on { animation: lb-hold 2.2s linear both; }
  .docked.is-on { animation: lb-hold 2.4s linear both; transform: rotate(-4deg); }
  .score.is-dock, .five.is-clapped .five-hand, .five[data-state="ok"] .five-text, .five[data-state="fail"] .five-text { animation: none; }
  .busy-pop.is-on { animation: lb-hold 0.6s linear both; transform: translate(var(--x, 0px), -14px); }
  #ui.is-fired .fired, #ui.is-fired .fired b { animation: none; }
  .toast.is-out { animation: none; opacity: 0; }
}
