/* Turning Point 3D table: dark petrol UI, amber accents. */

/* The two faces the table is drawn in, self-hosted so every machine gets the
   same type (design review row 7). Variable fonts: one file carries every
   weight used (400 to 700). SIL Open Font License; the licence sits beside each. */
@font-face {
  font-family: "JetBrains Mono";
  src: url("assets/fonts/jetbrains-mono/JetBrainsMono-wght.woff2") format("woff2");
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Work Sans";
  src: url("assets/fonts/work-sans/WorkSans-wght.ttf") format("truetype");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  --petrol-deep: #06161b;
  --petrol: #0a1f24;
  --petrol-raised: #103038;
  --teal-line: #1d4a52;
  --amber: #ff9a3c;
  --amber-dim: #b56a26;
  --text: #cfe3e6;
  --text-dim: #7fa0a6;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --sans: "Work Sans", -apple-system, "Helvetica Neue", Arial, sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  height: 100%;
  overflow: hidden;
  background: var(--petrol-deep);
  color: var(--text);
  font-family: var(--sans);
}

#app, #app canvas { position: fixed; inset: 0; display: block; }

#hud {
  position: fixed;
  top: 16px;
  left: 20px;
  z-index: 10;
  display: flex;
  align-items: baseline;
  gap: 12px;
  pointer-events: none;
}

#hud h1 {
  font-family: var(--mono);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text);
}

#hud h1::first-letter { color: var(--amber); }

#version-badge {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--text-dim);
  border: 1px solid var(--teal-line);
  border-radius: 3px;
  padding: 2px 8px;
  background: rgba(10, 31, 36, 0.75);
}

#version-badge.error {
  color: #e05a3a;
  border-color: #e05a3a;
}

#seatbar {
  position: fixed;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  display: flex;
  gap: 6px;
  padding: 6px;
  border: 1px solid var(--teal-line);
  border-radius: 6px;
  background: rgba(6, 22, 27, 0.82);
  backdrop-filter: blur(6px);
}

#seatbar button {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  background: var(--petrol);
  border: 1px solid var(--teal-line);
  border-radius: 4px;
  padding: 7px 12px;
  cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}

#seatbar button:hover {
  color: var(--text);
  border-color: var(--amber-dim);
}

#seatbar button.active {
  color: var(--amber);
  border-color: var(--amber);
  background: var(--petrol-raised);
}

#seatbar button .key {
  color: var(--amber-dim);
  margin-right: 6px;
}

#seatbar button.active .key { color: var(--amber); }

/* Control strip. It sits above the seat bar rather than beside it, so each of
   its two rows can run full-width and use whole words at 1280px. */
#keys {
  position: fixed;
  /* Clears the seat bar, which stands 76px tall from the bottom edge. */
  bottom: 86px;
  left: 20px;
  z-index: 10;
  /* The longer row is ~112 monospace characters (~717px at 10px); 820px leaves
     headroom for a wider fallback font without either row wrapping at 1280px. */
  max-width: min(820px, calc(100vw - 40px));
  font-family: var(--mono);
  font-size: 10px;
  line-height: 1.7;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  background: rgba(6, 22, 27, 0.82);
  border: 1px solid var(--teal-line);
  border-radius: 4px;
  padding: 6px 10px;
  pointer-events: none;
}

#keys .keys-row { display: block; }

#keys b {
  color: var(--amber-dim);
  font-weight: 700;
}

/* The enlarged card is the top layer of the table. It used to sit at 20, under
   the dock (21), the HUD and zoom (22), the strip (23), the roster (24), the
   movement labels (34) and Feedback (90): the strip hid the bottom of the card,
   Feedback sat on its title, and "click anywhere to close" could land on one of
   the strip's answer buttons and submit a choice. Only the Feedback tools'
   own 90 has to be cleared; everything else on the table is below that. */
#enlarge {
  position: fixed;
  inset: 0;
  z-index: 95;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  background: rgba(4, 12, 14, 0.82);
  backdrop-filter: blur(4px);
  cursor: pointer;
}

#enlarge[hidden] { display: none; }

#enlarge canvas {
  height: min(80vh, 700px);
  aspect-ratio: 5 / 7;
  border: 1px solid var(--amber-dim);
  border-radius: 12px;
  background: var(--petrol);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.6), 0 0 0 1px var(--teal-line);
}

#enlarge p {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--text-dim);
}

/* A visible way out as well as "anywhere". The whole overlay closes on a click,
   so this is not a second behaviour; it is the one a player looks for first. */
#enlarge .enlarge-close {
  position: absolute;
  top: 16px;
  right: 20px;
  padding: 6px 12px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--text);
  background: rgba(6, 22, 27, 0.9);
  border: 1px solid var(--amber-dim);
  border-radius: 6px;
  cursor: pointer;
}
#enlarge .enlarge-close:hover,
#enlarge .enlarge-close:focus-visible { color: var(--petrol-deep); background: var(--amber); outline: none; }

/* ---------------------------------------------------------- multiplayer UI */

#net-lobby {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(4, 12, 14, 0.72);
  backdrop-filter: blur(5px);
}

#net-lobby[hidden] { display: none; }

.net-panel {
  width: min(92vw, 360px);
  padding: 22px 22px 16px;
  border: 1px solid var(--teal-line);
  border-radius: 8px;
  background: rgba(6, 22, 27, 0.94);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.6);
}

.net-panel h2 {
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text);
}

.net-panel h2::first-letter { color: var(--amber); }

.net-sub {
  margin-top: 6px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-dim);
}

.net-actions {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 16px 0 4px;
}
/* The online build hides the old peer-to-peer table's buttons (online-panel.js);
   without this, display: flex above overrides [hidden] and they still show. */
.net-actions[hidden] { display: none; }

.net-panel button {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  background: var(--petrol);
  border: 1px solid var(--teal-line);
  border-radius: 4px;
  padding: 9px 12px;
  cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}

.net-panel button:hover {
  color: var(--text);
  border-color: var(--amber-dim);
}

.net-code {
  font-family: var(--mono);
  color: var(--amber);
  letter-spacing: 0.14em;
}

.net-code-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-top: 12px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-dim);
}

.net-code-row .net-code { font-size: 20px; }

.net-seats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  margin-top: 12px;
}

.net-seat {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
}

.net-seat .s-n { color: var(--text); }
.net-seat .s-t { color: var(--text-dim); font-size: 10px; letter-spacing: 0.08em; }
.net-seat.mine { border-color: var(--amber); }
.net-seat.mine .s-n, .net-seat.mine .s-t { color: var(--amber); }
.net-seat.taken { opacity: 0.55; }

/* Who you are at a shared table. One field, remembered per browser, read by
   both "Host" and "Join": a room with six "Seat 4"s in it is the problem the
   player areas and the shared pointers are trying to solve. */
.net-name-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 14px 0 2px;
}
.net-name-row > span {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--teal-line);
  white-space: nowrap;
}
.net-name {
  flex: 1;
  min-width: 0;
  font-family: var(--mono);
  font-size: 14px;
  color: var(--amber);
  background: var(--petrol);
  border: 1px solid var(--teal-line);
  border-radius: 4px;
  padding: 8px 10px;
}
.net-name::placeholder { color: #4d6f78; }

.net-join { display: flex; gap: 6px; margin-top: 12px; }

.net-input {
  flex: 1;
  font-family: var(--mono);
  font-size: 14px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--amber);
  background: var(--petrol);
  border: 1px solid var(--teal-line);
  border-radius: 4px;
  padding: 8px 10px;
}

.net-esc {
  margin-top: 14px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--text-dim);
}

#net-badge {
  position: fixed;
  top: 16px;
  right: 20px;
  z-index: 12;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--text-dim);
  border: 1px solid var(--teal-line);
  border-radius: 3px;
  padding: 3px 9px;
  background: rgba(10, 31, 36, 0.82);
}

#net-badge[hidden] { display: none; }
#net-badge b { color: var(--amber); letter-spacing: 0.12em; }

#net-banner {
  position: fixed;
  top: 52px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 12;
  max-width: 80vw;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.05em;
  color: var(--text);
  border: 1px solid var(--amber-dim);
  border-radius: 4px;
  padding: 6px 12px;
  background: rgba(20, 10, 6, 0.9);
}

#net-banner[hidden] { display: none; }

/* -------------------------------------------- landing: version picker + links */

#net-lobby .tp-illustrated-lobby {
  position: relative;
  width: min(960px, 94vw);
  box-sizing: border-box;
  padding: 34px 30px 24px calc(min(480px, 47vw) + 28px);
  min-height: 610px;
  border-color: #716d60;
  background: #101c20;
}

.tp-lobby-cover {
  position: absolute;
  inset: 0 50% 0 0;
  isolation: isolate;
  padding: 38px;
  color: #eee8d5;
  background: #07171b;
  border-right: 1px solid #716d60;
  border-radius: 7px 0 0 7px;
}
.tp-lobby-cover img { position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%; object-fit: cover; }
.tp-lobby-cover::before { content: ''; position: absolute; inset: 0; z-index: -1; background: linear-gradient(180deg, #07171b99, #07171b22 40%, #07171be8 90%); }
.tp-lobby-cover-kicker { font: 10px system-ui, sans-serif; letter-spacing: .3em; }
.net-panel .tp-lobby-cover h2 { margin: 22px 0 12px; font: 58px/1.05 Georgia, serif; letter-spacing: -.025em; color: #fff6de; text-transform: none; }
.tp-lobby-cover p { font: 20px/1.4 Georgia, serif; color: #eee8d5; text-shadow: 0 2px 12px #000; }
.tp-lobby-cover-foot { position: absolute; bottom: 40px; left: 38px; right: 32px; padding-top: 18px; border-top: 1px solid #eee8d570; font: 12px/1.8 system-ui, sans-serif; }
@media (max-width: 760px) {
  #net-lobby .tp-illustrated-lobby { padding: 260px 22px 22px; min-height: 0; }
  .tp-lobby-cover { inset: 0 0 auto; height: 220px; box-sizing: border-box; padding: 20px; border-right: 0; border-bottom: 1px solid #716d60; border-radius: 7px 7px 0 0; }
  .tp-lobby-cover img { object-position: center 45%; }
  .net-panel .tp-lobby-cover h2 { font-size: 42px; margin: 12px 0 10px; }
  .tp-lobby-cover p { font-size: 16px; margin: 0; max-width: 28ch; }
  .tp-lobby-cover-foot { display: none; }
}

.tp-versions {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  margin: 14px 0 2px;
}

.tp-ver {
  display: flex;
  flex-direction: column;
  gap: 1px;
  align-items: flex-start;
  text-align: left;
  font-family: var(--mono);
  color: var(--text-dim);
  background: var(--petrol);
  border: 1px solid var(--teal-line);
  border-radius: 4px;
  padding: 7px 9px;
  cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}

.tp-ver b { font-size: 13px; color: var(--text); letter-spacing: 0.06em; }
.tp-ver-name { font-size: 14px; color: var(--text); line-height: 1.25; }
.tp-ver-note {
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.tp-ver:hover:not(:disabled) { color: var(--text); border-color: var(--amber-dim); }

.tp-ver.active {
  border-color: var(--amber);
  background: var(--petrol-raised);
}
.tp-ver.active .tp-ver-name,
.tp-ver.active .tp-ver-note { color: var(--amber); }

.tp-ver:disabled { opacity: 0.4; cursor: not-allowed; }

.tp-links {
  display: flex;
  gap: 6px;
  margin-top: 12px;
}

.tp-link {
  flex: 1;
  text-align: center;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.05em;
  color: var(--text-dim);
  text-decoration: none;
  background: var(--petrol);
  border: 1px solid var(--teal-line);
  border-radius: 4px;
  padding: 8px 6px;
  transition: color 120ms ease, border-color 120ms ease;
}

.tp-link:hover { color: var(--text); border-color: var(--amber-dim); }

/* ------------------------------------------------------------ player-aid panel */

/* Four HUD buttons share one look: ? player aid, H interface guide, Menu, and
   "My player" (js/myplayer.js), which is a lookup like the other three rather
   than a mode. */
#tp-aid-btn,
#tp-help-btn,
#tp-menu-btn,
#tp-mine-btn {
  position: fixed;
  right: 20px;
  bottom: 18px;
  z-index: 22;
  width: 30px;
  height: 30px;
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 700;
  color: var(--text-dim);
  background: rgba(6, 22, 27, 0.82);
  border: 1px solid var(--teal-line);
  border-radius: 6px;
  cursor: pointer;
  backdrop-filter: blur(6px);
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}

#tp-aid-btn:hover,
#tp-help-btn:hover,
#tp-menu-btn:hover,
#tp-mine-btn:hover { color: var(--text); border-color: var(--amber-dim); }

#tp-aid-btn.active,
#tp-help-btn.active {
  color: var(--amber);
  border-color: var(--amber);
  background: var(--petrol-raised);
}

/* Sat to the left of ? in reading order: Menu, H, ?. */
#tp-help-btn { right: 58px; }

/* To the left of Menu, which is itself auto-width; the gap is measured from
   Menu's own right edge plus its widest label. */
#tp-mine-btn {
  right: 168px;
  width: auto;
  padding: 0 10px;
  font-size: 12px;
  letter-spacing: 0.06em;
}

#tp-menu-btn {
  right: 96px;
  width: auto;
  padding: 0 10px;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* The guidance strip reserves a 62px column at the right in every game
   (js/solo.css, --gd-gutter), so the references stand in that column rather
   than in a row along the bottom. The row was Firebreak-only until the camera
   and panel pass: in Common Ground and Vested Interests the strip, stacked above
   it, covered My player, Menu and Help for the whole of a guided game, and only
   ? was left to click. Keep references beside decisions, not above them in the
   stacking order. */
#tp-help-btn,
#tp-menu-btn,
#tp-mine-btn {
  right: 10px;
  width: 44px;
  padding: 0;
  font-size: 10px;
}
#tp-help-btn { bottom: 56px; font-size: 11px; }
#tp-menu-btn { bottom: 94px; }
/* The stack goes up the right edge, so a button added to it needs its own step.
   Without one it inherits the default bottom and sits exactly on top of the
   player-aid button, which is what happened in Firebreak: the aid button became
   unclickable and the lane timed out on it. */
#tp-mine-btn { bottom: 132px; }

#tp-aid {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 25;
  width: min(94vw, 360px);
  height: 100%;
  overflow-y: auto;
  color: var(--text);
  background: rgba(6, 22, 27, 0.96);
  border-left: 1px solid var(--teal-line);
  box-shadow: -18px 0 60px rgba(0, 0, 0, 0.55);
}

#tp-aid[hidden] { display: none; }

.aid-head {
  position: sticky;
  top: 0;
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 16px 18px 12px;
  background: rgba(6, 22, 27, 0.98);
  border-bottom: 1px solid var(--teal-line);
}

.aid-head b {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.aid-head b::first-letter { color: var(--amber); }

.aid-head span {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--text-dim);
}

/* A close that reads as a button (playtest UI-04, 28 September 2026: a player
   could not find how to dismiss this pane). */
.aid-close {
  margin-left: auto;
  min-height: 30px;
  padding: 4px 10px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  line-height: 1;
  color: var(--text);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--teal-line);
  border-radius: 4px;
  cursor: pointer;
}
.aid-close:hover { color: var(--amber); border-color: var(--amber-dim); }

.aid-body { padding: 6px 18px 28px; }

.aid-body h3 {
  margin-top: 16px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--amber-dim);
}

.aid-body p {
  margin-top: 5px;
  font-family: var(--sans);
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text);
}

.aid-body b {
  font-family: var(--mono);
  font-weight: 700;
  font-size: 11.5px;
  letter-spacing: 0.03em;
  color: var(--text);
}

.aid-fine {
  margin-top: 18px;
  color: var(--text-dim) !important;
  font-size: 11px !important;
}

/* Footer link out to the online manual (/3d/rules/), appended by aid.js. */
.aid-body .aid-rules-link {
  font-family: var(--mono);
  letter-spacing: 0.04em;
  color: var(--amber-dim);
  text-decoration: none;
}

.aid-body .aid-rules-link:hover { color: var(--amber); }

/* ------------------------------------------------- how-to-use-this-table guide */

/* Above the lobby (z 30) so H works even with the lobby open. */
#tp-help {
  position: fixed;
  inset: 0;
  z-index: 32;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(4, 12, 14, 0.78);
  backdrop-filter: blur(5px);
}

#tp-help[hidden] { display: none; }

.hk-panel {
  display: flex;
  flex-direction: column;
  width: min(96vw, 980px);
  max-height: min(90vh, 780px);
  border: 1px solid var(--teal-line);
  border-radius: 8px;
  background: rgba(6, 22, 27, 0.96);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.6);
}

.hk-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 16px 20px 12px;
  border-bottom: 1px solid var(--teal-line);
}

.hk-head b {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text);
}

.hk-head b::first-letter { color: var(--amber); }

.hk-head span {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--text-dim);
}

.hk-close {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 18px;
  line-height: 1;
  color: var(--text-dim);
  background: none;
  border: none;
  cursor: pointer;
}
.hk-close:hover { color: var(--amber); }

/* Two columns of self-contained sections; one column when there is no room. */
.hk-body {
  flex: 1;
  overflow-y: auto;
  padding: 6px 20px 16px;
  columns: 2;
  column-gap: 28px;
}

.hk-sec {
  break-inside: avoid;
  page-break-inside: avoid;
  margin-top: 13px;
}

.hk-sec h3 {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--amber-dim);
}

.hk-sec ul { margin-top: 5px; list-style: none; }

.hk-sec li {
  position: relative;
  padding-left: 12px;
  margin-top: 3px;
  font-family: var(--sans);
  font-size: 12px;
  line-height: 1.45;
  color: var(--text);
}

.hk-sec li::before {
  content: "·";
  position: absolute;
  left: 2px;
  color: var(--amber-dim);
}

.hk-sec a { color: var(--amber-dim); text-decoration: none; }
.hk-sec a:hover { color: var(--amber); }

#tp-help kbd {
  display: inline-block;
  min-width: 16px;
  padding: 0 4px;
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 700;
  line-height: 15px;
  text-align: center;
  color: var(--amber);
  background: var(--petrol);
  border: 1px solid var(--teal-line);
  border-bottom-color: var(--amber-dim);
  border-radius: 3px;
}

.hk-foot {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 12px 20px 14px;
  border-top: 1px solid var(--teal-line);
}

.hk-fine {
  flex: 1;
  min-width: 200px;
  font-family: var(--mono);
  font-size: 10px;
  line-height: 1.6;
  letter-spacing: 0.04em;
  color: var(--text-dim);
}

.hk-btns { display: flex; gap: 6px; margin-left: auto; }

.hk-btns button {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  background: var(--petrol);
  border: 1px solid var(--teal-line);
  border-radius: 4px;
  padding: 9px 14px;
  cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}

.hk-btns button:hover { color: var(--text); border-color: var(--amber-dim); }

.hk-btns button[data-act="ok"] {
  color: var(--amber);
  border-color: var(--amber-dim);
}

@media (max-width: 760px) {
  .hk-body { columns: 1; }
}

/* ---------------------------------------------------------- zoom controls */

/* Stacked + / - against the middle of the right edge, in the HUD button look.
   The player aid slides in over this side of the screen, so the bar steps left
   by exactly the aid's width while that panel is open (js/zoomui.js toggles
   .shifted), and stands down entirely when the screen is too narrow for both. */
#tp-zoom {
  position: fixed;
  top: 50%;
  right: 20px;
  transform: translateY(-50%);
  z-index: 22;
  display: flex;
  flex-direction: column;
  gap: 6px;
  transition: right 160ms ease;
}

#tp-zoom.shifted { right: calc(min(94vw, 360px) + 20px); }

.tp-zoom-btn {
  width: 30px;
  height: 30px;
  font-family: var(--mono);
  font-size: 17px;
  font-weight: 700;
  line-height: 1;
  color: var(--text-dim);
  background: rgba(6, 22, 27, 0.82);
  border: 1px solid var(--teal-line);
  border-radius: 6px;
  cursor: pointer;
  backdrop-filter: blur(6px);
  touch-action: none;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease, opacity 120ms ease;
}

.tp-zoom-btn:hover { color: var(--text); border-color: var(--amber-dim); }
.tp-zoom-btn:active { color: var(--amber); border-color: var(--amber); background: var(--petrol-raised); }

/* Nothing left in that direction: the rig is against minDistance/maxDistance. */
.tp-zoom-btn.spent { opacity: 0.32; }

/* The two view controls sit in their own group directly under the zoom bar,
   and step left with it when the player aid opens (js/zoomui.js). */
#tp-view {
  position: fixed;
  right: 20px;
  z-index: 22;
  display: flex;
  flex-direction: column;
  gap: 6px;
  transition: right 160ms ease;
}
#tp-view[hidden] { display: none; }
#tp-view.shifted { right: calc(min(94vw, 360px) + 20px); }

/* Your area wears the seat's own shape in the seat's colour (js/zoomui.js);
   with no seat to go to it is shown and says why, rather than vanishing. */
.tp-zoom-area { font-size: 15px; }
.tp-zoom-btn:disabled { opacity: 0.32; cursor: default; }
/* Back is there only while there is a view to go back to. */
.tp-zoom-btn[hidden] { display: none; }

@media (max-width: 720px) {
  #tp-zoom.shifted { display: none; }
}

/* ------------------------------------------------------------- the dock */

/* One column down the left edge holding every panel that would otherwise float
   over the table: the seat panel, the inspector, the action field. They are
   laid out, not positioned, so the stack reflows around whatever is open and no
   panel can ever cover another one's title bar or close button. js/dock.js owns
   the column and the fold-away chevrons; the panels own their own contents.

   Top clears the HUD. Bottom clears the sandbox key hints and the seat bar;
   solo play hides both, so js/solo.css lowers it while a game is running. */
#tp-dock {
  position: fixed;
  top: 74px;
  left: 20px;
  bottom: 142px;
  z-index: 21;
  width: min(92vw, 344px);
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: thin;
  /* The gaps between cards are table, not interface: a drag started there
     reaches the board. Each card takes its own clicks back. */
  pointer-events: none;
}

#tp-dock > * {
  pointer-events: auto;
  flex: 0 0 auto;
  min-height: 0;
}

/* ------------------------------------------------------------------ *
   My player (js/myplayer.js)

   A dock card like the others, so it folds by the same chevron and is found
   again by the same show-all widget. Its one structural rule is that the
   identity-and-resources strip never scrolls away: switching to Cards must not
   cost you sight of what you can afford.
   ------------------------------------------------------------------ */
/* [hidden] is an attribute selector and loses to the id rule below, so a panel
   given display:flex by id would never hide. Stated first and explicitly. */
#tp-myplayer[hidden] { display: none; }

#tp-myplayer {
  background: var(--panel, #0b1f26f2);
  border: 1px solid var(--teal-line);
  border-radius: 6px;
  max-height: min(62vh, 620px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
#tp-myplayer .mp-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--teal-line);
}
#tp-myplayer .mp-title {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--amber);
}
/* Pinned: the strip and the tabs stay put and only .mp-body scrolls. */
#tp-myplayer .mp-strip {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
  border-bottom: 1px solid #17444d;
}
#tp-myplayer .mp-who {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 3px 8px;
  border-radius: 4px;
  border: 1px solid var(--mp-seat, var(--teal-line));
  background: #06161b;
}
#tp-myplayer .mp-glyph { color: var(--mp-seat, var(--amber)); font-size: 13px; }
#tp-myplayer .mp-name { font-family: var(--mono); font-size: 13px; color: #eef4f2; }
#tp-myplayer .mp-colour {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--mp-seat, var(--teal-line));
}
#tp-myplayer .mp-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #9fc0c6;
  padding: 3px 8px;
  border: 1px solid #17444d;
  border-radius: 4px;
}
#tp-myplayer .mp-chip b { font-size: 15px; color: var(--amber); letter-spacing: 0; }
#tp-myplayer .mp-tabs {
  flex: 0 0 auto;
  display: flex;
  gap: 2px;
  padding: 6px 8px 0;
}
#tp-myplayer .mp-tab {
  flex: 1;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: #8fb2b9;
  background: transparent;
  border: 1px solid transparent;
  border-bottom: 1px solid var(--teal-line);
  border-radius: 4px 4px 0 0;
  padding: 6px 4px;
  cursor: pointer;
}
#tp-myplayer .mp-tab:hover { color: #d8e8ea; }
#tp-myplayer .mp-tab.on {
  color: var(--amber);
  border-color: var(--teal-line);
  border-bottom-color: transparent;
  background: #0d2830;
}
#tp-myplayer .mp-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 10px;
  scrollbar-width: thin;
}
#tp-myplayer h4 {
  margin: 12px 0 5px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #6f959d;
}
#tp-myplayer h4:first-child { margin-top: 0; }
#tp-myplayer .mp-none { color: #7f9aa0; font-size: 12px; margin: 4px 0; font-style: italic; }
/* An honest limit, stated rather than hidden: this is what a room without a
   referee can and cannot tell you. */
#tp-myplayer .mp-caveat {
  border-left: 2px solid var(--amber);
  padding: 2px 0 2px 8px;
  margin-bottom: 10px;
}
#tp-myplayer .mp-caveat p { margin: 0 0 4px; font-size: 11.5px; color: #a9c4c9; line-height: 1.45; }
#tp-myplayer ul { list-style: none; margin: 0; padding: 0; }
#tp-myplayer .mp-counts li {
  display: flex;
  gap: 8px;
  align-items: baseline;
  font-size: 12.5px;
  color: #cfe2e4;
  padding: 2px 0;
}
#tp-myplayer .mp-counts b { min-width: 2ch; text-align: right; color: var(--amber); font-family: var(--mono); }
#tp-myplayer .mp-filter { margin-bottom: 8px; font-size: 11.5px; color: #8fb2b9; }
/* "Show as": the two ways Sam asked a seat with a House to be written. It sits
   in the pinned strip, beside the name it changes, and wears the same petrol
   select as the filters rather than the browser's white default. */
#tp-myplayer .mp-format-row {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #6f959d;
}
#tp-myplayer .mp-format,
#tp-myplayer .mp-filter select {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--amber);
  background: var(--petrol);
  border: 1px solid var(--teal-line);
  border-radius: 3px;
  padding: 3px 5px;
}
#tp-myplayer .mp-cards li {
  display: flex;
  gap: 9px;
  padding: 8px 0;
  border-bottom: 1px solid #12333a;
}
#tp-myplayer .mp-thumb {
  flex: 0 0 auto;
  width: 64px;
  height: 90px;
  border-radius: 3px;
  border: 1px solid var(--teal-line);
  background: #06161b;
}
#tp-myplayer .mp-thumb-blank { opacity: 0.35; }
#tp-myplayer .mp-card-text { min-width: 0; }
#tp-myplayer .mp-card-text b { display: block; font-size: 12.5px; color: #eef4f2; }
#tp-myplayer .mp-deck {
  display: block;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #6f959d;
  margin: 2px 0 4px;
}
#tp-myplayer .mp-card-text p { margin: 0; font-size: 11.5px; color: #b6cdd1; line-height: 1.45; }
#tp-myplayer .mp-card-acts { display: flex; gap: 5px; margin-top: 6px; }
#tp-myplayer .mp-enlarge,
#tp-myplayer .mp-locate {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  color: var(--amber);
  background: transparent;
  border: 1px solid var(--teal-line);
  border-radius: 3px;
  padding: 3px 7px;
  cursor: pointer;
}
#tp-myplayer .mp-enlarge:hover,
#tp-myplayer .mp-locate:hover { background: #0d2830; }
#tp-myplayer .mp-assets li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  padding: 6px 0;
  border-bottom: 1px solid #12333a;
  font-size: 12.5px;
  color: #dfeced;
}
#tp-myplayer .mp-meta,
#tp-myplayer .mp-flags {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #6f959d;
}
#tp-myplayer .mp-heat { font-family: var(--mono); font-size: 11px; color: var(--amber); }
#tp-myplayer .mp-objectives li { padding: 8px 0; border-bottom: 1px solid #12333a; }
#tp-myplayer .mp-objectives b { display: block; font-size: 12.5px; color: #eef4f2; margin-bottom: 3px; }
#tp-myplayer .mp-objectives p { margin: 0; font-size: 11.5px; color: #b6cdd1; line-height: 1.45; }
#tp-myplayer .mp-bar {
  height: 4px;
  background: #12333a;
  border-radius: 2px;
  margin: 6px 0 4px;
  overflow: hidden;
}
#tp-myplayer .mp-bar i { display: block; height: 100%; background: var(--amber); }
/* Why there is no number here, said out loud rather than left as a gap. */
#tp-myplayer .mp-note { font-size: 10.5px; color: #7f9aa0; font-style: italic; }

/* The one card that takes the leftover height rather than its own. */
#tp-dock > .dk-grow { flex: 1 1 auto; }
#tp-dock > .dk-grow.dk-collapsed { flex: 0 0 auto; }

/* Folded away: the title bar is all that is left, and the stack closes up.
   Both forms of each rule are needed because the pane holding the title bar is
   sometimes the panel itself (the seat panel) and sometimes an element inside
   it (the inspector's .ins-panel, the action field's .hv-body). */
.dk-collapsed .dk-pane > :not(.dk-head),
.dk-collapsed.dk-pane > :not(.dk-head) { display: none; }

.dk-collapsed .dk-pane,
.dk-collapsed.dk-pane { padding-bottom: 0; }

.dk-collapsed .dk-head { border-bottom-color: transparent; }

.dk-min {
  flex: 0 0 auto;
  align-self: center;
  margin-left: auto;
  width: 20px;
  height: 18px;
  font-family: var(--mono);
  font-size: 10px;
  line-height: 1;
  color: var(--text-dim);
  background: transparent;
  border: 1px solid var(--teal-line);
  border-radius: 3px;
  cursor: pointer;
}

.dk-min:hover,
.dk-min:focus-visible { color: var(--amber); border-color: var(--amber-dim); outline: none; }

/* The climate tracker folds to its existing round/header bar in every game. */
#heritage-world.climate-folded > :not(.climate-panel-head) { display: none; }
#heritage-world .climate-panel-head { align-items: center; }
#heritage-world .dk-min { padding: 0; color: inherit; }

/* ------------------------------------------------- taken out of the column
   Sam's note G21. The column is still the default; this is what a card looks
   like once a player has dragged it somewhere of their own. Position, left,
   top and width are set inline by js/dock.js, because three of these panels
   are positioned by id in three different stylesheets and an id beats a class
   whichever file loads last. What is left here is what it looks like: over the
   table rather than in the column, and visibly picked up. */
.dk-float {
  z-index: 25;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.66);
  border-color: var(--amber-dim);
}

.dk-float.dk-grow { max-height: min(60vh, 520px); }

/* The title bar is the handle. It says so on hover, and it stops the browser
   selecting the panel's own words while a drag is in progress. */
.dk-head.dk-drag,
.ro-head.dk-drag { cursor: grab; touch-action: none; }
body.dk-dragging { cursor: grabbing; user-select: none; }
body.dk-dragging .dk-head.dk-drag,
body.dk-dragging .ro-head.dk-drag { cursor: grabbing; }

/* The way back, shown only while a panel is out of the column. */
.dk-redock {
  flex: 0 0 auto;
  align-self: center;
  width: 20px;
  height: 18px;
  font-family: var(--mono);
  font-size: 10px;
  line-height: 1;
  color: var(--amber-dim);
  background: transparent;
  border: 1px solid var(--amber-dim);
  border-radius: 3px;
  cursor: pointer;
}

.dk-redock[hidden] { display: none; }
.dk-redock:hover,
.dk-redock:focus-visible { color: var(--amber); border-color: var(--amber); outline: none; }

/* ------------------------------------------------------- show all windows
   The escape hatch (Sam's note G21): unfold everything, unhide anything with
   something to say, and put it all back in the column. It sits beside the
   roster in the same top-right corner and steps aside for it exactly as
   #net-badge does, so the three never stack. */
#tp-showall {
  position: fixed;
  top: 16px;
  right: 20px;
  z-index: 24;
  width: 26px;
  height: 26px;
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1;
  color: var(--text-dim);
  background: rgba(6, 22, 27, 0.94);
  border: 1px solid var(--teal-line);
  border-radius: 5px;
  cursor: pointer;
  transition: right 160ms ease, color 120ms ease;
}

#tp-showall:hover,
#tp-showall:focus-visible { color: var(--amber); border-color: var(--amber-dim); outline: none; }

/* The roster's width as a variable, so every neighbour clears it at whatever
   width it has (M2-08: the Players box is wider with the round tracker on). */
body.tp-roster { --ro-w: min(88vw, 232px); }
@media (max-width: 720px) { body.tp-roster { --ro-w: min(60vw, 190px); } }
body.tp-roster #tp-showall { right: calc(var(--ro-w) + 30px); }
/* #net-badge had this corner to itself; the widget is now always in it, so the
   badge starts one widget further left. The roster case is handled beside the
   badge's own rule further down, where the roster's width is already known. */
#net-badge { right: 54px; }

/* -------------------------------------------------------- inspector panel */

/* A card in the dock (js/dock.js), so it is laid out with the seat panel and
   the action field rather than positioned over them. Fixed in the reading
   sense: it is something to read, not a tooltip to chase. */
#tp-inspect {
  display: flex;
  flex: 0 1 auto;
  min-height: 0;
}

/* A thing just inspected is what the player is looking at, so it keeps room
   to be read: its title, whose it is and the start of what it says. Without a
   floor it was the one card in the column allowed to shrink, and with My player
   open at 768px it was squeezed to a title bar and two lines (the camera and
   panel pass). My player gives way instead, down to its own essentials. */
#tp-dock > #tp-inspect:not(.dk-collapsed) { min-height: min(40vh, 320px); }
#tp-dock > #tp-myplayer:not(.dk-collapsed) { flex: 0 1 auto; min-height: 150px; }

#tp-inspect[hidden] { display: none; }

.ins-panel {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
  border: 1px solid var(--teal-line);
  border-radius: 8px;
  background: rgba(6, 22, 27, 0.94);
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(6px);
}

.ins-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 12px 14px 10px;
  border-bottom: 1px solid var(--teal-line);
}

.ins-head .ins-title {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text);
}

.ins-head .ins-title::first-letter { color: var(--amber); }

.ins-close {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 18px;
  line-height: 1;
  color: var(--text-dim);
  background: none;
  border: none;
  cursor: pointer;
}
.ins-close:hover { color: var(--amber); }

.ins-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 10px 14px 12px;
}

.ins-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}

/* Why this thing matters to the question on the strip (js/inspect.js). Read
   only: it says which button answers, and never becomes one. */
.ins-decision {
  margin-top: 10px;
  padding: 8px 10px;
  border: 1px solid var(--amber-dim);
  border-radius: 6px;
  background: rgba(255, 154, 60, 0.07);
}
.ins-decision[hidden] { display: none; }
.ins-decision b {
  display: block;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--amber-dim);
}
.ins-decision p { margin: 4px 0 0; font-size: 12px; line-height: 1.45; color: var(--text); }
.ins-decision .ins-decision-how { font-size: 11px; color: var(--text-dim); }

.ins-tag {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--amber-dim);
  border: 1px solid var(--teal-line);
  border-radius: 3px;
  padding: 2px 6px;
}

/* The card, drawn through the same painter as the double-click enlarge. */
.ins-face {
  display: block;
  width: 196px;
  height: auto;
  aspect-ratio: 5 / 7;
  margin: 10px auto 2px;
  border: 1px solid var(--amber-dim);
  border-radius: 8px;
  background: var(--petrol);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}

.ins-face[hidden] { display: none; }

/* The specimen turntable (design review row 5): the piece itself, dragged to
   turn, with a pinned piece beside it when comparing. */
.ins-specimen { position: relative; margin: 10px 0 2px; }
.ins-specimen[hidden] { display: none; }
.ins-stage { display: flex; gap: 6px; }
.ins-turntable {
  flex: 1 1 0; min-width: 0; width: 100%; aspect-ratio: 1;
  border: 1px solid var(--teal-line); border-radius: 6px; background: #0d1b1f;
  cursor: grab; touch-action: none;
}
.ins-turntable:active { cursor: grabbing; }
.ins-turntable:focus-visible { outline: 2px solid var(--amber); outline-offset: 1px; }
.ins-turntable[hidden] { display: none; }
/* A short window (1366 x 768 with My player open left the Inspector 307px):
   the piece turns in a smaller square, letterboxed rather than stretched, so
   the first paragraph still fits above the fold (UX-LAYOUT-06). */
@media (max-height: 820px) {
  .ins-turntable { max-height: 140px; object-fit: contain; }
}
.ins-lead[hidden] { display: none; }
#tp-inspect.ins-has-lead .ins-text > p:first-child { display: none; }
.ins-turn-hint {
  position: absolute; left: 8px; bottom: 6px; pointer-events: none;
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-dim);
}
.ins-consequence {
  margin: 10px 0 0; padding: 7px 9px; border-left: 2px solid #5fe3f0; background: rgba(95, 227, 240, 0.07);
  font-family: var(--sans); font-size: 12.5px; line-height: 1.45; color: var(--text);
}
.ins-consequence[hidden] { display: none; }
.ins-actions { display: flex; gap: 6px; margin-top: 10px; }
.ins-actions button, .ins-pinned {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--amber-dim); background: none; border: 1px solid var(--teal-line); border-radius: 3px;
  padding: 3px 8px; cursor: pointer;
}
.ins-actions button:hover:not(:disabled), .ins-pinned:hover { color: var(--amber); }
.ins-actions button[aria-pressed="true"] { color: var(--amber); border-color: var(--amber-dim); }
.ins-actions button:disabled { opacity: 0.45; cursor: default; }
.ins-actions .ins-focus { float: none !important; margin: 0 !important; font-family: var(--mono) !important; font-size: 10px !important; padding: 3px 8px !important; }
.ins-pins { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.ins-pins[hidden] { display: none; }
.ins-pinned { text-transform: none; letter-spacing: 0; font-size: 10.5px; }
.ins-pinned.ins-pinned-on { color: var(--amber); border-color: var(--amber-dim); }
.ins-rules { margin-top: 10px; }
.ins-rules > summary {
  cursor: pointer; font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--amber-dim);
}
.ins-rules > summary:hover { color: var(--amber); }

.ins-text p, .ins-lead p {
  margin-top: 8px;
  font-family: var(--sans);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text);
}

.ins-text .ins-flavour {
  font-style: italic;
  color: var(--text-dim);
}

.ins-meta {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px 10px;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--teal-line);
  font-family: var(--mono);
  font-size: 10.5px;
  line-height: 1.6;
}

.ins-meta:empty { display: none; }

.ins-meta dt {
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.ins-meta dd { color: var(--text); }

.ins-foot {
  padding: 8px 14px 9px;
  border-top: 1px solid var(--teal-line);
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.05em;
  color: var(--text-dim);
}

#tp-inspect kbd {
  display: inline-block;
  min-width: 14px;
  padding: 0 3px;
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 700;
  line-height: 14px;
  text-align: center;
  color: var(--amber);
  background: var(--petrol);
  border: 1px solid var(--teal-line);
  border-bottom-color: var(--amber-dim);
  border-radius: 3px;
}

/* Understated toast showing the last rolled die value, floated near the die. */
#tp-dice-toast {
  position: fixed;
  transform: translate(-50%, -140%);
  padding: 2px 8px;
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 700;
  color: var(--amber);
  background: rgba(6, 22, 27, 0.82);
  border: 1px solid var(--amber-dim);
  border-radius: 4px;
  pointer-events: none;
  z-index: 40;
}
#tp-dice-toast[hidden] { display: none; }

/* ------------------------------------------------------------- the roster */

/* Who is at this table, top right (js/roster.js, play-test note G12). Its own
   corner rather than a dock card: the left column is for the thing you are
   reading, and "who is who" has to stay answerable while you read it.

   Two neighbours share this edge. #net-badge normally sits at top 16 / right
   20, so it steps aside while the roster is up (body.tp-roster, set by the
   roster itself). #tp-aid is a full-height drawer that slides in over this
   side, so the roster steps left by the drawer's width while it is open, which
   is exactly what #tp-zoom does. The zoom bar is at top: 50%, and the height
   cap below keeps the roster clear of it on a short window. */
#tp-roster {
  position: fixed;
  top: 16px;
  right: 20px;
  z-index: 24;
  width: min(88vw, 232px);
  max-height: min(42vh, 320px);
  display: flex;
  flex-direction: column;
  border: 1px solid var(--teal-line);
  border-radius: 8px;
  background: rgba(6, 22, 27, 0.94);
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(6px);
  transition: right 160ms ease;
}

#tp-roster[hidden] { display: none; }
#tp-roster.ro-shifted { right: calc(min(94vw, 360px) + 20px); }

/* The badge belongs to online rooms and the roster to solo play, so they should
   never both be up. Belt and braces all the same: one of them moving is better
   than two of them stacked. */
body.tp-roster #net-badge { right: calc(var(--ro-w) + 66px); }

.ro-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px 7px;
  border-bottom: 1px solid var(--teal-line);
}

.ro-title {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text);
}

.ro-title::first-letter { color: var(--amber); }

/* Where the game is, on the title line so the panel does not grow
   (playtest FLOW-01; the full picture is its hover text). */
.ro-head .ro-state {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  cursor: help;
}
.ro-head .ro-state[hidden] { display: none; }
.ro-head .ro-state b { color: var(--amber); font-weight: 700; }
.ro-row.ro-await .ro-dot { background: transparent; box-shadow: inset 0 0 0 1.5px var(--amber); }

.ro-min {
  flex: 0 0 auto;
  margin-left: auto;
  width: 20px;
  height: 18px;
  font-family: var(--mono);
  font-size: 10px;
  line-height: 1;
  color: var(--text-dim);
  background: transparent;
  border: 1px solid var(--teal-line);
  border-radius: 3px;
  cursor: pointer;
}

.ro-min:hover,
.ro-min:focus-visible { color: var(--amber); border-color: var(--amber-dim); outline: none; }

#tp-roster.ro-folded .ro-body { display: none; }
#tp-roster.ro-folded .ro-head { border-bottom-color: transparent; }

.ro-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  padding: 5px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

/* One seat. --sc is that seat's colour and --si the ink that reads on it, both
   set inline from js/seats.js so the swatch and the panel can never disagree
   about what colour a seat is. */
.ro-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 4px 6px;
  text-align: left;
  color: var(--text);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 5px;
  cursor: pointer;
  font-family: var(--sans);
}

.ro-row:hover,
.ro-row:focus-visible { border-color: var(--teal-line); background: rgba(16, 48, 56, 0.6); outline: none; }

.ro-swatch {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border-radius: 4px;
  background: var(--sc);
  color: var(--si);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  line-height: 20px;
  text-align: center;
  /* A hairline in the seat's own colour, lightened by the panel behind it: the
     swatch has to read as a colour sample even against a pale seat colour. */
  box-shadow: 0 0 0 1px rgba(6, 22, 27, 0.9);
}

.ro-who {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.ro-name {
  font-size: 12px;
  font-weight: 600;
  line-height: 1.15;
  color: var(--sc);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ro-house {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.04em;
  line-height: 1.2;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ro-house.ro-muted { opacity: 0.62; font-style: italic; }

/* A revealed Agenda (public once face up), on the seat's row. */
.ro-agenda {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.04em;
  line-height: 1.2;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The seat the table is waiting on. A dot rather than a colour change, because
   the row's colour is already saying something else. */
.ro-dot {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: transparent;
}

.ro-row.ro-turn .ro-dot { background: var(--amber); box-shadow: 0 0 6px var(--amber-dim); }
/* Your own row: outlined in your colour and tagged, so the one seat that is
   yours is unmistakable (play-test F3-002, 30 September 2026). */
.ro-row.ro-you { background: rgba(16, 48, 56, 0.42); border-color: var(--sc); box-shadow: inset 3px 0 0 var(--sc); }
.ro-row.ro-you .ro-name { font-weight: 700; }
/* An online seat that has lost its connection (play-test E18). */
#tp-roster .ro-away { font: 9.5px/1.2 var(--mono); color: var(--amber, #ff9a3c); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ro-youtag {
  flex: 0 0 auto;
  padding: 1px 5px;
  border-radius: 3px;
  background: var(--sc);
  color: var(--si);
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Vested Interests: each seat's Capital and free Operatives, public at the
   table (Package C19, play-test F3-055). One short line on the right of the
   row, so the row is no taller than it was. A coin for Capital and
   a hex drone in the seat's colour for the Operatives free this round, "/3"
   being the seat's crew. At none free the Operative count goes amber: that
   seat cannot defend a Takeover this round. Influence is never shown. */
.ro-res {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  cursor: help;
}
.ro-res > span { display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; }
.ro-res small { font-size: 9px; font-weight: 400; color: var(--text-dim); }
.ro-ico { display: inline-block; flex: 0 0 auto; width: 8px; height: 8px; }
.ro-ico-cap { border-radius: 50%; background: #e2b84a; box-shadow: inset 0 0 0 1.5px #a07a1c; }
.ro-ico-ops {
  width: 8px;
  height: 9px;
  background: var(--sc);
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
}
.ro-res.ro-res-none .ro-ops { color: var(--amber); }
.ro-res.ro-res-none .ro-ico-ops { background: transparent; box-shadow: inset 0 0 0 1.5px var(--amber); clip-path: none; border-radius: 2px; }

@media (max-width: 720px) {
  #tp-roster { width: min(60vw, 190px); }
  #tp-roster.ro-shifted { display: none; }
}

/* ------------------------------------------------- the inspector's owner */

/* The first thing the inspector says about an owned piece (play-test note G12:
   "clicking any piece should say which player it belongs to"). It sits above
   the tags, in the owner's own seat colour, so the answer is legible before a
   word of it has been read. */
.ins-owner {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 8px;
  padding: 6px 8px;
  border: 1px solid var(--teal-line);
  border-left: 3px solid var(--sc, var(--seat-none));
  border-radius: 5px;
  background: rgba(16, 48, 56, 0.42);
}

.ins-owner-chip {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  border-radius: 4px;
  background: var(--sc, var(--seat-none));
  box-shadow: 0 0 0 1px rgba(6, 22, 27, 0.9);
  /* The seat's glyph on its colour (design review row 9). */
  color: var(--si, #06161b);
  font: 10px/16px system-ui, sans-serif;
  text-align: center;
}
.ro-swatch { position: relative; }
.ro-glyph {
  position: absolute; right: -7px; bottom: -6px; font: normal 10px/1 system-ui, sans-serif;
  color: var(--sc); text-shadow: 0 0 2px #06161b, 0 0 2px #06161b, 0 0 1px #06161b;
}

.ins-owner-text {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--mono);
  font-size: 10.5px;
  line-height: 1.35;
  letter-spacing: 0.03em;
  color: var(--text);
}

.ins-owner-text b { color: var(--sc, var(--text)); font-weight: 700; }
.ins-owner-text span { display: block; color: var(--text-dim); font-size: 9.5px; }

/* Nobody's. Kept visually quieter than an owned line, and neutral grey rather
   than any seat's colour, so "unowned" is its own state and not a sixth player. */
.ins-owner.ins-owner-none { border-left-color: var(--seat-none); background: rgba(16, 48, 56, 0.22); }

/* Private online rooms (js/online/online-panel.js). */
.tp-online-entry .tp-online-waiting { margin: 8px 0 4px; font-weight: 600; }
.tp-online-wait-overlay { position: fixed; inset: 0; z-index: 100; display: grid; place-items: center;
  padding: 20px; box-sizing: border-box; background: #03111799; pointer-events: auto; }
.tp-online-wait-overlay > .tp-online-entry { width: min(640px, 100%); max-height: calc(100dvh - 40px);
  overflow-y: auto; box-sizing: border-box; padding: 24px; margin: 0; border: 1px solid #4b7279;
  border-radius: 14px; background: #10272e; color: #edf5f4; box-shadow: 0 16px 60px #0009; }
.tp-online-countdown { font-size: 1.25rem; font-weight: 700; color: #b6ece0; }
.tp-online-confirm { margin: auto; max-width: min(460px, calc(100vw - 48px)); padding: 24px; border: 1px solid #83c4ba;
  border-radius: 12px; background: #10272e; color: #edf5f4; font: 16px/1.5 system-ui, sans-serif; }
.tp-online-confirm::backdrop { background: #0009; }
.tp-online-countdown-announcement { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
/* An invitation's focused view (playtest JOIN-01): the cover and this room's
   box only, so the invited player meets one Join button, not the whole menu. */
.net-panel.tp-invite-view > :not(.tp-lobby-cover):not(.tp-online-entry):not(.tp-online-wait-overlay):not(.tp-choices) { display: none !important; }
/* The online block now sits inside the lobby's third choice: in the invitation
   view only that block shows, without the choice heads around it. */
.net-panel.tp-invite-view .tp-choices > .tp-choice:not([data-choice="online"]),
.net-panel.tp-invite-view .tp-choice-head,
.net-panel.tp-invite-view .tp-choice-body > :not(.tp-online-entry) { display: none !important; }
.net-panel.tp-invite-view .tp-choices,
.net-panel.tp-invite-view .tp-choice[data-choice="online"] .tp-choice-body { display: block !important; }
.net-panel.tp-invite-view .tp-choice { border: 0; background: none; padding: 0; }
.tp-online-entry .tp-online-seats { list-style: none; margin: 6px 0; padding: 0; }
.tp-online-entry .tp-online-seats li { display: flex; gap: 6px; align-items: center; padding: 2px 0; }
.tp-online-secret, .tp-room-link { display: block; overflow-wrap: anywhere; user-select: all; padding: 6px 8px; margin: 6px 0;
  background: rgba(0, 0, 0, 0.35); border-radius: 4px; font-size: 12px; }
.tp-online-share { flex-wrap: wrap; align-items: center; }
.tp-online-share [role="status"] { flex-basis: 100%; min-height: 1.3em; }
/* The badge sat over the player aid's close button in online games (UI-04), so
   it steps left of the aid while the aid is open. */
body:has(#tp-aid:not([hidden])) .tp-online-badge { right: calc(min(94vw, 360px) + 8px); }
.tp-online-badge { position: fixed; top: 8px; right: 8px; z-index: 40; padding: 3px 9px; border-radius: 10px;
  font: 12px/1.4 system-ui, sans-serif; color: #f4efe3; background: rgba(20, 40, 38, 0.85); pointer-events: none; }
.tp-online-badge[data-status="saving"], .tp-online-badge[data-status="reconnecting"], .tp-online-badge[data-status="connecting"] { background: rgba(120, 88, 20, 0.9); }
.tp-online-badge[data-status="replaced"], .tp-online-badge[data-status="revoked"], .tp-online-badge[data-status="closed"], .tp-online-badge[data-status="outdated"] { background: rgba(120, 30, 30, 0.9); }

/* In room play (js/online/online-panel.js): the organiser's in-game panel, and
   the table display, which shows the board alone on a shared screen. */
.tp-inroom { margin-top: 8px; }
/* Playing over a video call (F3-006): the lobby's how-to, folded until asked. */
.tp-online-call { margin: 8px 0; padding: 6px 10px; border: 1px solid rgba(244, 239, 227, 0.25); border-radius: 6px; font-size: 13px; line-height: 1.45; }
.tp-online-call summary { cursor: pointer; font-weight: 600; }
.tp-online-call ol { margin: 6px 0 2px; padding-left: 20px; }
.tp-online-call li { margin: 3px 0; }
.tp-inroom-bar { position: fixed; top: 6px; right: 150px; z-index: 45; width: min(360px, calc(100vw - 16px));
  font: 13px/1.4 system-ui, sans-serif; color: #f4efe3; pointer-events: none; }
.tp-inroom-bar > * { pointer-events: auto; }
.tp-inroom-bar button, .tp-inroom-bar select { font: 12px/1.3 system-ui, sans-serif; color: #f4efe3; cursor: pointer;
  padding: 4px 9px; border-radius: 10px; border: 1px solid rgba(244, 239, 227, 0.35); background: rgba(20, 40, 38, 0.9); }
.tp-inroom-bar button:hover { border-color: rgba(244, 239, 227, 0.7); }
.tp-inroom-open { float: right; }
.tp-inroom-body { clear: both; margin-top: 4px; padding: 8px 10px; border-radius: 6px; background: rgba(20, 40, 38, 0.95);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.4); }
.tp-inroom-body .tp-solo-opts { display: flex; flex-wrap: wrap; gap: 4px; }
.tp-inroom-body .net-sub { margin: 4px 0; font-size: 12px; color: rgba(244, 239, 227, 0.8); }
/* The room during a game (F3-048): its link for everyone, End room for the
   organiser. It takes the In room play button's place; that one steps left. */
.tp-room-bar { position: fixed; top: 6px; right: 150px; z-index: 45; width: min(360px, calc(100vw - 16px));
  font: 13px/1.4 system-ui, sans-serif; color: #f4efe3; pointer-events: none; }
.tp-room-bar > * { pointer-events: auto; }
.tp-room-bar button { font: 12px/1.3 system-ui, sans-serif; color: #f4efe3; cursor: pointer;
  padding: 4px 9px; border-radius: 10px; border: 1px solid rgba(244, 239, 227, 0.35); background: rgba(20, 40, 38, 0.9); }
.tp-room-bar button:hover { border-color: rgba(244, 239, 227, 0.7); }
.tp-room-open { float: right; }
.tp-room-body { clear: both; margin-top: 4px; padding: 8px 10px; border-radius: 6px; background: rgba(20, 40, 38, 0.95);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.4); }
.tp-room-body .tp-solo-opts { display: flex; flex-wrap: wrap; gap: 4px; }
.tp-room-body .net-sub { margin: 4px 0; font-size: 12px; color: rgba(244, 239, 227, 0.8); }
body:has(.tp-room-bar:not([hidden])) .tp-inroom-bar { right: 260px; }
/* Both rules below are kept (#144 M2-08 and #142 M1-11). Where the Players box is
   docked and the window is over 720px, #142's :has() rules are the more specific and
   set the chips' right edge; #144's still limit the opened Room panel's width, and
   place the chips when the box floats or the window is narrow. */
/* M2-08: with the Players box up, the Room and In room buttons sit to its left,
   clear of its title and of the show-all button, and the opened Room panel opens
   leftwards from there instead of over the box. */
body.tp-roster .tp-room-bar, body.tp-roster .tp-inroom-bar { right: calc(var(--ro-w) + 66px); width: min(360px, calc(100vw - var(--ro-w) - 82px)); }
body.tp-roster:has(.tp-room-bar:not([hidden])) .tp-inroom-bar { right: calc(var(--ro-w) + 66px + 112px); }
.tp-online-colour-prompt { margin: 6px 0; font-weight: 700; color: #ffd77a; }
/* With the Players box up, the room chips stand to its left rather than over its
   heading (E2E M1-11: at 1400 x 900 "In room play: on" and the room code sat on
   "PLAYERS"). The box is 300px wide at its right edge gap of 20px. */
@media (min-width: 721px) {
  body:has(#tp-roster:not([hidden]):not(.dk-float)) .tp-inroom-bar,
  body:has(#tp-roster:not([hidden]):not(.dk-float)) .tp-room-bar { right: 340px; }
  body:has(#tp-roster:not([hidden]):not(.dk-float)):has(.tp-room-bar:not([hidden])) .tp-inroom-bar { right: 470px; }
}
/* A player who dropped out during play: the question to everyone else, and
   who the computer is playing for. Top centre, above the table, below dialogs. */
.tp-standin { position: fixed; top: 48px; left: 50%; transform: translateX(-50%); z-index: 46;
  width: min(420px, calc(100vw - 32px)); font: 14px/1.4 system-ui, sans-serif; color: #f4efe3; }
.tp-standin-row { margin-bottom: 6px; padding: 10px 12px; border-radius: 8px; background: rgba(20, 40, 38, 0.96);
  border: 1px solid rgba(244, 239, 227, 0.35); box-shadow: 0 4px 18px rgba(0, 0, 0, 0.45); }
.tp-standin-row p { margin: 0 0 6px; }
.tp-standin-row .net-sub, .tp-standin-report .net-sub { font-size: 12px; color: rgba(244, 239, 227, 0.8); margin: 4px 0 0; }
.tp-standin-computer { padding: 6px 10px; background: rgba(20, 40, 38, 0.85); }
.tp-standin-computer p { margin: 0; font-size: 13px; }
.tp-standin .tp-solo-opts { display: flex; flex-wrap: wrap; gap: 6px; }
.tp-standin button { font: 13px/1.3 system-ui, sans-serif; color: #f4efe3; cursor: pointer; padding: 5px 12px;
  border-radius: 10px; border: 1px solid rgba(244, 239, 227, 0.45); background: rgba(40, 70, 64, 0.95); }
.tp-standin button.quiet { background: transparent; }
.tp-standin-report { top: 80px; z-index: 47; padding: 12px 14px; border-radius: 8px; background: rgba(20, 40, 38, 0.97);
  border: 1px solid rgba(244, 239, 227, 0.4); box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5); }
.tp-standin-report h4 { margin: 0 0 6px; font-size: 15px; }
.tp-standin-report .tp-standin-moves { max-height: 38vh; overflow-y: auto; }
.tp-standin-report ul { margin: 6px 0 10px; padding-left: 18px; max-height: 40vh; overflow: auto; }
.tp-move { margin-top: 8px; }
body.tp-table-display > :not(#app):not(.tp-table-overlay):not(.tp-table-caption):not(.tp-online-badge):not(.tp-table-sound):not(.tp-table-speech):not(#tp-solo-end):not(#tp-roster) { display: none !important; }
/* Vested Interests keeps the Players box on the shared screen (Sam, 1 October
   2026, row 12 option B): public counts only (js/roster.js). Top right, under
   the online badge, in the empty margin beside the board and clear of the round
   card (top left), the caption (bottom centre) and the sound bar (bottom right).
   Larger on a big screen, read from across a table. Other games: hidden. */
body.tp-table-display:not(.tp-table-players) > #tp-roster { display: none !important; }
body.tp-table-display.tp-table-players #tp-roster { top: 44px; right: 8px; max-height: calc(100vh - 140px); }
body.tp-table-display.tp-table-players #tp-roster .ro-row { cursor: default; }
@media (min-width: 1600px) and (min-height: 900px) {
  body.tp-table-display.tp-table-players #tp-roster { zoom: 1.3; top: 34px; right: 6px; max-height: calc((100vh - 140px) / 1.3); }
}
/* The captions switch on the sound bar: off hides the narration caption only. */
body.tp-captions-off .tp-table-speech { display: none !important; }
.tp-table-sound { position: fixed; right: 8px; bottom: 8px; z-index: 50; display: flex; gap: 6px; align-items: center; }
.tp-table-sound button, .tp-table-sound select { font: 14px/1.3 system-ui, sans-serif; color: #f4efe3; cursor: pointer;
  padding: 8px 12px; border-radius: 12px; border: 1px solid rgba(244, 239, 227, 0.4); background: rgba(20, 40, 38, 0.9); }
.tp-table-sound button[hidden] { display: none; }
.tp-table-sound-state { font: 14px/1.3 system-ui, sans-serif; color: #f4efe3; padding: 8px 12px; border-radius: 12px; background: rgba(20, 40, 38, 0.9); }
.tp-table-sound-state[hidden] { display: none; }
/* The session survey is each person's own, asked on their own device, not on the shared screen. */
body.tp-table-display #tp-feedback-end { display: none; }
/* The commentary caption (F3-051): the line the table display last said to the
   room, on screen as well as aloud, above the sound bar and clear of every
   click. Empty until the first line. */
.tp-table-speech { position: fixed; left: 50%; bottom: 64px; transform: translateX(-50%); z-index: 45;
  width: max-content; max-width: min(900px, calc(100vw - 32px)); padding: 10px 16px; border-radius: 8px;
  font: 19px/1.4 system-ui, sans-serif; text-align: center; color: #f4efe3; background: rgba(20, 40, 38, 0.92);
  pointer-events: none; }
.tp-table-speech:empty { display: none; }
.tp-table-overlay { position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 50; max-width: 80vw;
  padding: 14px 20px; border-radius: 8px; text-align: center; font: 18px/1.4 system-ui, sans-serif;
  color: #f4efe3; background: rgba(20, 40, 38, 0.9); }
.tp-table-overlay[hidden] { display: none; }
.tp-table-caption { position: fixed; left: 8px; bottom: 8px; z-index: 40; font: 12px/1.4 system-ui, sans-serif;
  color: rgba(244, 239, 227, 0.75); pointer-events: none; }
/* The waiting box has left .net-panel, so it owns readable controls and copy. */
.tp-online-wait-overlay > .tp-online-entry { font: 15px/1.5 system-ui, sans-serif; }
.tp-online-wait-overlay .tp-online-entry h3 { font-size: 17px; letter-spacing: .08em; margin: 0 0 12px; }
.tp-online-wait-overlay .tp-online-entry p { font: 14px/1.5 system-ui, sans-serif; margin: 10px 0; letter-spacing: normal; color: #c2d6d9; }
.tp-online-wait-overlay .tp-online-entry .tp-online-waiting { font-size: 17px; color: #edf5f4; }
.tp-online-wait-overlay .tp-online-entry .tp-online-countdown { font-size: 21px; font-weight: 700; color: #b6ece0; }
.tp-online-wait-overlay .tp-online-seats li { padding: 5px 0; flex-wrap: wrap; }
.tp-online-wait-overlay .tp-solo-opts { gap: 8px; flex-wrap: wrap; margin: 12px 0; }
.tp-online-wait-overlay button, .tp-online-wait-overlay select {
  font: 14px/1.4 system-ui, sans-serif; color: #edf5f4; background: #193840;
  border: 1px solid #64868b; border-radius: 6px; padding: 8px 12px; cursor: pointer;
}
.tp-online-wait-overlay button:hover { border-color: #b6ece0; background: #234950; }
.tp-online-wait-overlay button:focus-visible, .tp-online-wait-overlay select:focus-visible { outline: 2px solid #b6ece0; outline-offset: 3px; }
.tp-online-wait-overlay button:disabled { opacity: .55; cursor: default; }
.tp-online-wait-overlay .tp-online-entry .tp-solo-go { font: 600 14px/1.4 system-ui, sans-serif; letter-spacing: normal; text-transform: none; }
.tp-online-wait-overlay button.quiet { background: transparent; }
.tp-online-wait-overlay .tp-online-seats .net-sub { font-size: 13px; }

/* Public round-card caption on the in-room board; never intercepts play. */
.tp-table-round-card { position: fixed; top: 48px; left: 8px; max-width: min(620px, calc(100vw - 40px));
  padding: 10px 12px; border-radius: 8px; font: 16px/1.4 system-ui, sans-serif;
  color: #f4efe3; background: rgba(20, 40, 38, 0.94); }
.tp-table-round-card[hidden] { display: none; }
.tp-table-sound button:disabled { opacity: .5; cursor: default; }

/* ------------------------------------------- the start screen (lobby plan) */
/* Three choices, one name, settings out of the way (docs/lobby-simplify-
   2026-10-02/PLAN.md rows 2, 3, 7 and 13). */
.tp-choices { display: flex; flex-direction: column; gap: 8px; margin: 14px 0 4px; }
.tp-choices[hidden], .tp-in-game[hidden], .tp-continue-save[hidden], .tp-load-slot[hidden] { display: none; }
.tp-choice { border: 1px solid var(--teal-line); border-radius: 6px; background: rgba(16, 48, 56, 0.35); }
.tp-choice.active { border-color: var(--amber-dim); background: rgba(16, 48, 56, 0.6); }
.net-panel .tp-choice-head {
  display: grid; grid-template-columns: 16px 1fr; column-gap: 8px; align-items: center;
  width: 100%; text-align: left; background: transparent; border: 0; padding: 9px 12px;
}
.tp-choice-dot { width: 12px; height: 12px; border-radius: 50%; border: 1px solid var(--teal-line); box-sizing: border-box; }
.tp-choice.active .tp-choice-dot { border: 4px solid var(--amber); }
.tp-choice-title { color: var(--text); font-size: 13px; letter-spacing: 0.04em; }
.tp-choice.active .tp-choice-title { color: var(--amber); }
.tp-choice-sub { grid-column: 2; font-size: 11px; line-height: 1.45; color: var(--text-dim); letter-spacing: 0; text-transform: none; }
.tp-choice-off .tp-choice-head { cursor: not-allowed; opacity: 0.55; }
.tp-choice-body { padding: 0 12px 10px; }
.tp-choice-body[hidden] { display: none; }
/* Inside a choice the blocks lose their own frame and heading: the card is the frame. */
#net-lobby .tp-choice .tp-solo-entry { margin: 0; padding: 0; border: 0; background: none; }
.tp-choice .tp-online-entry > h3 { display: none; }
.net-panel.tp-invite-view .tp-choice .tp-online-entry > h3 { display: block; }
.tp-solo-names { display: flex; flex-wrap: wrap; gap: 6px 10px; margin-top: 8px; }
/* "People" on one screen is not a <label>: the host form's People keeps that name for its lanes. */
.tp-solo-opts .tp-solo-people { display: flex; align-items: center; gap: 5px; font-family: var(--mono); font-size: 10px;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-dim); }
.tp-solo-opts .tp-solo-people[hidden] { display: none; }
.tp-solo-names[hidden] { display: none; }
.tp-solo-seat1 { font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-dim); }
.tp-solo-seat1 b { color: var(--amber); text-transform: none; letter-spacing: 0; }
.tp-choice-inroom { font-size: 11px; }
.net-panel .tp-free-table, .net-panel .tp-another-game, .net-panel .tp-choice-inroom button, .net-panel .tp-solo-buy {
  background: transparent; border: 0; padding: 2px 0; color: var(--amber); text-decoration: underline; text-underline-offset: 2px;
}

/* Advanced: closed by default; the summary names every non-default. */
.tp-advanced { margin: 10px 0 0; border-top: 1px dashed var(--teal-line); padding-top: 6px; }
.tp-advanced > summary { cursor: pointer; font-family: var(--mono); font-size: 11px; color: var(--text-dim); line-height: 1.5; }
.tp-advanced > summary b { color: var(--text); font-weight: 700; }
.tp-advanced-sum { color: var(--amber); }
.tp-advanced-body { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.tp-advanced-row { display: grid; grid-template-columns: 120px 1fr; gap: 8px; align-items: start; font-size: 11px; }
.tp-advanced-label { font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-dim); padding-top: 4px; }
.tp-advanced-cell { display: flex; flex-direction: column; gap: 3px; color: var(--text); }
.tp-advanced-cell select, .tp-advanced-cell input[type="text"] {
  align-self: flex-start; font-family: var(--mono); font-size: 11px; color: var(--text);
  background: var(--petrol-deep); border: 1px solid var(--teal-line); border-radius: 3px; padding: 4px 6px; width: auto;
}
.tp-advanced-note { color: var(--text-dim); font-size: 10px; line-height: 1.45; }
.tp-adv-switch { display: flex; gap: 6px; align-items: center; }
.tp-adv-deal-cell { display: flex; flex-direction: column; gap: 3px; }

/* The rules in force, from the engine's own observation (plan 3.4). */
.tp-rules-in-force { margin: 8px 0 0; font-size: 11px; line-height: 1.45; color: #b6ece0; }
.tp-rules-in-force[hidden] { display: none; }

/* While a game is on, Menu opens on Continue this game (row 13). */
.tp-in-game { margin: 14px 0 6px; }
.tp-in-game .tp-continue-game { min-width: 0; padding: 9px 20px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--petrol-deep); background: var(--amber); border: 1px solid var(--amber); }

/* The foot: links, the free table (dev), Settings and Developer. */
.tp-lobby-foot { margin-top: 12px; }
.tp-lobby-foot > details { margin-top: 8px; border-top: 1px solid var(--teal-line); padding-top: 6px; }
.tp-lobby-foot > details > summary { cursor: pointer; font-family: var(--mono); font-size: 11px; letter-spacing: 0.08em; color: var(--text-dim); }
.tp-fold-hint { color: #4d6f78; letter-spacing: 0; }
.tp-dev-only[hidden] { display: none !important; }
.tp-dev-body .net-actions { margin-top: 8px; }
/* Before a game the lobby's narration offers the voice and the commentary
   switch only; Read aloud and Pause have nothing to read yet (plan 2.2). */
.tp-settings-body .tp-narration > button.gd-btn:not(.tp-commentary-voice) { display: none; }

@media (max-width: 520px) {
  .tp-advanced-row { grid-template-columns: 1fr; gap: 3px; }
  .tp-choice-body { padding: 0 10px 10px; }
}
