:root {
  color-scheme: dark;
  --bg: #16161d;
  --fg: #e8e6e3;
  --accent: #7aa2f7;
  --warn: #e0af68;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: system-ui, sans-serif;
}

.connection-banner {
  position: sticky;
  top: 0;
  padding: 0.4rem 1rem;
  background: var(--warn);
  color: #1a1a1a;
  font-size: 0.9rem;
  text-align: center;
}

.placeholder {
  max-width: 40rem;
  margin: 4rem auto;
  padding: 0 1rem;
}

.placeholder h1 {
  color: var(--accent);
}

.error {
  color: #f7768e;
}

.hint {
  color: #9aa0a6;
  font-size: 0.85rem;
}

.badge {
  background: var(--accent);
  color: #1a1a1a;
  border-radius: 3px;
  padding: 0 0.35rem;
  margin-left: 0.4rem;
  font-size: 0.75rem;
}

.badge.muted {
  background: #565f89;
}

button {
  background: #2a2a37;
  color: var(--fg);
  border: 1px solid #3b3b4d;
  border-radius: 4px;
  padding: 0.3rem 0.7rem;
  cursor: pointer;
}

button:hover:not(:disabled) {
  border-color: var(--accent);
}

button:disabled {
  opacity: 0.45;
  cursor: default;
}

a {
  color: var(--accent);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

input,
select,
textarea {
  background: #1f1f29;
  color: var(--fg);
  border: 1px solid #3b3b4d;
  border-radius: 4px;
  padding: 0.35rem 0.5rem;
}

/* login + setup */
.login-page {
  max-width: 26rem;
  margin: 4rem auto;
  padding: 0 1rem;
}

.login-page h1 {
  color: var(--accent);
}

.roster {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.roster button {
  position: relative;
  width: 100%;
  padding: 0.7rem;
  font-size: 1rem;
  display: flex;
  align-items: center;
}

/* badge is out of flow so it can't shift the name; symmetric padding keeps
   the name centred and clear of it */
.roster .roster-name {
  flex: 1;
  min-width: 0;
  padding: 0 3rem;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.roster button .badge {
  position: absolute;
  right: 0.7rem;
  top: 50%;
  transform: translateY(-50%);
  margin-left: 0;
}

.password-form,
.setup-form,
.admin-login {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 1rem;
}

/* tables + admin */
.tables-page,
.admin-page {
  max-width: 46rem;
  margin: 2rem auto;
  padding: 0 1rem;
}

.table-list {
  list-style: none;
  padding: 0;
}

.table-list li {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem;
  border-bottom: 1px solid #2a2a37;
}

.table-list li.active-table {
  border-left: 3px solid var(--accent);
}

.table-name {
  font-weight: 600;
}

.member-count {
  color: #9aa0a6;
  font-size: 0.85rem;
}

.table-list li {
  flex-wrap: wrap;
}

.table-members {
  flex-basis: 100%;
  padding: 0.4rem 0 0.2rem 1rem;
  border-left: 2px solid #2a2a37;
}

/* name | username | badges | role | password | suspend | remove | hint —
   rows are display:contents, so cells align in shared columns and buttons
   in the same column come out equal-width. column count must match the
   cells a row renders exactly, or auto-placement drifts */
.member-list {
  list-style: none;
  padding: 0;
  margin: 0 0 0.5rem;
  display: grid;
  grid-template-columns: repeat(8, max-content) 1fr;
  column-gap: 0.75rem;
  row-gap: 0.35rem;
  align-items: center;
}

.member-list li {
  display: contents;
}

/* the admin view adds the erase column before the hint */
.member-list.admin {
  grid-template-columns: repeat(9, max-content) 1fr;
}

.member-username {
  color: #9aa0a6;
  font-size: 0.85rem;
}

.member-badges {
  display: flex;
  gap: 0.3rem;
}

.member-add {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.member-hint {
  color: #9aa0a6;
  font-size: 0.8rem;
  font-style: italic;
}

.admin-page table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 0.75rem;
}

.admin-page th,
.admin-page td {
  text-align: left;
  padding: 0.35rem 0.5rem;
  border-bottom: 1px solid #2a2a37;
}

tr.disabled-user {
  opacity: 0.5;
}

.inline-form,
.player-row {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin: 0.4rem 0;
  flex-wrap: wrap;
}

.create-table {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  align-items: flex-start;
}

/* play window */
.play {
  display: flex;
  height: calc(100vh - 0px);
  position: relative;
}

/* ---- tabbed right sidebar (specs/09, specs/11) ---- */

.sidebar {
  width: 26rem;
  max-width: 90vw;
  border-left: 1px solid #2a2a37;
  background: #1d1d26;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.sidebar.collapsed {
  width: 3rem;
}

.sidebar-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.8rem;
  border-bottom: 1px solid #2a2a37;
}

.sidebar-header h2 {
  margin: 0;
  font-size: 1rem;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sidebar.collapsed .sidebar-header {
  justify-content: center;
  padding: 0.5rem 0.2rem;
}

.sidebar.collapsed .sidebar-header h2,
.sidebar.collapsed .tab-text,
.sidebar.collapsed .sidebar-body {
  display: none;
}

.sidebar-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  padding: 0.4rem;
  border-bottom: 1px solid #2a2a37;
}

.sidebar.collapsed .sidebar-tabs {
  flex-direction: column;
  align-items: stretch;
}

.sidebar-tab {
  position: relative;
  font-size: 0.85rem;
  padding: 0.25rem 0.5rem;
}

.sidebar-tab.active {
  outline: 1px solid var(--accent);
}

.tab-unread {
  display: none;
}

.tab-unread.on {
  display: inline-block;
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: var(--warn);
  position: absolute;
  top: 2px;
  right: 2px;
}

.sidebar-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.sidebar-chat {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.sidebar-chat.hidden {
  display: none;
}

.sidebar-tab.hidden {
  display: none;
}

.wb-png.hidden {
  display: none;
}

/* ---- presence dock (lower-left over the scene) ---- */

.presence-dock {
  position: absolute;
  left: 0.75rem;
  bottom: 0.75rem;
  z-index: 8;
}

.presence-dock .dock-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: rgba(10, 10, 16, 0.85);
  border: 1px solid #2a2a37;
  border-radius: 6px;
  padding: 0.25rem 0.5rem;
}

/* collapsed, only the handle is left in the scene's lower-left corner, so
   presented content (pdf page controls especially) reaches its bottom edge.
   the row is hidden rather than unmounted — it holds the ptt listeners */
.dock-collapsible {
  display: contents;
}

.dock-collapsible.hidden {
  display: none;
}

.dock-collapse {
  background: none;
  border: none;
  padding: 0.1rem 0.25rem;
  font-size: 0.8rem;
  line-height: 1.3;
  color: #9aa0a6;
}

.dock-collapse:hover {
  color: #e6e6f0;
}

.dock-toggle {
  display: flex;
  align-items: center;
  gap: 0.2rem;
  background: none;
  border: none;
  padding: 0.1rem;
}

.dock-member {
  position: relative;
  display: inline-flex;
}

.dock-member .avatar,
.dock-member .initials {
  width: 1.7rem;
  height: 1.7rem;
  border-radius: 50%;
  object-fit: cover;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #3b3b4d;
  font-size: 0.7rem;
  font-weight: bold;
}

.dock-member.speaking .avatar,
.dock-member.speaking .initials {
  outline: 2px solid #9ece6a;
}

.dock-member .presence {
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 0.5rem;
  height: 0.5rem;
  border: 2px solid #101017;
}

.dock-more {
  font-size: 0.75rem;
  color: #9aa0a6;
  margin-left: 0.2rem;
}

.presence-popover {
  position: absolute;
  bottom: 100%;
  left: 0;
  margin-bottom: 0.4rem;
  width: 17rem;
  max-height: 55vh;
  overflow-y: auto;
  background: #1d1d26;
  border: 1px solid #33334a;
  border-radius: 6px;
  padding: 0.4rem 0.8rem;
}

.presence-dock .voice-controls {
  font-size: 0.85rem;
  padding: 0;
  border-bottom: none;
  margin-bottom: 0;
}

.presence-dock .voice-buttons {
  flex-wrap: nowrap;
}

.presence-dock .voice-buttons button {
  font-size: 0.75rem;
  padding: 0.2rem 0.4rem;
  white-space: nowrap;
}

/* single line so the dock never grows over the focus controls above it */
.presence-dock .voice-controls .hint,
.presence-dock .voice-controls .error {
  margin: 0;
  font-size: 0.72rem;
  max-width: 13rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.members {
  list-style: none;
  padding: 0;
}

.members li {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.25rem 0;
}

.presence {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  display: inline-block;
}

.presence.active { background: #9ece6a; }
.presence.reconnecting { background: var(--warn); }
.presence.offline { background: #3b3b4d; }

.chat {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.chat-header {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 1rem;
  border-bottom: 1px solid #2a2a37;
}

.chat-header h2 {
  margin: 0;
  font-size: 1rem;
  flex: 1;
}

.chat-header .clear-chat {
  font-size: 0.75rem;
  padding: 0.15rem 0.45rem;
  color: #d98a8a;
}

.chat-header .clear-chat:hover {
  background: #b03a3a;
  color: #fff;
}

.timeline {
  flex: 1;
  overflow-y: auto;
  padding: 0.5rem 1rem;
}

.chat-entry {
  padding: 0.25rem 0.4rem;
  border-radius: 4px;
}

.chat-entry .author {
  font-weight: 600;
  color: var(--accent);
  margin-right: 0.4rem;
}

.chat-entry .body p {
  margin: 0.15rem 0;
}

.chat-entry.whisper {
  background: #232336;
  border-left: 2px solid #bb9af7;
}

.whisper-tag {
  color: #bb9af7;
  font-size: 0.8rem;
  margin-right: 0.4rem;
}

.chat-entry.mention {
  background: #2b2b1f;
}

.chat-entry.deleted {
  opacity: 0.55;
}

.chat-entry.pending {
  opacity: 0.6;
}

.chat-entry.pending.failed {
  opacity: 1;
  border-left: 2px solid #f7768e;
}

.edited-badge {
  color: #9aa0a6;
  font-size: 0.75rem;
  margin-right: 0.4rem;
}

.entry-actions {
  float: right;
  visibility: hidden;
  display: inline-flex;
  gap: 0.3rem;
}

.chat-entry:hover .entry-actions {
  visibility: visible;
}

.entry-actions button {
  font-size: 0.7rem;
  padding: 0.1rem 0.35rem;
}

.system-entry {
  color: #9aa0a6;
  font-size: 0.85rem;
  font-style: italic;
  padding: 0.2rem 0.4rem;
}

.chat-entry.emote {
  font-style: italic;
}

.unread-divider {
  text-align: center;
  color: var(--warn);
  font-size: 0.8rem;
  margin: 0.4rem 0;
  border-bottom: 1px dashed var(--warn);
}

.mention-menu {
  list-style: none;
  margin: 0;
  padding: 0.25rem;
  border-top: 1px solid #2a2a37;
}

.mention-menu button {
  width: 100%;
  text-align: left;
  border: none;
  background: none;
}

.mention-menu button:hover {
  background: #2a2a37;
}

.chat-input {
  margin: 0.6rem 1rem 1rem;
  min-height: 3rem;
  resize: vertical;
  font-family: inherit;
}

.chat-entry .body code,
.chat-entry .body pre {
  background: #101017;
  border-radius: 3px;
  padding: 0 0.25rem;
}

.chat-entry .body pre {
  padding: 0.5rem;
  overflow-x: auto;
}

.chat-entry .body blockquote {
  border-left: 3px solid #3b3b4d;
  margin: 0.2rem 0;
  padding-left: 0.6rem;
  color: #b5b3ae;
}

/* ---- voice (phase 2) ---- */

.voice-controls {
  padding: 0.4rem 0;
  border-bottom: 1px solid #2a2a37;
  margin-bottom: 0.5rem;
}

.voice-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}

.voice-buttons button.active {
  background: #3b3b4d;
}

.voice-buttons .leave-voice {
  color: #e07070;
}

.join-voice,
.unlock-audio {
  width: 100%;
  padding: 0.4rem;
}

.voice-error {
  font-size: 0.85rem;
}

.voice-badge {
  margin-left: 0.3rem;
  opacity: 0.6;
}

.voice-badge.speaking {
  opacity: 1;
  text-shadow: 0 0 6px #6dc56d;
}

.members .voice-only .member-name {
  font-style: italic;
}

.prejoin-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 20;
}

.prejoin {
  background: #1c1c26;
  border: 1px solid #3b3b4d;
  border-radius: 6px;
  padding: 1.2rem;
  width: min(26rem, 90vw);
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}

.prejoin select {
  width: 100%;
  margin-top: 0.2rem;
}

.prejoin .check {
  display: flex;
  gap: 0.4rem;
  align-items: center;
}

.mic-meter {
  height: 6px;
  background: #101017;
  border-radius: 3px;
  overflow: hidden;
}

.mic-meter-fill {
  height: 100%;
  background: #6dc56d;
  transition: width 80ms linear;
}

.ptt-rebind {
  align-self: flex-start;
  font-size: 0.85rem;
  padding: 0.15rem 0.5rem;
}

.gm-defaults {
  border: 1px solid #2a2a37;
  border-radius: 4px;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.9rem;
}

.prejoin-actions {
  display: flex;
  gap: 0.5rem;
  justify-content: flex-end;
}

.voice-tiles {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.5rem 1rem 0;
}

.voice-tiles.empty {
  display: none;
}

.tile {
  position: relative;
  width: 10rem;
  border: 2px solid #2a2a37;
  border-radius: 6px;
  overflow: hidden;
  background: #101017;
}

.tile.speaking {
  border-color: #6dc56d;
}

.tile video {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
}

.tile-avatar {
  aspect-ratio: 16 / 9;
  display: flex;
  align-items: center;
  justify-content: center;
}

.tile-avatar .initials {
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: #3b3b4d;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
}

.tile-footer {
  display: flex;
  gap: 0.3rem;
  align-items: center;
  padding: 0.2rem 0.4rem;
  font-size: 0.8rem;
}

.elevate-self {
  margin-left: auto;
  font-size: 0.65rem;
  padding: 0 0.3rem;
  opacity: 0.7;
}

/* capture views must stay control-free */
.scene.capture .elevate-self {
  display: none;
}

.tile-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.quality-badge {
  color: #d5a94f;
}

.tile-controls {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.2rem 0.4rem 0.4rem;
  font-size: 0.75rem;
}

.tile-controls input[type="range"] {
  width: 100%;
}

.tile-controls .gm-mute {
  color: #e07070;
}

/* in the scene grid the per-tile controls overlay on hover — always-on
   sliders under every face is clutter at gallery size */
.scene-tiles .tile .tile-controls {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(10, 10, 16, 0.85);
  opacity: 0;
  transition: opacity 0.15s;
  pointer-events: none;
}

.scene-tiles .tile:hover .tile-controls,
.scene-tiles .tile:focus-within .tile-controls {
  opacity: 1;
  pointer-events: auto;
}

.content-slot {
  margin: 0.5rem 1rem 0;
  border: 1px solid #3b3b4d;
  border-radius: 6px;
  overflow: hidden;
}

.content-slot video {
  width: 100%;
  max-height: 55vh;
  object-fit: contain;
  display: block;
  background: #000;
}

.slot-header {
  padding: 0.3rem 0.6rem;
  font-size: 0.85rem;
  background: #1c1c26;
}

.diagnostics {
  margin-top: 0.5rem;
  font-size: 0.75rem;
}

.diag-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.diagnostics pre {
  background: #101017;
  padding: 0.4rem;
  border-radius: 4px;
  max-height: 14rem;
  overflow: auto;
  white-space: pre-wrap;
}

/* ---- handouts (phase 3, specs/07) ---- */

.handouts-panel {
  flex: 1;
  min-height: 0;
  padding: 0.8rem;
  overflow-y: auto;
}

.handouts-panel header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.new-handout {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 0.8rem;
}

.new-handout .folder-input {
  flex: 1;
  min-width: 7rem;
}

.new-text {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.new-text textarea {
  min-height: 6rem;
}

.file-button {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.6rem;
  background: #2a2a3a;
  border: 1px solid #44445a;
  border-radius: 4px;
  cursor: pointer;
  font-size: 0.85rem;
}

.file-button input[type="file"] {
  display: none;
}

.file-button.primary {
  border-color: var(--accent);
}

.library .folder {
  margin: 0.7rem 0 0.2rem;
  font-size: 0.85rem;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.handout-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.handout-row {
  position: relative;
  /* reserve room so the pinned × never overlaps a long title/reveal-state */
  padding: 0.4rem 1.6rem 0.4rem 0.2rem;
  border-bottom: 1px solid #2a2a3a;
  cursor: grab;
}

/* red × pinned top-right, same affordance as the background-image delete */
.handout-delete {
  position: absolute;
  top: 0.3rem;
  right: 0.3rem;
  width: 1.15rem;
  height: 1.15rem;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: #b03a3a;
  color: #fff;
  font-size: 0.8rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s;
}

.handout-row:hover .handout-delete,
.handout-delete:focus-visible {
  opacity: 1;
  pointer-events: auto;
}

/* touch/coarse-pointer devices have no hover: keep it visible */
@media (hover: none) {
  .handout-delete {
    opacity: 1;
    pointer-events: auto;
  }
}

.handout-row .handout-title {
  background: none;
  border: none;
  color: var(--fg);
  font-size: 0.95rem;
  cursor: pointer;
  padding: 0;
}

.handout-row .handout-title:hover {
  color: var(--accent);
}

.kind-icon {
  margin-right: 0.3rem;
}

.reveal-state {
  display: block;
  font-size: 0.75rem;
  color: #9a9ab0;
}

.row-actions {
  display: flex;
  gap: 0.25rem;
  flex-wrap: wrap;
  margin-top: 0.25rem;
}

.row-actions button,
.row-actions .file-button {
  font-size: 0.75rem;
  padding: 0.15rem 0.45rem;
}

.row-actions .active {
  outline: 1px solid var(--accent);
}

.reveal-picker {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin: 0.4rem 0;
  padding: 0.5rem;
  background: #22222e;
  border-radius: 4px;
}

.access-picker .picker-row {
  display: flex;
  gap: 0.4rem;
}

.access-picker .picker-row .done {
  margin-left: auto;
}

.access-picker label {
  display: flex;
  gap: 0.4rem;
  align-items: center;
}

/* collection */

.collection-tools {
  display: flex;
  gap: 0.4rem;
  margin-bottom: 0.6rem;
}

.collection-tools input {
  flex: 1;
}

.collection-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: 0.6rem;
}

.collection-item {
  position: relative;
  background: #22222e;
  border-radius: 6px;
  overflow: hidden;
}

.thumb-button {
  width: 100%;
  background: none;
  border: none;
  color: var(--fg);
  cursor: pointer;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.thumb-button .thumb {
  width: 100%;
  height: 6rem;
  object-fit: cover;
  display: block;
}

.thumb-fallback {
  width: 100%;
  height: 6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  background: #2a2a3a;
}

.thumb-button .title {
  padding: 0.3rem 0.4rem;
  font-size: 0.85rem;
  text-align: left;
}

.badge.updated {
  position: absolute;
  top: 0.3rem;
  left: 0.3rem;
  background: var(--warn);
  color: #1a1a1a;
  border-radius: 3px;
  padding: 0 0.3rem;
  font-size: 0.7rem;
}

.link-in-chat {
  position: absolute;
  top: 0.3rem;
  right: 0.3rem;
  font-size: 0.8rem;
  padding: 0.1rem 0.3rem;
}

.show-more {
  width: 100%;
  margin-top: 0.6rem;
}

/* floating viewers */

.viewer-panel {
  position: fixed;
  z-index: 40;
  /* inline sizes are viewport-clamped in code; border-box keeps that
     arithmetic true of the rendered rect (1px borders included) */
  box-sizing: border-box;
  width: min(44rem, 90vw);
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  background: #1d1d26;
  border: 1px solid #44445a;
  border-radius: 8px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}

/* user-resized: explicit inline width/height, body fills */
.viewer-panel.sized {
  max-height: none;
}

.viewer-panel.maximized {
  left: 2vw;
  top: 2vh;
  width: 96vw;
  height: 92vh;
  max-height: none;
}

.viewer-panel.sized .viewer-body,
.viewer-panel.maximized .viewer-body {
  flex: 1;
  min-height: 0;
}

.viewer-panel.sized .image-view,
.viewer-panel.maximized .image-view {
  max-height: none;
  height: 100%;
}

.viewer-panel.sized .image-view img,
.viewer-panel.maximized .image-view img {
  max-height: 100%;
}

/* fluid (blurry) preview during the resize gesture; crisp re-render
   happens on pointerup */
.viewer-panel.resizing .pdf-view canvas {
  width: 100%;
}

.viewer-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.4rem 0.7rem;
  background: #26263a;
  border-radius: 8px 8px 0 0;
  cursor: move;
  user-select: none;
  touch-action: none;
}

.viewer-controls {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.viewer-controls a {
  color: inherit;
  text-decoration: none;
  padding: 0 0.15rem;
}

.viewer-controls a:focus-visible,
.viewer-controls button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.viewer-max {
  font-size: 0.85rem;
}

.viewer-close {
  font-size: 1rem;
}

.viewer-body {
  overflow: auto;
  padding: 0.6rem;
  min-height: 8rem;
}

.viewer-resize {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 1.1rem;
  height: 1.1rem;
  cursor: nwse-resize;
  touch-action: none;
  background: linear-gradient(
    135deg,
    transparent 50%,
    #44445a 50%,
    #44445a 60%,
    transparent 60%,
    transparent 70%,
    #44445a 70%,
    #44445a 80%,
    transparent 80%
  );
  border-bottom-right-radius: 8px;
}

/* whiteboard pop-out (specs/08): plain flex body, no pdf letterboxing —
   the surface's own .whiteboard-* styles fill it edge to edge */
.viewer-panel.wb-window .viewer-body {
  padding: 0;
  overflow: hidden;
  flex: 1;
  min-height: 0;
  display: flex;
}

.viewer-panel.wb-window .wb-surface {
  flex: 1;
  min-height: 0;
  min-width: 0;
}

.wb-popout {
  font-size: 0.85rem;
}

.viewer-panel.maximized .viewer-resize {
  display: none;
}

.image-view {
  position: relative;
  overflow: hidden;
  min-height: 10rem;
  max-height: 70vh;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: grab;
}

.image-view img {
  max-width: 100%;
  max-height: 68vh;
  transition: transform 0.05s linear;
}

.image-view .zoom-hint {
  position: absolute;
  bottom: 0.3rem;
  right: 0.5rem;
  font-size: 0.7rem;
  color: #9a9ab0;
  pointer-events: none;
}

.text-view {
  max-width: 38rem;
  line-height: 1.5;
}

.pdf-view canvas {
  max-width: 100%;
  display: block;
  margin: 0 auto;
  background: #fff;
}

.pdf-nav {
  display: flex;
  justify-content: center;
  gap: 0.6rem;
  align-items: center;
  padding-top: 0.5rem;
}

/* presented handout + share pip (content-slot arbitration) */

.content-slot.presented {
  border: 1px solid var(--accent);
  border-radius: 6px;
  margin: 0.5rem;
  overflow: auto;
  max-height: 60vh;
}

.content-slot.presented .slot-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.3rem 0.6rem;
  background: #26263a;
}

.content-slot.pip {
  position: absolute;
  right: 1rem;
  bottom: 6rem;
  width: 16rem;
  z-index: 20;
  border: 1px solid #44445a;
  border-radius: 6px;
  overflow: hidden;
}

.content-slot.pip .slot-header {
  font-size: 0.7rem;
  padding: 0.15rem 0.4rem;
}

.presented-minimized {
  margin: 0.5rem;
  align-self: flex-start;
}

/* toast + notices */

.reveal-toast {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 0.3rem;
  background: #26263a;
  border: 1px solid var(--accent);
  border-radius: 6px;
  padding: 0.4rem 0.6rem;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
}

.reveal-toast .toast-body {
  background: none;
  border: none;
  color: var(--fg);
  cursor: pointer;
}

.reveal-toast.notice {
  border-color: var(--warn);
}

/* chat chips */

.handout-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  background: #2a2a3a;
  border: 1px solid var(--accent);
  border-radius: 999px;
  color: var(--fg);
  padding: 0.05rem 0.55rem;
  font-size: 0.85rem;
  cursor: pointer;
}

.handout-chip:hover {
  background: #33334a;
}

/* avatars */

.avatar {
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  object-fit: cover;
  vertical-align: middle;
}

.member-list.hidden,
.member-add.hidden {
  display: none;
}
.avatar.hidden {
  display: none;
}

.member-avatar .initials {
  display: inline-flex;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  background: #3b3b4d;
  align-items: center;
  justify-content: center;
  font-size: 0.65rem;
  font-weight: bold;
}

.tile-avatar .avatar {
  width: 3rem;
  height: 3rem;
}

.self-avatar {
  margin-top: 0.5rem;
}

/* ---- dice (phase 4, specs/05) ---- */

.dice-bar {
  border-top: 1px solid #2a2a3d;
  padding: 0.4rem 1rem 0.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

/* chips sit inline with the die buttons and wrap as the library grows */
.macro-chips,
.dice-shortcuts {
  display: contents;
}

.macro-chip {
  display: inline-flex;
  align-items: center;
  background: #2a2a3d;
  border-radius: 999px;
  overflow: hidden;
}

.macro-chip .macro-roll {
  padding: 0.15rem 0.2rem 0.15rem 0.6rem;
  font-size: 0.8rem;
}

.macro-chip .macro-unpin {
  padding: 0.15rem 0.45rem 0.15rem 0.15rem;
  font-size: 0.8rem;
  opacity: 0.5;
}

.macro-chip .macro-unpin:hover {
  opacity: 1;
  color: var(--accent);
}

.macro-chip .macro-bind-edit {
  padding-inline: 0.35rem;
  border-left: 1px solid var(--line);
}

.macro-binding {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 0.45rem;
  width: 100%;
  padding: 0.55rem 0.65rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--panel);
}

.macro-binding label {
  display: grid;
  gap: 0.15rem;
  font-size: 0.75rem;
}

.macro-binding input {
  width: 6rem;
}

.macro-binding-name {
  align-self: center;
  font-weight: 650;
}

.macro-edit,
.macro-export {
  font-size: 0.75rem;
  padding: 0.15rem 0.5rem;
}

/* advanced dice (specs/16) */
.dice-mode {
  margin: 0;
  color: #9aa0a6;
  font-size: 0.75rem;
  font-style: italic;
}

.subtotal.tally,
.roll-total.tally,
.ticker-total.tally {
  font-variant-numeric: normal;
  font-weight: 600;
}

.die.scored {
  outline: 1px solid var(--accent);
}

.die.unmatched {
  opacity: 0.55;
}

.die-note {
  margin-left: 0.2rem;
  font-size: 0.7rem;
  color: #9aa0a6;
}

.unmatched-count {
  margin-left: 0.4rem;
  color: #9aa0a6;
  font-size: 0.8rem;
}

.buckets {
  display: inline-flex;
  gap: 0.4rem;
  margin-left: 0.5rem;
}

.bucket {
  display: inline-flex;
  gap: 0.2rem;
  padding: 0 0.3rem;
  background: #2a2a3d;
  border-radius: 3px;
  font-size: 0.8rem;
}

.bucket.empty {
  opacity: 0.4;
}

.bucket-count {
  font-weight: 600;
}

/* macro manager dialog */
.macro-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 60;
}

.macro-dialog {
  background: #16161f;
  border: 1px solid #2a2a37;
  border-radius: 8px;
  padding: 1rem;
  width: min(46rem, 92vw);
  max-height: 82vh;
  overflow-y: auto;
}

.macro-dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.macro-dialog-header h3 {
  margin: 0;
}

/* one column per control: every row emits the same cells, so pinned and
   unpinned rows line up instead of shifting each other's buttons */
.macro-manager-list {
  list-style: none;
  padding: 0;
  margin: 0.5rem 0;
  display: grid;
  grid-template-columns:
    max-content minmax(8rem, 1fr) max-content
    repeat(5, max-content);
  column-gap: 0.6rem;
  row-gap: 0.4rem;
  align-items: center;
}

.macro-manager-row,
.macro-row-actions {
  display: contents;
}

.macro-manager-meta,
.macro-action-edit {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.macro-manager-list button {
  white-space: nowrap;
}

/* eight columns don't fit a phone: stack one macro per block instead */
@media (max-width: 44rem) {
  .macro-manager-list {
    display: block;
  }

  .macro-manager-row {
    display: block;
    padding: 0.5rem 0;
    border-bottom: 1px solid #2a2a37;
  }

  .macro-row-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    margin-top: 0.3rem;
  }

  .macro-manager-expr,
  .macro-manager-meta {
    display: block;
    overflow-wrap: anywhere;
  }

  .macro-name-edit,
  .macro-expr-edit {
    width: 100%;
    max-width: none;
  }

  .macro-create {
    flex-wrap: wrap;
  }

  /* beats the wider `.macro-create-expr { flex: 1 }` further down */
  .macro-dialog .macro-create-expr {
    flex: 1 1 100%;
  }
}

.macro-manager-row.unpinned .macro-manager-name {
  opacity: 0.65;
}

.macro-trial {
  grid-column: 2 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 0.4rem;
}

.macro-trial label {
  display: grid;
  gap: 0.1rem;
  font-size: 0.72rem;
}

.macro-trial input {
  width: 5.5rem;
}

.macro-manager-name {
  font-weight: 600;
}

.macro-manager-expr,
.macro-expr-edit {
  font-family: ui-monospace, monospace;
  font-size: 0.85rem;
  min-width: 0;
}

.macro-name-edit {
  font-size: 0.85rem;
  min-width: 0;
  max-width: 10rem;
}

.macro-import {
  margin-top: 0.8rem;
  border-top: 1px solid #2a2a37;
  padding-top: 0.6rem;
}

.macro-import summary {
  cursor: pointer;
  font-size: 0.85rem;
}

.macro-import textarea {
  width: 100%;
  font-family: ui-monospace, monospace;
  font-size: 0.85rem;
  margin: 0.4rem 0;
}

.import-note {
  margin-top: 0.4rem;
}

.macro-mode {
  color: #9aa0a6;
  font-size: 0.75rem;
  font-style: italic;
  margin: 0;
}

.macro-row-actions button {
  font-size: 0.75rem;
  padding: 0.15rem 0.4rem;
}

.macro-create {
  display: flex;
  gap: 0.4rem;
  margin-top: 0.6rem;
}

.macro-create-expr {
  flex: 1;
  font-family: ui-monospace, monospace;
}

.dice-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
}

.die-button,
.adv-toggle,
.mod-chip {
  font-size: 0.8rem;
  padding: 0.2rem 0.5rem;
}

/* shift-click pool badge */
.die-button {
  position: relative;
}

.die-count {
  position: absolute;
  top: -0.45rem;
  right: -0.35rem;
  min-width: 1rem;
  padding: 0 0.2rem;
  border-radius: 0.5rem;
  background: var(--accent);
  color: #0e0e14;
  font-size: 0.65rem;
  font-weight: 700;
  line-height: 1rem;
}

.adv-toggle {
  border: 1px solid #3b3b4d;
}

.modifier-pad {
  display: inline-flex;
  gap: 0.25rem;
  margin-left: auto;
  align-items: center;
}

.mod-custom {
  width: 3.2rem;
  font-size: 0.8rem;
  padding: 0.15rem 0.3rem;
}

.dice-input-row {
  display: flex;
  gap: 0.4rem;
  align-items: center;
}

/* the field keeps its own line; who-sees-it and Roll drop below it */
@media (max-width: 44rem) {
  .dice-input-row {
    flex-wrap: wrap;
    row-gap: 0.3rem;
  }

  .dice-input-row .dice-input-wrap {
    flex: 1 1 60%;
  }

  .roll-visibility {
    margin-left: auto;
  }
}

/* the (i) sits inside the field's right edge */
.dice-input-wrap {
  position: relative;
  display: flex;
  flex: 1;
}

.dice-input {
  flex: 1;
  font-family: monospace;
  padding-right: 1.9rem;
}

.dice-help {
  position: absolute;
  right: 0.35rem;
  top: 50%;
  transform: translateY(-50%);
  width: 1.1rem;
  height: 1.1rem;
  padding: 0;
  border: 1px solid #3b3b4d;
  border-radius: 999px;
  background: none;
  font-size: 0.7rem;
  font-style: italic;
  line-height: 1;
  color: #9aa0a6;
}

.dice-help:hover {
  color: var(--accent);
}

.dice-collapse {
  padding: 0.1rem 0.35rem;
  font-size: 0.7rem;
  color: #9aa0a6;
}

/* collapsed, the whole bar leaves the scene column — the scene grows to
   fill it, exactly as it does when the sidebar collapses — and this handle
   brings it back. it rides *in* the presence dock, which already owns the
   scene's lower-left corner, so it costs no layout row and can't overlap */
.dice-restore {
  padding: 0.2rem 0.5rem;
  border-radius: 999px;
  border: 1px solid #3b3b4d;
  background: #1b1b26;
  font-size: 0.9rem;
  line-height: 1.3;
}

.dice-restore:hover {
  border-color: var(--accent);
}

.dice-bar.hidden {
  display: none;
}

.dice-guide-table {
  border-collapse: collapse;
  width: 100%;
  font-size: 0.85rem;
}

.dice-guide-table td {
  padding: 0.2rem 0.5rem 0.2rem 0;
  vertical-align: top;
}

.dice-guide-table code {
  color: var(--accent);
  white-space: nowrap;
}

.dice-guide h4 {
  margin: 1rem 0 0.3rem;
}

.dice-guide-note {
  margin: 0.8rem 0 0;
  color: #9aa0a6;
  font-size: 0.8rem;
}

.dice-input.invalid {
  border-color: #f7768e;
}

.dice-error {
  margin: 0;
  color: #f7768e;
  font-size: 0.8rem;
}

.roll-visibility {
  font-size: 0.8rem;
}

.roll-entry {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.4rem;
  padding: 0.25rem 0.4rem;
  border-radius: 4px;
  background: #1f2430;
  border-left: 2px solid var(--accent);
  margin: 0.15rem 0;
}

.roll-entry .author {
  font-weight: 600;
  color: var(--accent);
}

.roll-entry.hidden-roll {
  border-left-color: #bb9af7;
}

.visibility-tag {
  color: #bb9af7;
  font-size: 0.75rem;
}

.roll-notation {
  background: #2a2a3d;
  padding: 0 0.3rem;
  border-radius: 3px;
}

.roll-comment {
  font-style: italic;
  color: #9aa0a6;
}

.roll-total {
  margin-left: auto;
  font-weight: 700;
  font-size: 1rem;
  padding: 0.05rem 0.5rem;
  background: #2a2a37;
  border: 1px solid #3b3b4d;
  border-radius: 4px;
  animation: roll-pop 0.45s ease-out;
}

@keyframes roll-pop {
  0% { transform: scale(1.6); color: var(--warn); }
  100% { transform: scale(1); }
}

.save-as-macro {
  font-size: 0.75rem;
  visibility: hidden;
}

.roll-entry:hover .save-as-macro {
  visibility: visible;
}

.roll-breakdown {
  font-family: monospace;
  font-size: 0.85rem;
  color: #c0caf5;
}

/* repeated rolls (3x d6) wrap to their own lines under the header */
.roll-breakdown.multi {
  flex-basis: 100%;
  padding: 0.15rem 0 0.1rem;
}

.roll-repeat {
  padding: 0.1rem 0;
}

.die {
  display: inline-block;
  padding: 0 0.25rem;
  margin: 0 0.1rem;
  background: #2a2a3d;
  border-radius: 3px;
}

.die.dropped {
  text-decoration: line-through;
  opacity: 0.5;
}

.die.nat20 {
  background: #1f3324;
  color: #9ece6a;
  font-weight: 700;
}

.die.nat1 {
  background: #3a2029;
  color: #f7768e;
  font-weight: 700;
}

.die.success {
  outline: 1px solid #9ece6a;
}

.subtotal {
  color: #9aa0a6;
}

.dice-error .error-span {
  margin-left: 0.5rem;
  background: #2a2a3d;
  padding: 0 0.3rem;
  border-radius: 3px;
  color: #c0caf5;
}

.dice-error mark {
  background: #f7768e;
  color: #1a1b26;
  border-radius: 2px;
}

/* ---- phase 5: notebook ---- */

.notebook-panel,
.whiteboard-panel {
  flex: 1;
  min-height: 0;
  padding: 0.8rem;
  display: flex;
  flex-direction: column;
}

.notebook-panel header,
.whiteboard-panel header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.notebook-docs ul {
  list-style: none;
  padding: 0;
  margin: 0.4rem 0;
  max-height: 10rem;
  overflow-y: auto;
}

.notebook-docs li {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.15rem 0.3rem;
  border-radius: 4px;
}

.notebook-docs li.active {
  background: #2a2a3a;
}

.notebook-docs li .doc-open {
  flex: 1;
  text-align: left;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.2rem;
}

.notebook-docs li .entry-actions {
  visibility: hidden;
}

.notebook-docs li:hover .entry-actions {
  visibility: visible;
}

.doc-create {
  display: flex;
  gap: 0.4rem;
  margin: 0.4rem 0;
}

.doc-create input {
  flex: 1;
}

.deleted-docs {
  font-size: 0.85rem;
  color: #888;
}

.deleted-docs ul {
  list-style: none;
  padding-left: 0.6rem;
}

.deleted-docs li {
  display: flex;
  justify-content: space-between;
  padding: 0.1rem 0;
}

.notebook-editor {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-top: 1px solid #33334a;
  padding-top: 0.5rem;
}

.editor-toolbar {
  display: flex;
  gap: 0.4rem;
  margin-bottom: 0.4rem;
}

.editor-hint {
  margin-top: 1rem;
}

.editor-stack {
  position: relative;
  flex: 1;
  min-height: 0;
}

/* transparent textarea over the highlighted mirror — classic trick;
   both must share metrics exactly */
.editor-mirror,
.editor-input {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0.6rem;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.9rem;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-word;
  overflow-wrap: break-word;
  overflow-y: auto;
  border: 1px solid #33334a;
  border-radius: 4px;
  box-sizing: border-box;
  tab-size: 4;
}

.editor-mirror {
  pointer-events: none;
  color: #d8d8e0;
  background: #14141b;
  overflow: hidden;
}

.editor-input {
  color: transparent;
  caret-color: #e6e6f0;
  background: transparent;
  resize: none;
}

.editor-input::selection {
  background: rgba(90, 120, 255, 0.35);
}

.md-heading { color: #7aa2f7; font-weight: bold; }
.md-quote { color: #8a8fa8; font-style: italic; }
.md-bullet { color: #e0af68; }
.md-code, .md-codespan { color: #9ece6a; }
.md-bold { color: #f7768e; font-weight: bold; }
.md-italic { font-style: italic; }

.nb-cursor {
  position: relative;
  display: inline-block;
  width: 0;
}

.nb-cursor::before {
  content: "";
  position: absolute;
  left: -1px;
  top: -0.1em;
  width: 2px;
  height: 1.3em;
  background: var(--cursor-color);
}

.nb-cursor::after {
  content: attr(data-name);
  position: absolute;
  left: -1px;
  top: -1.25em;
  background: var(--cursor-color);
  color: #fff;
  font-size: 0.62rem;
  line-height: 1.2;
  padding: 0 0.25em;
  border-radius: 2px;
  white-space: nowrap;
  pointer-events: none;
}

.notebook-preview {
  flex: 1;
  overflow-y: auto;
  border: 1px solid #33334a;
  border-radius: 4px;
  padding: 0.6rem;
  background: #14141b;
}

/* ---- phase 5: whiteboard ---- */

.wb-toolbar {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  flex-wrap: wrap;
  padding: 0.3rem 0;
}

.wb-toolbar button.active {
  outline: 1px solid var(--accent);
}

.wb-sep {
  width: 1px;
  height: 1.2rem;
  background: #33334a;
  margin: 0 0.3rem;
}

/* gm whiteboard-access selector (specs/08) */
.wb-access {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
}

.wb-access-label {
  font-size: 0.75rem;
  opacity: 0.7;
  margin-right: 0.1rem;
}

.wb-access-opt {
  font-size: 0.75rem;
  padding: 0.1rem 0.4rem;
}

.wb-access-opt.active {
  outline: 1px solid var(--accent);
  background: #2a2a3d;
}

.wb-width {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
}

.wb-width-dot {
  display: inline-block;
  border-radius: 50%;
  background: #d8d8e0;
}

.wb-color {
  width: 1.3rem;
  height: 1.3rem;
  border-radius: 50%;
  border: 2px solid transparent;
  background: var(--swatch);
  cursor: pointer;
  padding: 0;
}

.wb-color.active {
  border-color: #fff;
}

/* colour popover (phase 14): one current-colour trigger opening a swatch menu */
.wb-color-popover {
  position: relative;
  display: inline-flex;
}

.wb-color-trigger {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  border: 2px solid #55556a;
  background: var(--swatch);
  cursor: pointer;
  padding: 0;
}

.wb-popover-backdrop {
  position: fixed;
  inset: 0;
  z-index: 40;
}

.wb-color-menu {
  position: absolute;
  top: 110%;
  left: 0;
  z-index: 41;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.35rem;
  padding: 0.5rem;
  background: #1c1c28;
  border: 1px solid #33334a;
  border-radius: 6px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4);
}

/* zoom readout (phase 14) */
.wb-zoom-readout {
  min-width: 3.2em;
  text-align: center;
  font-variant-numeric: tabular-nums;
  color: #9aa0a6;
  font-size: 0.85rem;
}

.wb-surface {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.wb-canvas-wrap {
  position: relative;
  flex: 1;
  min-height: 0;
  border: 1px solid #33334a;
  border-radius: 4px;
  overflow: hidden;
  background: #f5f5f0;
}

/* whiteboard as the content-slot occupant: fills the stage */
.wb-slot {
  display: flex;
  flex-direction: column;
}

.wb-presented-note {
  padding: 1rem 0.2rem;
  color: #9aa0a6;
}

.wb-presented-note button {
  margin-top: 0.5rem;
}

.wb-canvas {
  display: block;
  touch-action: none;
  cursor: crosshair;
}

.wb-canvas.pan-tool {
  cursor: grab;
}

.wb-loading {
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 1;
  color: #555;
}

.wb-label-input {
  position: absolute;
  z-index: 2;
  font-size: 0.9rem;
  padding: 0.1rem 0.3rem;
}

/* markers (phase 12, specs/08): a layer above the canvas, positioned in
   board space so a puck sits on the same spot under any pan/zoom */
.wb-markers {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}

.wb-marker {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  user-select: none;
}

/* only your own puck takes pointer events — nobody moves anyone else's */
.wb-marker.mine {
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
}

/* board-image arrange overlay (phase 14, gm-only): boxes over the canvas in
   board space, with move-drag, corner handles, and per-image controls */
.wb-image-arrange {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

.wb-img-box {
  position: absolute;
  border: 1.5px dashed var(--accent);
  background: rgba(80, 120, 220, 0.05);
  pointer-events: auto;
  cursor: move;
  touch-action: none;
}

.wb-img-tools {
  position: absolute;
  top: -1.6rem;
  right: 0;
  display: flex;
  gap: 0.2rem;
}

.wb-img-tools button {
  width: 1.4rem;
  height: 1.4rem;
  padding: 0;
  line-height: 1;
  background: #1c1c28;
  border: 1px solid #33334a;
  border-radius: 3px;
  cursor: pointer;
}

.wb-img-remove {
  color: #e11d48;
}

.wb-img-handle {
  position: absolute;
  width: 12px;
  height: 12px;
  background: #fff;
  border: 1.5px solid var(--accent);
  border-radius: 2px;
  touch-action: none;
}

.wb-img-handle.nw { top: -6px; left: -6px; cursor: nwse-resize; }
.wb-img-handle.ne { top: -6px; right: -6px; cursor: nesw-resize; }
.wb-img-handle.sw { bottom: -6px; left: -6px; cursor: nesw-resize; }
.wb-img-handle.se { bottom: -6px; right: -6px; cursor: nwse-resize; }

/* add-image picker modal (phase 14) */
.wb-picker-backdrop {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
}

.wb-picker {
  width: min(640px, 90vw);
  max-height: 80vh;
  overflow: auto;
  background: #1c1c28;
  border: 1px solid #33334a;
  border-radius: 8px;
  padding: 1rem;
}

.wb-picker header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.75rem;
}

.wb-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 0.6rem;
}

.wb-picker-item {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 0.4rem;
  background: #14141e;
  border: 1px solid #33334a;
  border-radius: 6px;
  cursor: pointer;
}

.wb-picker-item img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 4px;
}

.wb-picker-item span {
  font-size: 0.8rem;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wb-marker-dot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--puck);
  border: 2px solid #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}

.wb-marker-label {
  font-size: 0.7rem;
  line-height: 1;
  padding: 1px 4px;
  border-radius: 3px;
  background: rgba(30, 30, 40, 0.8);
  color: #eee;
  white-space: nowrap;
}

.wb-tray {
  display: flex;
  align-items: center;
  gap: 0.3rem;
}

.wb-tray-label {
  font-size: 0.75rem;
  color: #9aa0a6;
}

.wb-tray-mine {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

.wb-readonly {
  position: absolute;
  bottom: 0.5rem;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(30, 30, 40, 0.85);
  color: #eee;
  padding: 0.2rem 0.7rem;
  border-radius: 4px;
  font-size: 0.85rem;
}

/* ---- scene, music & streaming (phase 6, specs/09) ---- */

.scene-column {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* the layered surface: background → content slot → tiles → chrome.
   fills the column above the dice bar (specs/09: scene fills the viewport) */
.scene {
  position: relative;
  overflow: hidden;
  flex: 1;
  min-height: 200px;
  display: flex;
  flex-direction: column;
  border-bottom: 1px solid #2a2a37;
}

.scene-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.scene-bg-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.scene-content {
  /* flex items honor z-index without position; absolute overlays inside
     (share pip) must anchor to the scene, not this box — it can shrink.
     above the tiles layer (3) so pips stay visible and clickable; the
     chrome (4) is a later sibling, so it still paints on top */
  z-index: 4;
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.3s ease;
  pointer-events: none;
}

.scene-content > * {
  pointer-events: auto;
}

.scene-content .content-slot {
  background: rgba(10, 10, 16, 0.85);
  max-width: min(92%, 1100px);
  max-height: 100%;
}

.scene-content .content-slot img {
  max-width: 100%;
  max-height: 70vh;
  display: block;
}

/* content on stage: the slot fills the content column edge to edge */
.scene.has-content .scene-content {
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  gap: 0.4rem;
  padding: 0.6rem;
  min-width: 0;
}

.scene.has-content .scene-content .content-slot:not(.pip) {
  flex: 1;
  min-height: 0;
  width: auto;
  max-width: none;
  max-height: none;
  margin: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* the occupant under the slot header takes the rest of the slot */
.scene.has-content .scene-content .content-slot:not(.pip) > :not(.slot-header) {
  flex: 1;
  min-height: 0;
  overflow: auto;
}

.scene.has-content .scene-content .content-slot .image-view {
  max-height: none;
  overflow: hidden;
}

.scene.has-content .scene-content .content-slot .image-view img {
  max-height: 100%;
}

.scene.has-content .scene-content .content-slot video {
  height: 100%;
  max-height: none;
}

.scene-tiles {
  position: relative;
  z-index: 3;
  transition:
    opacity 0.3s ease,
    width 0.3s ease;
  flex: 0 1 auto;
  max-height: 45%;
  overflow-y: auto;
}

.scene-tiles .voice-tiles {
  padding: 0.5rem;
}

/* nobody in voice: no strip, no reserved column — content gets the scene
   (tables running voice elsewhere still use the board and handouts).
   collapsed, not display:none, so the layout still crossfades (specs/09) */
.scene.no-tiles .scene-tiles {
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
}

/* the side column collapses — this beats the layout rule below on
   specificity, whatever the source order. the gallery needs no collapse:
   an empty strip there holds a scene with nothing else in it */
.scene.has-content.no-tiles .scene-tiles {
  width: 0;
  padding: 0;
}

/* one adaptive layout (specs/09) — empty slot: faces fill the scene as a
   call grid, column count computed from container shape + tile count
   (--gallery-cols/--gallery-tile-w set by VoiceTiles) */
.scene:not(.has-content) .scene-tiles {
  flex: 1;
  max-height: none;
  min-height: 0;
}

/* an empty slot must not eat half the scene — the grid gets it all */
.scene:not(.has-content) .scene-content {
  flex: none;
}

.scene:not(.has-content) .voice-tiles {
  display: grid;
  grid-template-columns: repeat(var(--gallery-cols, 1), 1fr);
  gap: 0.75rem;
  align-content: center;
  align-items: center;
  justify-items: center;
  height: 100%;
  padding: 1rem;
}

.scene:not(.has-content) .voice-tiles .tile {
  width: 100%;
  max-width: var(--gallery-tile-w, 100%);
}

/* presented content takes the stage: content fills, faces move to a
   narrow side column */
.scene.has-content {
  flex-direction: row;
}

.scene.has-content .scene-tiles {
  flex: 0 0 auto;
  width: 13rem;
  max-height: none;
  overflow-y: auto;
}

.scene.has-content .voice-tiles {
  flex-direction: column;
  padding: 0.5rem 0.5rem 0.5rem 0;
}

.scene.has-content .scene-tiles .tile {
  width: 100%;
}

/* own face tucked away by default (local pref): a floating pip in the
   lower corner, not a grid cell — the others fill the grid without you */
.scene:not(.has-content):not(.self-elevated) .voice-tiles .tile.mine {
  position: absolute;
  right: 1rem;
  /* clear of the voice-controls row and the music chip */
  bottom: 4rem;
  width: 14rem;
  max-width: 40%;
  z-index: 6;
  opacity: 0.95;
}

/* the tuck/elevate toggle only means something in the gallery */
.scene.has-content .elevate-self {
  display: none;
}

/* theme chrome */
.scene.frame-square .tile,
.scene.frame-square .content-slot {
  border-radius: 0;
}

.scene .tile.speaking {
  border-color: var(--scene-accent, var(--accent));
}

.scene .content-slot.presented {
  border-color: var(--scene-accent, var(--accent));
}

.scene-chrome {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
}

.scene-chrome > * {
  pointer-events: auto;
}

.scene-logo {
  position: absolute;
  top: 0.6rem;
  left: 0.6rem;
  max-width: 6rem;
  max-height: 3.5rem;
  object-fit: contain;
  opacity: 0.9;
}

/* dice ticker: recent public rolls fade in/out over the scene */
.dice-ticker {
  position: absolute;
  right: 0.6rem;
  top: 0.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  align-items: flex-end;
  pointer-events: none;
}

.ticker-roll {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
  background: rgba(10, 10, 16, 0.82);
  border-left: 3px solid var(--scene-accent, var(--accent));
  padding: 0.25rem 0.6rem;
  border-radius: 4px;
  animation: ticker-fade 9s ease forwards;
}

.ticker-roller {
  font-weight: 600;
  font-size: 0.85rem;
}

.ticker-expr {
  font-size: 0.8rem;
  opacity: 0.8;
}

.ticker-dies .die {
  font-size: 0.8rem;
}

/* high-contrast totals — stream compression eats subtle colors */
.ticker-total {
  font-size: 1.25rem;
  font-weight: 800;
  color: #ffffff;
  text-shadow: 0 0 4px #000;
}

.dice-ticker.minimal .ticker-roller,
.dice-ticker.minimal .ticker-expr,
.dice-ticker.minimal .ticker-dies {
  display: none;
}

@keyframes ticker-fade {
  0% { opacity: 0; transform: translateY(-4px); }
  6% { opacity: 1; transform: none; }
  85% { opacity: 1; }
  100% { opacity: 0; }
}

/* music player chrome */
.music-chip {
  position: absolute;
  bottom: 0.5rem;
  right: 0.6rem;
  display: flex;
  gap: 0.4rem;
  align-items: center;
  background: rgba(10, 10, 16, 0.82);
  border-radius: 999px;
  padding: 0.2rem 0.6rem;
  opacity: 0.5;
  transition: opacity 0.2s;
}

.music-chip:hover {
  opacity: 1;
}

.music-chip input[type="range"] {
  width: 6rem;
}

.music-mute {
  border: none;
  background: none;
  cursor: pointer;
}

.music-unlock {
  position: absolute;
  bottom: 3rem;
  right: 0.6rem;
  background: rgba(10, 10, 16, 0.92);
  border: 1px solid var(--warn);
  border-radius: 6px;
  color: var(--fg);
  padding: 0.3rem 0.7rem;
  cursor: pointer;
}

/* gm scene settings tab */
.scene-settings {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.scene-settings section {
  padding: 0.6rem 1rem;
  border-top: 1px solid #2a2a37;
}

.scene-settings h3 {
  margin: 0 0 0.4rem;
  font-size: 0.95rem;
}

.mode-buttons,
.bg-controls {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
}

.mode-buttons button.active {
  border-color: var(--accent);
  color: var(--accent);
}

.upload-picker {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  margin-top: 0.5rem;
}

.picker-thumb {
  padding: 0;
  border: 2px solid #2a2a37;
  border-radius: 4px;
  overflow: hidden;
  cursor: pointer;
  background: none;
}

.picker-thumb img {
  width: 5.5rem;
  height: 3.2rem;
  object-fit: cover;
  display: block;
}

.picker-thumb.active {
  border-color: var(--accent);
}

/* hover-revealed delete affordance on picker thumbs */
.picker-item {
  position: relative;
}

.picker-delete {
  position: absolute;
  top: -0.35rem;
  right: -0.35rem;
  width: 1.15rem;
  height: 1.15rem;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: #b03a3a;
  color: #fff;
  font-size: 0.8rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s;
}

.picker-item:hover .picker-delete,
.picker-delete:focus-visible {
  opacity: 1;
  pointer-events: auto;
}

/* touch/coarse-pointer devices have no hover: keep the affordance visible */
@media (hover: none) {
  .picker-delete {
    opacity: 1;
    pointer-events: auto;
  }
}

.music-library {
  list-style: none;
  padding: 0;
  margin: 0.5rem 0 0;
}

.music-library li {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  padding: 0.2rem 0;
}

.music-library li.active span {
  color: var(--accent);
}

.stage-url {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.stage-url code {
  overflow-x: auto;
  white-space: nowrap;
  max-width: 26rem;
  background: #101017;
  padding: 0.2rem 0.4rem;
  border-radius: 4px;
}

.hint.warn {
  color: var(--warn);
}

/* streamer mode: scene + chosen overlays only (specs/09) */
.play.streamer .sidebar,
.play.streamer .presence-dock,
.play.streamer .chat,
.play.streamer .dice-bar,
.play.streamer .dice-restore {
  display: none;
}

/* shift+, — the sidebar overlays the capture until dismissed */
.play.streamer.show-sidebar .sidebar,
.play.streamer.show-sidebar .sidebar .chat {
  display: flex;
}

.play.streamer .scene {
  height: 100vh;
  border: none;
}

.scene.hide-tiles .scene-tiles {
  display: none;
}

.scene.hide-rings .tile.speaking {
  border-color: #2a2a37;
}

.scene.hide-rings .voice-badge.speaking {
  text-shadow: none;
}

.streamer-controls {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  z-index: 7;
  display: flex;
  gap: 0.4rem;
  /* generous invisible hit zone: the bar reveals only when the pointer
     is actually on it at the top edge, not on any window hover */
  padding: 0.5rem 2.5rem 1rem;
  opacity: 0;
  transition: opacity 0.2s;
}

.streamer-controls:hover,
.streamer-controls:focus-within {
  opacity: 1;
}

.streamer-controls button {
  background: rgba(10, 10, 16, 0.9);
  border: 1px solid #3b3b4d;
  border-radius: 4px;
  color: var(--fg);
  padding: 0.2rem 0.5rem;
  cursor: pointer;
  font-size: 0.8rem;
}

.streamer-keys {
  align-self: center;
  font-size: 0.7rem;
  color: #9aa0a6;
  background: rgba(10, 10, 16, 0.7);
  padding: 0.15rem 0.4rem;
  border-radius: 4px;
}

/* shift+c / shift+m: discrete right-side panels, invisible until invoked */
.streamer-menu {
  position: absolute;
  top: 3rem;
  right: 0.75rem;
  z-index: 9;
  width: 20rem;
  max-height: 70vh;
  overflow-y: auto;
  background: rgba(10, 10, 16, 0.92);
  border: 1px solid #3b3b4d;
  border-radius: 6px;
}

.streamer-present-list {
  list-style: none;
  margin: 0;
  padding: 0.4rem;
}

.streamer-present-list li {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.3rem;
}

.streamer-present-list .present-title {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.streamer-menu section {
  padding: 0 0.6rem 0.6rem;
}

/* esc: custom confirm — a native dialog would land in the capture */
.streamer-dice {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.6rem;
}

.streamer-dice-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}

.streamer-dice-pool {
  display: flex;
  gap: 0.4rem;
  align-items: center;
}

.streamer-dice-pool code {
  flex: 1;
  color: #9aa0a6;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.streamer-confirm {
  position: absolute;
  top: 40%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 10;
  background: rgba(10, 10, 16, 0.95);
  border: 1px solid #3b3b4d;
  border-radius: 6px;
  padding: 1rem 1.4rem;
  text-align: center;
}

.streamer-confirm .confirm-row {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  margin-top: 0.6rem;
}

.streamer-hint-chip {
  position: absolute;
  top: 3rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 9;
  background: rgba(10, 10, 16, 0.9);
  border: 1px solid #3b3b4d;
  border-radius: 4px;
  padding: 0.2rem 0.6rem;
  font-size: 0.8rem;
  color: #9aa0a6;
}

/* /stage: the whole viewport is the scene; nothing is interactive */
.stage {
  height: 100vh;
  background: #000;
}

.stage .scene,
.stage .stage-dead {
  height: 100vh;
  border: none;
}

.stage * {
  pointer-events: none;
}

.stage-slot {
  margin: 0;
}

.stage-slot canvas {
  max-width: 100%;
  display: block;
}

.stage-slot .handout-text {
  padding: 1rem 1.5rem;
  max-width: 60ch;
}

/* ---- phase 6 review fixes ---- */

/* capture cleanliness: interactive per-tile controls never render in
   streamer mode or on /stage (specs/09: scene + chosen overlays only) */
.scene.capture .tile-controls,
.stage .tile-controls {
  display: none;
}

.play.streamer .music-chip {
  display: none;
}

/* the stage's deliberate interactive exceptions: audio/music unlock
   (reachable via the obs browser-source "Interact" window) */
.stage .stage-unlock,
.stage .music-unlock {
  pointer-events: auto;
}

.stage-unlock {
  position: absolute;
  bottom: 0.6rem;
  left: 0.6rem;
  background: rgba(10, 10, 16, 0.92);
  border: 1px solid var(--warn);
  border-radius: 6px;
  color: var(--fg);
  padding: 0.3rem 0.7rem;
  cursor: pointer;
}

/* the pipped share + the gm's one-click slot switch under it: the wrap
   is the positioned box so the button can never anchor astray */
.share-pip-wrap {
  position: absolute;
  right: 0.5rem;
  bottom: 0.5rem;
  width: 14rem;
  z-index: 20;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  align-items: flex-end;
}

.share-pip-wrap .content-slot.pip {
  position: static;
  width: 100%;
  margin: 0;
}

.share-pip-wrap .switch-slot {
  background: rgba(10, 10, 16, 0.92);
  border: 1px solid var(--accent);
  border-radius: 4px;
  color: var(--fg);
  padding: 0.2rem 0.5rem;
  cursor: pointer;
  font-size: 0.8rem;
}

.stage-share video {
  width: 100%;
  max-height: 70vh;
  object-fit: contain;
  display: block;
  background: #000;
}

/* ---- keyboard shortcuts overlay (p7 a11y floor) ---- */

.shortcuts-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 40;
}

.shortcuts-overlay {
  background: #1c1c26;
  border: 1px solid #3b3b4d;
  border-radius: 6px;
  padding: 1.2rem 1.5rem;
  max-width: 26rem;
}

.shortcuts-overlay h3 {
  margin: 0 0 0.8rem;
}

.shortcuts-overlay table {
  border-collapse: collapse;
  width: 100%;
}

.shortcuts-overlay td {
  padding: 0.2rem 0.6rem 0.2rem 0;
}

.shortcuts-overlay kbd {
  background: #2a2a38;
  border: 1px solid #3b3b4d;
  border-radius: 4px;
  padding: 0.05rem 0.4rem;
  font-size: 0.85em;
  white-space: nowrap;
}

.shortcuts-overlay button {
  margin-top: 0.8rem;
}

/* keyboard users get a visible focus ring everywhere */
:focus-visible {
  outline: 2px solid #7aa2ff;
  outline-offset: 1px;
}

/* admin p7 additions */
.admin-page .danger {
  color: #ff8484;
  border-color: #6e3a3a;
}

.admin-page .disk-usage {
  color: #9a9ab0;
  font-size: 0.85em;
  margin: 0 0.5rem;
}

.admin-page a.button-like {
  border: 1px solid #3b3b4d;
  border-radius: 4px;
  padding: 0.15rem 0.5rem;
  text-decoration: none;
  font-size: 0.9em;
}

.admin-page .limits label {
  display: inline-flex;
  flex-direction: column;
  gap: 0.2rem;
  margin-right: 0.8rem;
}

/* ---- empty states & onboarding (specs/11, p7) ---- */

.empty-state {
  color: #9a9ab0;
  font-size: 0.9em;
  padding: 0.6rem 0.8rem;
  border: 1px dashed #3b3b4d;
  border-radius: 6px;
  margin: 0.6rem 0;
}

.onboarding-card {
  position: absolute;
  right: 1rem;
  bottom: 3.2rem;
  z-index: 12;
  background: rgba(22, 22, 32, 0.92);
  border: 1px solid #3b3b4d;
  border-radius: 8px;
  padding: 0.7rem 0.9rem;
  max-width: 17rem;
}

.onboarding-card header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.4rem;
}

.onboarding-card ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.onboarding-card li {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.15rem 0;
}

.onboarding-card li.done {
  opacity: 0.6;
}

.onboarding-card li.done .linkish {
  text-decoration: line-through;
}

button.linkish {
  background: none;
  border: none;
  color: #7aa2ff;
  cursor: pointer;
  padding: 0;
  font: inherit;
  text-decoration: underline;
}

/* ---- phase 8: session tooling (specs/14) ---- */

/* shared timer chip (overlay chrome) */
.timer-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.7rem;
  border-radius: 999px;
  background: rgba(20, 20, 30, 0.75);
  border: 1px solid var(--accent, #7aa2f7);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}

.timer-chip .timer-label {
  opacity: 0.8;
  font-size: 0.85rem;
}

.timer-chip .timer-remaining {
  font-weight: bold;
  font-size: 1.05rem;
}

.timer-chip.paused {
  opacity: 0.7;
}

.timer-chip.final-minute {
  border-color: #d5734f;
}

.timer-chip.final-minute .timer-remaining {
  color: #ff9d6e;
  animation: timer-pulse 1s ease-in-out infinite;
}

.timer-chip.expired {
  border-color: #e05555;
  animation: timer-pulse 0.6s ease-in-out 4;
}

.timer-chip.no-motion,
.timer-chip.no-motion .timer-remaining {
  animation: none;
}

@keyframes timer-pulse {
  50% { transform: scale(1.06); }
}

@media (prefers-reduced-motion: reduce) {
  .timer-chip, .timer-chip .timer-remaining { animation: none; }
}

/* breakout room rail */
.room-rail {
  border-top: 1px solid #33334a;
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.rooms-degraded {
  font-size: 0.8rem;
}

.room-group {
  border: 1px solid #2c2c3e;
  border-radius: 6px;
  padding: 0.3rem 0.45rem;
}

.room-group.here {
  border-color: var(--accent, #7aa2f7);
}

.room-header {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.room-name {
  font-weight: 600;
  font-size: 0.85rem;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.room-join {
  font-size: 0.75rem;
  padding: 0.05rem 0.5rem;
}

.room-occupants {
  list-style: none;
  margin: 0.2rem 0 0;
  padding: 0;
}

.room-occupants li {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.1rem 0;
  font-size: 0.85rem;
}

.room-occupants .avatar,
.room-occupants .initials {
  width: 1.3rem;
  height: 1.3rem;
  border-radius: 50%;
  font-size: 0.6rem;
}

.room-occupants .member-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.room-move-menu {
  font-size: 0.7rem;
  max-width: 8rem;
}

.room-gm-controls {
  display: flex;
  gap: 0.3rem;
  flex-wrap: wrap;
}

.room-gm-controls button {
  font-size: 0.75rem;
}

.room-badge {
  font-size: 0.75rem;
  opacity: 0.85;
  white-space: nowrap;
}

/* video-tile identity chip (specs/04) */
.tile-identity .avatar,
.tile-identity .initials {
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  font-size: 0.6rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* notebook grouping (specs/08 private docs) */
.doc-group {
  margin: 0.6rem 0 0.2rem;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  opacity: 0.7;
}

.doc-create-private {
  font-size: 0.8rem;
  align-self: flex-start;
}

/* timer gm controls */
.timer-section .timer-controls {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex-wrap: wrap;
  margin-bottom: 0.35rem;
}


/* ---- structured play (specs/15) ---- */
.game-panel { display: flex; flex-direction: column; gap: 0.75rem; overflow-y: auto; }
.game-runbar { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.game-status { font-weight: 600; }
.game-paused { color: var(--warn, #e0af68); }
.game-ap-row { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.ap-chip, .grant-chip {
  font-size: 0.8rem; padding: 0.1rem 0.5rem; border-radius: 999px;
  background: color-mix(in srgb, var(--accent, #7aa2f7) 18%, transparent);
}
.pile-grid { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.pile {
  display: flex; flex-direction: column; align-items: center; gap: 0.2rem;
  padding: 0.5rem; border-radius: 8px; min-width: 5.5rem;
}
.pile.selected { outline: 2px solid var(--accent, #7aa2f7); }
.pile.disabled { opacity: 0.45; }
.pile-back { width: 100%; height: 100%; object-fit: cover; border-radius: 4px; }
.pile-back.generic {
  font-size: 2.4rem; line-height: 1; display: flex;
  align-items: center; justify-content: center;
}
/* printed backs: the top card's title over the back visual. the wrap owns
   the card shape so a title-only back still gets a full card to fill */
.pile-back-wrap { position: relative; display: block; width: 3rem; height: 4.2rem; }
.pile-back-label {
  position: absolute; inset: 0.15rem; display: flex; align-items: center;
  justify-content: center; text-align: center; padding: 0.1rem;
  font-size: 0.68rem; line-height: 1.15; word-break: break-word;
  overflow: hidden; border-radius: 4px;
  background: rgba(10, 10, 16, 0.45);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
}
.pile-count, .pile-top, .evidence-meta { font-size: 0.72rem; opacity: 0.75; }
.take-card { width: 100%; margin-top: 0.4rem; }
/* free-pick spread (specs/15): every undrawn card, backs only, one per
   realized slot. same card shape as a pile so the two read alike */
.pile-spread {
  display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.4rem;
}
/* roomier than a pile thumb: these carry a card *name* the player has to
   read and choose between, not just a "there is a pile here" marker */
.spread-card {
  position: relative; display: block; width: 4.8rem; height: 6.6rem;
  padding: 0; border-radius: 5px; border: 1px solid #2a2a37;
}
.spread-card:not(:disabled):hover { border-color: var(--accent, #7aa2f7); }
.spread-card:disabled { opacity: 0.45; cursor: default; }
.spread-card.armed {
  border-color: var(--accent, #7aa2f7);
  box-shadow: 0 0 0 2px rgba(122, 162, 247, 0.35);
}
.spread-label {
  position: absolute; inset: 0.2rem; display: flex; align-items: center;
  justify-content: center; text-align: center; padding: 0.15rem;
  font-size: 0.8rem; line-height: 1.2;
  /* only break a word that can't fit on its own line — the old
     `word-break: break-word` split every name mid-syllable */
  overflow-wrap: break-word; hyphens: auto;
  overflow: hidden; border-radius: 4px;
  background: rgba(10, 10, 16, 0.55);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
}
/* an ap is spent the instant the pick lands, so say which card first */
.pick-confirm {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem;
  margin-top: 0.5rem; padding: 0.4rem 0.55rem; border-radius: 6px;
  background: #1b1b26; border: 1px solid var(--accent, #7aa2f7);
}
.pick-question { font-size: 0.85rem; }
.pick-cost { font-size: 0.72rem; opacity: 0.75; }
.pick-take { margin-left: auto; }
.take-blocked { margin-top: 0.3rem; }
.card-back-label { width: 8rem; font-size: 0.75rem; }
.card-list { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.game-card {
  display: flex; flex-direction: column; align-items: center; gap: 0.2rem;
  max-width: 7rem; font-size: 0.8rem; padding: 0.4rem; border-radius: 6px;
}
.game-card.shown { outline: 1px dashed var(--accent, #7aa2f7); }
.card-thumb { width: 3rem; height: 4.2rem; object-fit: cover; border-radius: 4px; }
.card-thumb.text { font-size: 2rem; display: grid; place-items: center; }
.game-card-viewer { max-width: min(90vw, 40rem); }
.game-card-viewer .card-image { max-width: 100%; max-height: 60vh; }
.game-card-viewer .card-frame { width: 100%; height: 60vh; border: 0; }
.card-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; padding-top: 0.5rem; }
.vote-options { display: flex; flex-direction: column; gap: 0.3rem; }
.vote-option.picked { outline: 2px solid var(--accent, #7aa2f7); }
.vote-matrix td { padding: 0.15rem 0.6rem; }
.game-gm-controls .gm-row { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.gm-ap-row { display: inline-flex; gap: 0.25rem; align-items: center; margin-right: 0.6rem; }
.gm-confirm { border: 1px solid var(--warn, #e0af68); border-radius: 6px; padding: 0.5rem; }
.act-preview { white-space: pre-wrap; font-size: 0.8rem; opacity: 0.9; }
.prep-row { display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center; margin: 0.25rem 0; }
.prep-block { border-top: 1px solid color-mix(in srgb, currentColor 15%, transparent); padding-top: 0.5rem; }
.prep-toggle { text-align: left; width: 100%; }
/* keep the reorder arrows on the title's line: the pile list is long and
   a wrapped second row per pile would double it */
.pile-row { flex-wrap: nowrap; }
.pile-row .prep-toggle { width: auto; flex: 1; min-width: 0; }
.readiness.ready { color: var(--ok, #9ece6a); }
.card-titles { font-size: 0.8rem; margin: 0.25rem 0 0.25rem 1rem; }
.show-toast { position: fixed; bottom: 4.5rem; right: 1rem; z-index: 40; }
.reveal-banner {
  position: absolute; top: 0.5rem; left: 50%; transform: translateX(-50%);
  z-index: 5; padding: 0.35rem 0.9rem; border-radius: 999px;
}
/* gm prep workspace: large overlay — the sidebar column is too cramped
   for deck building */
.prep-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 35;
}

.prep-overlay {
  display: flex;
  flex-direction: column;
  width: min(94vw, 78rem);
  height: min(92vh, 60rem);
  background: #1d1d26;
  border: 1px solid #44445a;
  border-radius: 8px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}

.prep-header {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 0.5rem 0.9rem;
  background: #26263a;
  border-radius: 8px 8px 0 0;
}

.prep-header h3 { margin: 0; }
.prep-header .prep-close { margin-left: auto; font-size: 1rem; }

.prep-body {
  display: grid;
  grid-template-columns: minmax(20rem, 26rem) 1fr;
  gap: 1.2rem;
  padding: 0.9rem;
  overflow-y: auto;
  align-items: start;
}

.prep-side, .prep-main { display: flex; flex-direction: column; gap: 0.75rem; min-width: 0; }

@media (max-width: 60rem) {
  .prep-body { grid-template-columns: 1fr; }
}

/* file inputs: compact, button-styled picker instead of a full-width bar */
.prep-overlay input[type="file"] { max-width: 16rem; }
.prep-overlay input[type="file"]::file-selector-button,
.game-panel input[type="file"]::file-selector-button {
  background: #2a2a38;
  color: inherit;
  border: 1px solid #3b3b4d;
  border-radius: 4px;
  padding: 0.15rem 0.6rem;
  margin-right: 0.5rem;
  cursor: pointer;
}

/* upload labels: keep caption + picker on one line */
.pile-back-upload, .card-bulk-upload {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
}

.pile-fields > label { display: inline-flex; align-items: center; gap: 0.3rem; margin-right: 0.6rem; }

/* delete rides the identity row, pushed off Save when the line has room */
.pile-fields .pile-delete { margin-left: auto; }
.pile-fields .danger { color: var(--danger, #f7768e); }
.pile-fields .danger:disabled { color: inherit; opacity: 0.45; cursor: not-allowed; }
.prep-note { font-size: 0.8rem; opacity: 0.75; }

/* card rows: name flexes, controls hug the right; the per-card back
   picker clips to just its button */
.card-titles li { display: flex; align-items: center; gap: 0.35rem; }
.card-titles .card-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.card-titles .card-rename { flex: 1; min-width: 0; }
/* prep back previews: pile-level next to the picker, card-level in rows */
.back-preview { width: 1.6rem; height: 2.2rem; object-fit: cover; border-radius: 3px; }
.back-preview.generic { font-size: 1.5rem; line-height: 1; opacity: 0.8; }
.card-back-thumb { width: 1.1rem; height: 1.5rem; object-fit: cover; border-radius: 2px; }
/* per-card back picker: the label is the button, native input hidden */
.card-back-upload input[type="file"] { display: none; }
.card-back-upload {
  background: #2a2a38;
  border: 1px solid #3b3b4d;
  border-radius: 4px;
  padding: 0.1rem 0.5rem;
  font-size: 0.75rem;
  cursor: pointer;
}

/* one channel for success and refusal text — keep it neutral */
.prep-status {
  margin: 0.25rem 0;
  font-size: 0.85rem;
  color: var(--accent, #7aa2f7);
}

/* planned rooms (prep) */
.planned-rooms { margin: 0.25rem 0; padding: 0; list-style: none; font-size: 0.85rem; }
.planned-rooms li { display: flex; align-items: center; gap: 0.35rem; }

/* come-join-me invites (specs/14) */
.room-invite-menu { max-width: 3.2rem; }
.invite-toast {
  position: fixed;
  right: 1rem;
  bottom: 8rem;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: #26263a;
  border: 1px solid var(--accent, #7aa2f7);
  border-radius: 6px;
  padding: 0.4rem 0.6rem;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
}
.invite-toast.outcome { bottom: 11.5rem; border-color: #3b3b4d; }

/* streamer rooms + evidence menu bodies */
.streamer-rooms, .streamer-evidence {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 0.5rem 0.7rem;
}
.streamer-evidence h5 { margin: 0.3rem 0 0.1rem; }
.streamer-room-row, .streamer-card-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.streamer-room-row.here { opacity: 0.85; }
.streamer-room-row > span:first-child, .streamer-card-row .card-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.game-reveal.flourish { animation: reveal-flourish 700ms ease-out; }
@keyframes reveal-flourish {
  from { transform: scale(0.92); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .game-reveal.flourish { animation: none; }
}
.dismiss-presentation { margin-left: auto; }

/* download policy (specs/07) — gm-only section above the library */
.download-settings {
  border-bottom: 1px solid #2a2a35;
  padding-bottom: 0.6rem;
  margin-bottom: 0.6rem;
}
.download-default {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}
.download-default .check { flex: 1; }
.info-toggle {
  background: none;
  border: none;
  color: #9aa0a6;
  cursor: pointer;
  font-size: 0.95rem;
  line-height: 1;
  padding: 0.15rem 0.3rem;
}
.info-toggle:hover, .info-toggle[aria-expanded="true"] { color: var(--accent); }
.download-guide { max-width: 32rem; }
.download-guide p { margin: 0 0 0.6rem; font-size: 0.85rem; line-height: 1.45; }
.download-guide p:last-child { margin-bottom: 0; }
.download-exceptions {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.download-exceptions li {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.82rem;
}
.download-exceptions .ex-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.download-exceptions .ex-resolved { color: #9aa0a6; font-size: 0.75rem; }

/* ---- settings tab (sidebar) ---- */

.settings-panel {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  overflow-y: auto;
}

.settings-group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.4rem;
}

.settings-group .switch-player,
.settings-group .streamer-toggle {
  font-size: 0.85rem;
}

.settings-group h3 {
  margin: 0;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #9aa0a6;
}

.settings-group > .hint {
  margin: 0;
}

.settings-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.4rem;
}

/* the player's present toggle on a collection card (specs/07) */
.collection-item .present-toggle {
  padding: 0.1rem 0.3rem;
  background: none;
  border: none;
  font-size: 0.9rem;
}

.collection-item .present-toggle.active {
  color: var(--accent);
}
