/* demos.css — shared baseline styling for every demo (BUILD_PLAN stage 10).
 *
 * Loaded from each demo's index.html with an absolute path so it resolves in
 * both solo mode (/demos/<id>/index.html) and via /s/<code> (where a <base> tag
 * rewrites relative paths to the demo folder):
 *
 *   <link rel="stylesheet" href="/demos.css">
 *
 * This holds the chrome common to all demos — page reset, typography, buttons,
 * the participant roster bar, and dark-mode theming for those. Demo-specific
 * layout (the #app container width, canvases, grids, piles, tiles, sliders) and
 * any demo-only controls stay in that demo's own <style> block. The inline
 * block loads after this sheet, so a demo can override any rule here at equal
 * specificity (e.g. each demo sets where its roster sits). */

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  background: #f9f9f7;
  color: #1a1a1a;
  margin: 0;
  padding: 2rem;
  display: flex;
  flex-direction: column;
  align-items: center;
}

h1 {
  font-size: 20px;
  font-weight: 500;
  margin: 0 0 1.5rem;
}

label {
  font-size: 14px;
  color: #555;
  white-space: nowrap;
}

button {
  font-size: 13px;
  padding: 5px 14px;
  border: 0.5px solid #bbb;
  border-radius: 8px;
  background: white;
  cursor: pointer;
  white-space: nowrap;
}
button:hover { background: #f0f0f0; }

/* Participant roster bar (the live who's-here strip). The look lives here; each
 * demo positions it (margins, width) in its own block, since some show it above
 * the board and some below. */
.roster {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  font-size: 13px;
  color: #555;
  min-height: 1.2em;
}
.roster .who { display: flex; align-items: center; gap: 6px; }
.roster .dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  display: inline-block;
}

/* "Animate" link added by /animate-link.js on a demo page: opens the animator for
 * this demo, carrying the current board across. Fixed in the corner so it never
 * disturbs the demo's own layout. */
.animate-link {
  position: fixed;
  top: 12px;
  right: 12px;
  z-index: 10;
  font-size: 13px;
  padding: 5px 12px;
  border: 0.5px solid #bbb;
  border-radius: 8px;
  background: white;
  color: #1a1a1a;
  text-decoration: none;
  cursor: pointer;
}
.animate-link:hover { background: #f0f0f0; }

/* Settings panel (renderSettingsPanel, demos.js, BUILD_PLAN stages 21-22): the
 * generic layout every demo's settingsSchema renders through, so a demo no
 * longer hand-rolls its own toggle/slider markup and a new demo inherits the
 * look for free. Each demo still positions/sizes the panel itself (width,
 * margins) in its own <style> block, the same split as .roster above. */
/* A genuine two-column table (border, alternating row shading, a column
 * divider) so it's unambiguous which row a "Shared" toggle belongs to,
 * especially once a demo has more than one or two settings. .settings-panel
 * is the grid that owns the column tracks; each .setting-row is itself a
 * subgrid spanning both of them, so its two cells (.setting-main,
 * .setting-shared-col) always land on exactly the same x position as every
 * other row's - that shared alignment is what lets a border on
 * .setting-shared-col (see below) chain seamlessly row to row into what
 * reads as one continuous rule down the full height of the panel, rather
 * than a border on each row independently (which can only ever extend as far
 * as that row's own edges). */
.settings-panel {
  display: grid;
  grid-template-columns: 1fr auto;
  border: 0.5px solid #bbb;
  border-radius: 8px;
  overflow: hidden; /* clip the alternating shading to the rounded corners */
}
.setting-row {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
}
.setting-row:nth-child(even) { background: #f2f2ef; }
.setting-row + .setting-row { border-top: 0.5px solid #e2e2e2; }
.setting-main {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 7px 12px;
  min-width: 0; /* grid items default to min-width: auto, which can push the
    column wider than 1fr to fit unwrapped content - same fix as the label
    below, one level up. */
}
/* Fixed-width label column so every row's control starts at the same x
 * position, reinforcing the table look started by the shading/dividers above.
 * min-width: 0 overrides the flex default (min-width: auto), which otherwise
 * lets a long label's un-wrapped content grow the column past 130px anyway -
 * overflow/ellipsis then truncates rather than silently breaking alignment. */
.setting-label {
  flex: 0 0 160px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* A standalone toggle button - one control, its own "on" colour when active -
 * for any boolean-ish choice in the panel (a "boolean"-kind setting's control,
 * and the coach-only "Shared"/"Sync" toggles below). Base look (border,
 * padding, colour) already comes from the plain `button` rule above; this
 * only adds the "on" state, matching .mode-toggle's own active/hover look. */
.toggle-btn.active { background: #1a1a1a; color: white; }
.toggle-btn:hover:not(.active):not(:disabled) { background: #f0f0f0; }

/* The coach-only "Shared"/"Sync" toggle-btns: smaller and more muted than a
 * demo's own setting control, since they're an administrative layer on top of
 * it, not the setting itself. Sync (when present) is the only one still
 * inside .setting-main - margin-left: auto pushes it flush against that
 * cell's right edge, i.e. right up against the divider, so it reads as
 * grouped with Shared even from its own cell. */
.setting-share {
  margin-left: auto;
  flex: 0 0 auto;
  padding: 3px 10px;
  font-size: 12px;
  color: #666;
}
/* Shared's own column: fixed width (grid-template-columns: auto above sizes
 * it once, uniformly, to fit "Shared" - every row's cell is the same width
 * since every row's cell holds identical text), and the divider lives here
 * rather than on the button. A .setting-row is a subgrid (above), so this
 * cell stretches to the row's full height by default, including the row's
 * own padding - unlike a border on the button, which only ever spans the
 * button's own ~14px, this spans the whole row, and with no gap between grid
 * rows, adjacent rows' cells chain into one line the full height of the
 * panel. 1px/#999 rather than this file's usual 0.5px/#bbb hairline, for the
 * same reason a hairline needs to be a real rule here, not this file's usual
 * subtle one. */
.setting-shared-col {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 7px 12px;
  border-left: 0.5px solid #bbb;
}

/* A "number"-kind (dispatched) settings-panel row: a stepper (-/value/+), the
 * same pill shape as .mode-toggle (border, rounded corners, buttons flush
 * against each other) with a live value readout in the middle instead of a
 * third button. Suits a small discrete range (e.g. twirling-tiles' triangle
 * count, 1-8) better than a slider, whose fine-motor dragging buys nothing
 * over a handful of positions. */
.stepper {
  display: flex;
  border: 0.5px solid #bbb;
  border-radius: 8px;
  overflow: hidden;
}
.stepper-btn {
  border: none;
  border-radius: 0;
  padding: 5px 12px;
  font-size: 13px;
  background: white;
  cursor: pointer;
  color: #555;
}
.stepper-btn:first-child { border-right: 0.5px solid #bbb; }
.stepper-btn:last-child { border-left: 0.5px solid #bbb; }
.stepper-btn:hover:not(:disabled) { background: #f0f0f0; }
.stepper-btn:disabled { cursor: not-allowed; opacity: 0.5; }
/* Fixed-width so a digit-width change (9 -> 10) doesn't shift the buttons
 * either side of it. */
.setting-value {
  flex: 0 0 auto;
  min-width: 1.6em;
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  text-align: right;
}
.stepper-value {
  padding: 5px 10px;
  text-align: center;
}

/* A button-group choice control, used by a "choice"-kind settings-panel row.
 * flex: 1 1 auto fills whatever width .setting-main leaves it (so every row's
 * group is the same width regardless of its own option count or label
 * lengths), and each button's flex: 1 1 0 (below) then splits that width
 * evenly among just its own row's options - two options get halves, three get
 * thirds, etc. */
.mode-toggle {
  display: flex;
  gap: 0;
  border: 0.5px solid #bbb;
  border-radius: 8px;
  overflow: hidden;
  flex: 1 1 auto;
}
.mode-toggle button {
  flex: 1 1 0;
  border: none;
  border-radius: 0;
  border-right: 0.5px solid #bbb;
  padding: 5px 12px;
  font-size: 13px;
  background: white;
  cursor: pointer;
  color: #555;
}
.mode-toggle button:last-child { border-right: none; }
.mode-toggle button.active { background: #1a1a1a; color: white; }
.mode-toggle button:hover:not(.active):not(:disabled) { background: #f0f0f0; }
.mode-toggle button:disabled { cursor: not-allowed; opacity: 0.5; }

/* Every demo's board canvas handles its own taps/drags via Pointer Events
 * (stage 15); without this the browser steals a tap for scroll or
 * double-tap-zoom before the canvas ever sees it. */
canvas { touch-action: none; }

/* Platform connection chrome (stage 16), owned by room.js and appended to
 * <body>. The offline indicator shows while the socket is down; the reconnect
 * notice tells the user their offline (sandbox) edits were discarded. */
.offline-indicator {
  position: fixed;
  bottom: 12px;
  left: 12px;
  z-index: 20;
  font-size: 13px;
  padding: 6px 12px;
  border-radius: 8px;
  background: #b45309;
  color: white;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}
.reconnect-notice {
  position: fixed;
  bottom: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: min(90vw, 480px);
  font-size: 13px;
  padding: 8px 12px;
  border-radius: 8px;
  border: 0.5px solid #bbb;
  background: white;
  color: #1a1a1a;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}
.reconnect-notice-close {
  flex: none;
  padding: 0 6px;
  font-size: 16px;
  line-height: 1;
  border: none;
  background: transparent;
  color: #666;
  cursor: pointer;
}

/* Who-can-act chrome (BUILD_PLAN stage 24), folded into whatever roster a
 * demo already renders (a follow-up at the coach's own request, rather than
 * the standalone top-left control this stage originally shipped with) -
 * room.js owns the click wiring/highlighting, appended as a post-render pass
 * over the demo's own `.roster`, so no demo needs any code change. The
 * highlighted entry (the current presenter, or the coach's own name in
 * coach-only mode) is visible to every participant, not just the coach -
 * the same information the "Watching - ..." banner already reveals; only the
 * click handling is coach-only. Clicking the already-highlighted name is the
 * only way back to "everyone" - a separate reset button was tried and
 * removed again, at the coach's own request, in favour of this one
 * interaction surface. */
.roster .who.acting-target {
  background: #1a1a1a;
  color: white;
  border-radius: 10px;
  padding: 1px 8px;
}
.roster .who.acting-clickable {
  cursor: pointer;
}
.roster .who.acting-clickable:not(.acting-target):hover {
  background: #f0f0f0;
  border-radius: 10px;
}
.watching-banner {
  position: fixed;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  font-size: 13px;
  padding: 6px 12px;
  border-radius: 8px;
  background: #374151;
  color: white;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}

/* Scrub control (BUILD_PLAN stage 25), owned by room.js (renderScrubControl,
 * demos.js) and appended to <body> like the platform chrome above - always
 * shown in networked mode, no permission gate. Reuses .stepper/.stepper-btn
 * (the settings panel's numeric stepper) and .toggle-btn rather than bespoke
 * button styling, so dark mode is correct for free. */
.scrub-control {
  position: fixed;
  bottom: 12px;
  right: 12px;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  padding: 6px 10px;
  border-radius: 8px;
  border: 0.5px solid #bbb;
  background: white;
  color: #1a1a1a;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}
.scrub-position {
  min-width: 3.5em;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.scrub-status {
  color: #b45309;
  font-weight: 600;
}
/* Follower state (BUILD_PLAN stage 26): a presenter is driving my view, so my
 * own controls are suspended. Muted to read as informational ("this is being
 * driven for me"), not as the amber "you are in a read-only past" warning a
 * private/driving scrub shows. */
.scrub-control.following .scrub-status {
  color: #6b7280;
  font-weight: 500;
}

/* Archiving chrome (BUILD_PLAN stage 29), owned by room.js like the indicators
 * above. The coach-only "Archive session" button sits top-right (clear of the
 * bottom-right scrub control); the "archived" indicator, shown to everyone once
 * frozen, reuses the .watching-banner look (top-centre) in a distinct slate so a
 * finished session reads as deliberate, not as a warning. */
.archive-button {
  position: fixed;
  top: 12px;
  right: 12px;
  z-index: 20;
  font-size: 13px;
  padding: 6px 12px;
  border-radius: 8px;
  border: 0.5px solid #bbb;
  background: white;
  color: #1a1a1a;
  cursor: pointer;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}
.archive-button:hover {
  background: #f0f0f0;
}
.archived-indicator {
  position: fixed;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  font-size: 13px;
  padding: 6px 12px;
  border-radius: 8px;
  background: #475569;
  color: white;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}

@media (prefers-color-scheme: dark) {
  body { background: #111; color: #e0e0e0; }
  button { background: #222; border-color: #444; color: #e0e0e0; }
  button:hover { background: #333; }
  label, .roster { color: #aaa; }
  .animate-link { background: #222; border-color: #444; color: #e0e0e0; }
  .animate-link:hover { background: #333; }
  .reconnect-notice { background: #222; border-color: #444; color: #e0e0e0; }
  .reconnect-notice-close { color: #aaa; }
  .settings-panel { border-color: #444; }
  .setting-row:nth-child(even) { background: #1b1b1b; }
  .setting-row + .setting-row { border-top-color: #333; }
  .setting-share { color: #aaa; }
  .setting-shared-col { border-left-color: #666; }
  .toggle-btn.active { background: #e0e0e0; color: #111; }
  .toggle-btn:hover:not(.active):not(:disabled) { background: #333; }
  .mode-toggle { border-color: #444; }
  .mode-toggle button { background: #222; border-right-color: #444; color: #aaa; }
  .mode-toggle button.active { background: #e0e0e0; color: #111; }
  .mode-toggle button:hover:not(.active):not(:disabled) { background: #333; }
  .stepper { border-color: #444; }
  .stepper-btn { background: #222; color: #aaa; }
  .stepper-btn:first-child { border-right-color: #444; }
  .stepper-btn:last-child { border-left-color: #444; }
  .stepper-btn:hover:not(:disabled) { background: #333; }
  .roster .who.acting-target { background: #e0e0e0; color: #111; }
  .roster .who.acting-clickable:not(.acting-target):hover { background: #333; }
  .scrub-control { background: #222; border-color: #444; color: #e0e0e0; }
  .scrub-control.following .scrub-status { color: #9ca3af; }
  .archive-button { background: #222; border-color: #444; color: #e0e0e0; }
  .archive-button:hover { background: #333; }
  .archived-indicator { background: #334155; }
}
