:root {
  --face: #c0c0c0;
  --light: #ffffff;
  --shadow: #808080;
  --navy: #000080;
  --ink: #000000;
  --tap: 34px;
}
* { box-sizing: border-box; }

/* `hidden` loses to any display rule set on the same element, and .app, .stage
   and .veil all set one. Without this the join screen never goes away. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: #008080;
  font: 13px/1.45 "Segoe UI", Tahoma, "MS Sans Serif", system-ui, sans-serif;
  color: var(--ink);
  min-height: 100vh;
  -webkit-text-size-adjust: 100%;
}

.win { background: var(--face); border: 2px outset var(--face); }
.title-bar {
  background: linear-gradient(90deg, var(--navy), #1084d0);
  color: #fff; font-weight: 700; padding: 4px 7px;
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
}
/* The title bar's caption is a real heading now (H1 on the landing screen,
   H2 on the about panel below it) — reset the browser defaults so it still
   renders exactly like the plain label it replaced. */
.title-bar h1, .title-bar h2 { margin: 0; font: inherit; }
.win-body { padding: 10px; }
.win-body.tight { padding: 6px; }
.badge { font-weight: 400; font-size: 11px; opacity: .9; white-space: nowrap; }

.btn {
  font: inherit; padding: 7px 14px; cursor: pointer; min-height: var(--tap);
  background: var(--face); border: 2px outset var(--face); color: var(--ink);
}
/* A fast double-click on a button must press it twice, not select its label —
   the mic toggle is exactly the button people hammer. */
.btn, .tool, .sizes button, .palette button {
  -webkit-user-select: none; user-select: none;
}
.btn:active:not(:disabled) { border-style: inset; }
.btn:disabled { color: var(--shadow); text-shadow: 1px 1px 0 var(--light); cursor: not-allowed; }
.btn.primary { font-weight: 700; width: 100%; }
.btn.correct { background: #b6f0b6; }
.btn.hot { background: #ffd3a8; }
.btn.cold { background: #bcd9ff; }

input, .select {
  font: inherit; padding: 7px; width: 100%; min-height: var(--tap);
  border: 2px inset var(--face); background: #fff; color: var(--ink);
}
.select { padding: 5px; }
label { display: block; margin: 10px 0 4px; font-weight: 700; }
.hint { color: #333; margin: 8px 0 0; }
.err { color: #a00000; font-weight: 700; margin: 6px 0 0; }

/* Join screen */
.gate { display: grid; place-items: center; min-height: 100vh; padding: 16px; }
.gate .win { width: min(380px, 100%); }
.lede { margin: 0 0 4px; }

/* Crawlable description of the game, shown below the join panel rather than
   inside it — real content for search, with zero effect on the join flow. */
.gate .about { width: min(380px, 100%); margin-top: 14px; }
.about p { margin: 0 0 8px; font-size: 12px; line-height: 1.5; }
.about p:last-child { margin-bottom: 0; }

/* Layout */
.app {
  display: grid; grid-template-columns: minmax(0, 1fr) 300px;
  gap: 10px; padding: 10px; align-items: start;
}
.canvas-win { min-width: 0; }

/* Intro stage — the word box and the countdown, in place of the canvas. */
.stage { padding: 6px; }
.intro {
  border: 2px inset var(--face); background: #fff;
  min-height: 260px; display: grid; place-items: center; padding: 24px 16px; text-align: center;
}
.intro h2 { margin: 0 0 12px; font-size: 18px; }
.intro .who { color: var(--navy); }
.intro form { width: min(420px, 100%); }
.intro input { text-align: center; font-size: 16px; }
/* The win announcement rides on the intro screen — a note above the next
   round already starting, not a stop of its own. */
.lastwin {
  background: #ffffc0; border: 1px solid var(--shadow);
  padding: 6px 12px; margin: 0 0 14px; font-weight: 700;
}
.count {
  font-size: clamp(64px, 22vw, 140px); font-weight: 700; line-height: 1;
  color: var(--navy); font-variant-numeric: tabular-nums;
}
.count.go { color: #008000; font-size: clamp(40px, 12vw, 80px); }

.workspace { display: flex; gap: 6px; }
/* One pane beside the canvas holds every control: tools, sizes, fill and
   colours. The canvas then owns the whole height instead of losing a strip at
   the bottom to the palette. */
.toolpane { flex: 0 0 96px; display: flex; flex-direction: column; gap: 6px; }
.tools { display: grid; grid-template-columns: repeat(2, 1fr); gap: 3px; align-content: start; }
/* Fills its grid cell rather than sitting at a fixed width inside one. The
   tools and the size buttons are both two-column grids in the same 96px pane,
   so a fixed width on one of them left two ragged columns of different widths
   stacked directly above each other. */
.tool {
  width: 100%; height: var(--tap); font-size: 15px; line-height: 1; cursor: pointer;
  background: var(--face); border: 2px outset var(--face); padding: 0;
}
/* The selected tool must be unmistakable next to a merely focused one, which is
   why the keyboard ring is an offset outline and never touches the bevel. */
.tool[aria-pressed="true"] {
  border-style: inset;
  background: #8fa8c8;
  box-shadow: inset 0 0 0 1px #fff;
}
.tool:focus { outline: none; }
.tool:focus-visible { outline: 2px dotted var(--navy); outline-offset: -6px; }
/* Undo and Clear do something rather than select something: never "pressed". */
.tool.act[aria-pressed] { border-style: outset; background: var(--face); box-shadow: none; }

.canvas-area { flex: 1; min-width: 0; }
.canvas-frame { position: relative; border: 2px inset var(--face); background: #fff; }
canvas { display: block; width: 100%; height: auto; touch-action: none; cursor: crosshair; }
canvas.locked { cursor: not-allowed; }

.veil { position: absolute; inset: 0; background: rgba(0,0,0,.45); display: grid; place-items: center; padding: 12px; }
.veil-inner { background: #ffffe1; border: 2px outset var(--face); padding: 10px 16px; font-weight: 700; text-align: center; }

.check { display: flex; align-items: center; gap: 5px; margin: 0; font-weight: 400; font-size: 11px; line-height: 1.2; }
.check input { width: auto; min-height: 0; }
.sizes { display: grid; grid-template-columns: repeat(2, 1fr); gap: 3px; padding: 0; }
.sizes button { width: 100%; height: var(--tap); background: var(--face); border: 2px outset var(--face); cursor: pointer; }
.sizes button[aria-pressed="true"] { border-style: inset; }
.sizes .dot { display: inline-block; background: #000; border-radius: 50%; }

/* Fixed-size swatches, so a narrow screen gets more rows rather than giant
   blocks of colour taking over the page. */
.palette { display: grid; grid-template-columns: repeat(4, 1fr); gap: 3px; padding: 0; }
/* The pencil is always one pixel, so the size buttons do not apply to it. */
.sizes.na { opacity: .4; }
.palette button { aspect-ratio: 1; border: 1px solid var(--shadow); cursor: pointer; padding: 0; }
.palette button[aria-pressed="true"] { outline: 2px solid var(--navy); outline-offset: -4px; }

.status { border-top: 1px solid var(--shadow); padding: 4px 8px; min-height: 24px; }

/* A guesser cannot draw, so the toolbox is dead weight on their screen — and on
   a phone it was pushing the guess box below the fold, where the keyboard then
   covered it entirely. */
body.watching .toolpane { display: none; }

/* The mic sits beside the box rather than under it: on a phone the box and the
   way you fill it belong on the same line. */
.guess-row { display: flex; gap: 6px; align-items: stretch; }
.guess-row input { flex: 1; min-width: 0; }
/* Held, not tapped — so a long press must neither scroll the page nor pop the
   long-press callout. */
.btn.mic {
  width: 46px; padding: 0; font-size: 17px; flex: 0 0 auto;
  touch-action: none; -webkit-touch-callout: none;
}
.btn.mic[aria-pressed="true"] { border-style: inset; background: #ffd3a8; }
#micHint:empty { margin: 0; }

/* Side panel */
.side { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
#copyBtn { width: 100%; margin-top: 6px; }
.players, .guesses { list-style: none; margin: 0; padding: 0; }
.players li { display: flex; justify-content: space-between; gap: 8px; padding: 4px; }
.players li.painting { background: #ffffc0; font-weight: 700; }
.players li.gone { color: var(--shadow); }
.players .pips { letter-spacing: 1px; }

/* Bounded and scrollable, so a long round cannot push the page around. */
.guesses {
  height: 210px; overflow-y: auto; overscroll-behavior: contain;
  border: 2px inset var(--face); background: #fff; padding: 4px;
}
.guesses li { padding: 4px; border-bottom: 1px solid #e6e6e6; overflow-wrap: anywhere; }
.guesses li.head { background: #ffffc0; }
.guesses li.mine { font-weight: 700; }
.guesses li.flash { animation: flash 1.2s ease-out; }
@keyframes flash { from { background: #ffe89a; } to { background: transparent; } }
.guesses .who { color: var(--navy); }
.guesses .verdict { float: inline-end; font-size: 10px; padding: 0 5px; border: 1px solid var(--shadow); }
.verdict.correct { background: #b6f0b6; }
.verdict.hot { background: #ffd3a8; }
.verdict.cold { background: #bcd9ff; }
.verdict.waiting { background: var(--face); color: var(--shadow); }

.guesses li.head { background: #ffffc0; }
.verdict-row { display: flex; gap: 4px; margin-top: 6px; }
.verdict-row .btn { flex: 1; padding: 6px 2px; min-height: 32px; font-size: 12px; }

/* Lobby */
.group { border: 2px inset var(--face); margin: 12px 0 0; padding: 8px 10px 10px; }
.group legend { font-weight: 700; padding: 0 4px; }
.radio { display: flex; align-items: center; gap: 6px; margin: 4px 0; font-weight: 400; }
.radio input { width: auto; min-height: 0; }
#createBtn, #joinBtn { margin-top: 8px; }
.rooms { list-style: none; margin: 0; padding: 0; max-height: 150px; overflow-y: auto; }
.rooms li { margin: 4px 0; }
.rooms button { width: 100%; text-align: start; font: inherit; cursor: pointer;
  background: var(--face); border: 2px outset var(--face); padding: 7px 9px; min-height: var(--tap); }
.rooms button:active { border-style: inset; }
.rooms .empty { color: var(--shadow); padding: 4px; }

@media (prefers-reduced-motion: reduce) {
  .guesses li.flash { animation: none; }
}

/* --- Narrow screens ---------------------------------------------------- */
@media (max-width: 900px) {
  .app { grid-template-columns: 1fr; padding: 6px; gap: 6px; }
  .side { flex-direction: column; }
  .guesses { height: 180px; }
}

@media (max-width: 620px) {
  /* The page itself must never scroll on a phone. The body's min-height:100vh
     is a Safari-toolbar taller than the dynamic viewport, and a swipe on the
     board's window chrome dragged that slack into view — shearing the whole
     layout up and leaving the bottom half cut off. Everything that needs to
     scroll (side panel, guess list, join screen) scrolls inside itself. */
  html, body { height: 100dvh; min-height: 0; overflow: hidden; overscroll-behavior: none; }
  /* The join screen can outgrow a small phone, so it scrolls internally.
     `safe` keeps the top reachable; browsers without it just centre. */
  .gate { height: 100dvh; min-height: 0; overflow-y: auto; place-items: center; place-items: safe center; }
  body { font-size: 14px; }
  /* iOS Safari zooms the page whenever a focused field is under 16px, and there
     is no way back out of that zoom. The keyboard opening must not move the
     page, so every field a thumb can land in is 16px on a phone. */
  input, .select, textarea { font-size: 16px; }
  .workspace { flex-direction: column; }
  .toolpane { flex: initial; order: 2; gap: 5px; }
  .tools { grid-template-columns: repeat(6, 1fr); gap: 4px; }
  .tool { height: 40px; font-size: 17px; }
  .canvas-area { order: 1; }
  .palette { grid-template-columns: repeat(auto-fill, minmax(20px, 1fr)); gap: 3px; max-width: 100%; }
  .sizes { grid-template-columns: repeat(4, 1fr); }
  .sizes button { height: 38px; }
  .check { font-size: inherit; }
  .intro { min-height: 200px; padding: 18px 12px; }

  /* No page scroll. The window is the board plus the guesses, and the list
     scrolls inside itself rather than pushing the canvas off the top.
     align-items must be restated: the base rule's `start` is vertical in the
     desktop grid, but in this flex column it governs WIDTH, and shrink-wrapped
     the guess and player windows to their content. */
  .app { height: 100dvh; display: flex; flex-direction: column; overflow: hidden; align-items: stretch; }
  .canvas-win { display: flex; flex-direction: column; min-height: 0; flex: 0 0 auto; }
  .stage { min-height: 0; }
  .canvas-area { min-height: 0; }
  /* Cap the height so the controls and the guess list always have somewhere to
     live — but cap it on the FRAME, not the canvas. Giving the canvas
     width:auto made its intrinsic 800px the min-content width of the whole
     column, which blew the window out to 825px and clipped half the tools. */
  .canvas-frame { max-width: min(100%, calc(36dvh * 4 / 3)); margin-inline: auto; }
  .side { flex: 1 1 auto; min-height: 0; overflow-y: auto; gap: 6px; }
  .guesses { height: 22dvh; }

  /* Every pixel spent on chrome is a pixel the painter cannot use to judge.
     The pane stays a column — making it a row collapsed the tool grid and put
     half the tools past the right edge — and the savings come from height:
     colours to one swipeable row, shorter buttons, and no status line (the
     title bar already says whose turn it is). */
  .tool { height: 36px; }
  /* The palette stays a wrapping grid. A single scrolling row was tried and
     reverted: 28 swatches make an 809px row, and that became the min-content
     width of the whole column no matter what min-width said, which pushed the
     canvas off the right edge. Forty pixels of height is the cheaper price. */
  .palette { grid-template-columns: repeat(auto-fill, minmax(20px, 1fr)); gap: 3px; }
  .sizes button { height: 32px; }
  .status { display: none; }
}
