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

/* Every theme's palette, ship colours, board texture and hit effect live in
   their own file under css/themes/, linked from index.html, and listed in
   js/themes/registry.js. Nothing in this file references a theme by name. */

body {
  font-family: system-ui, sans-serif;
  margin: 0;
  padding: 2rem 1rem;
  color: var(--ink);
  background: var(--page-bg);
  line-height: 1.4;
}

.game {
  max-width: 900px;
  margin: 0 auto;
  text-align: center;
}

/* Keeps the theme toggle reachable next to the title, outside every
   phase-gated .controls block, so it works mid-placement and mid-battle.
   flex-wrap: wrap so a phone-width viewport stacks these onto multiple
   centered lines instead of forcing one line whose overflow gets clipped
   symmetrically (title cut off on the left, quit-to-menu squeezed into the
   top-right corner) -- see the .board-panel comment below for the other
   half of this responsive pass. */
.header-row {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 1rem;
  row-gap: 0.5rem;
  flex-wrap: wrap;
}

h1 {
  margin-bottom: 0.25rem;
  font-size: 2rem;
  letter-spacing: -0.02em;
}

.status {
  font-size: 1.1rem;
  min-height: 1.6rem;
  margin: 0.75rem 0;
}

.status.win {
  color: var(--win-color);
  font-weight: bold;
}

.status.lose {
  color: var(--lose-color);
  font-weight: bold;
}

.controls {
  margin: 0.75rem 0 1.25rem;
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  flex-wrap: wrap;
}

/* Game mode choice, shown before the first placement and again after Play
   Again, so a rematch can switch modes instead of being locked into one. */
.mode-select {
  margin: 1.5rem 0;
  display: flex;
  gap: 0.75rem;
  justify-content: center;
  flex-wrap: wrap;
}

/* Hot-seat hand-off: replaces the whole board area with a single message and
   one button, so the outgoing player's board can never be left on screen
   for the incoming player to see. */
.handoff-screen {
  margin: 2rem auto;
  padding: 2rem;
  max-width: 420px;
  background: var(--surface-bg);
  border-radius: var(--panel-radius);
  box-shadow: 0 1px 4px var(--panel-shadow);
}

.handoff-screen p {
  margin: 0 0 1rem;
  font-size: 1.05rem;
}

/* Hot-seat player names: shown together before/during placement, since a
   name is not secret information the way a ship layout is, so both can be
   entered while the screen is still fully shared. */
.hotseat-names {
  margin: 0.75rem 0 1.25rem;
  display: flex;
  gap: 0.5rem;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  font-size: 0.9rem;
  color: var(--muted);
}

.hotseat-names input {
  font: inherit;
  padding: 0.35rem 0.6rem;
  border: 1px solid var(--water-border);
  border-radius: 6px;
  background: var(--surface-bg);
  color: var(--ink);
  width: 10rem;
}

[hidden] {
  display: none !important;
}

button,
select {
  font: inherit;
  padding: 0.5rem 1rem;
  border: 1px solid var(--water-border);
  border-radius: 6px;
  background: var(--surface-bg);
  color: var(--ink);
  cursor: pointer;
  transition: background-color 0.15s, box-shadow 0.15s;
}

button:hover,
select:hover {
  background: var(--surface-bg-hover);
}

button:active {
  background: var(--surface-bg-active);
}

.theme-label {
  font-size: 0.9rem;
  color: var(--muted);
}

.boards {
  display: flex;
  gap: 2.5rem;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 1rem;
}

/* Below ~860px, two 394px panels plus the 2.5rem (40px) gap between them
   (828px) no longer fit a phone or small-tablet viewport, so stack the
   panels instead of squeezing them side by side. align-items: center is
   needed here (not left implicit): .board-panel carries its own explicit
   width, so flex's default cross-axis stretch has nothing to stretch and
   would otherwise leave a narrower panel pinned to the start edge instead
   of centered under the wider one. */
@media (max-width: 860px) {
  .boards {
    flex-direction: column;
    align-items: center;
    gap: 1.25rem;
  }
}

/* Fixed, not min-width: the panel is a flex item of .boards with no
   max-width, so as a min-width-only box it grew to fit its widest child
   instead of the grid's actual 362px (grid-template-columns: 22px +
   10x32px + 10x2px gaps = 342 + 20). 394px = 362 + this panel's own 32px
   horizontal padding (1rem each side), the smallest width that fits the
   grid with zero slack, so a long player name in the heading below can no
   longer stretch blank space in beside it. width: min(394px, 100%) keeps
   that same floor on wide screens while still letting the panel shrink to
   fit a narrower viewport instead of forcing horizontal scroll; the long
   name is still contained by .board-panel h2's own overflow-wrap below,
   which wraps the name onto a second line rather than stretching anything
   once the panel itself can no longer grow past its content. */
.board-panel {
  background: var(--surface-bg);
  padding: 1rem;
  border-radius: var(--panel-radius);
  box-shadow: 0 1px 4px var(--panel-shadow);
  width: min(394px, 100%);
}

.board-panel h2 {
  margin-top: 0;
  font-size: 1rem;
  color: var(--muted);
  overflow-wrap: break-word;
}

/* Rings whichever board is currently taking fire. Because a hit now earns
   another shot, a single turn can run several shots long, and this makes the
   direction of fire readable at a glance while that plays out. Generic
   .board-panel selectors rather than #player-panel/#enemy-panel: in hot-seat
   each panel is now bound to a fixed player, so either physical panel can
   carry either state depending on whose turn it is. */
.board-panel.your-turn {
  box-shadow: 0 0 0 2px var(--preview-ok-edge), 0 1px 4px var(--panel-shadow);
}

.board-panel.under-fire {
  box-shadow: 0 0 0 2px var(--hit), 0 1px 4px var(--panel-shadow);
}

/* --cell-size is fluid so the grid (and .cell below, which inherits the
   custom property from here as its descendant) can shrink on a narrow
   viewport instead of forcing the board wider than the screen. The clamp's
   preferred value (9vw - 6.6px) is a straight-line fit of "the largest cell
   that keeps the full 11-column grid inside a phone-width .board-panel",
   solved from panel width = viewport - 32px (body's 1rem side padding) -
   32px (this panel's own 1rem side padding), and grid width = cell *
   (10 + 22/32) + 20px (10 gaps at 2px, label column at 22/32 of a cell) --
   see the .board-panel comment above for where the 32px paddings come from.
   The 27px floor and 32px ceiling bound it at the two ends: 32px matches
   the original fixed size once a viewport is wide enough (~426px) that the
   fixed grid already fit, and 27px keeps cells close to tappable size at
   the ~375px low end this was tuned for, accepting a little unclamped
   slack below that width, which is out of this pass's targeted range. */
.board-grid {
  --cell-size: clamp(27px, 9vw - 6.6px, 32px);
  position: relative;
  display: grid;
  grid-template-columns: calc(var(--cell-size) * 0.6875) repeat(10, var(--cell-size));
  grid-auto-rows: var(--cell-size);
  gap: 2px;
}

.label-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
  color: var(--muted);
}

.cell {
  position: relative;
  width: var(--cell-size);
  height: var(--cell-size);
  background: var(--water);
  border: 1px solid var(--water-border);
  border-radius: 3px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8rem;
  transition: background-color 0.15s;
}

.cell:hover {
  background: var(--water-hover);
}

.cell.miss,
.cell.hit,
.cell.sunk {
  z-index: 2;
}

.cell.miss {
  background: var(--miss);
  cursor: default;
}

.cell.miss::after {
  content: "\2022";
  color: var(--muted);
}

.cell.hit {
  background: var(--hit);
  cursor: default;
}

.cell.hit::after {
  content: "\2715";
  color: white;
  font-weight: bold;
}

.cell.sunk {
  background: var(--sunk);
  cursor: default;
}

.cell.sunk::after {
  content: "\2715";
  color: white;
  font-weight: bold;
}

/* Boat artwork. The boat itself is one SVG per ship, sitting in an overlay
   that spans the ship's whole footprint, so a 5 cell carrier is a single
   carrier rather than five rounded blocks. The overlay is out of flow, so it
   never disturbs the cells underneath it, and it ignores clicks so the cells
   under a boat stay clickable. ui.js sizes and positions it off the ship's
   first and last cell. */
.ship-overlay {
  position: absolute;
  z-index: 1;
  pointer-events: none;
}

.ship-svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* Hull colour comes from the ship-NAME class on the overlay, so the boat, the
   tray entry and the held ghost all read their colour from the same place. */
.ship-svg .ha-hull {
  fill: var(--ship-color, var(--ship));
}

.ship-svg .ha-dark {
  fill: rgba(0, 0, 0, 0.32);
}

.ship-svg .ha-mid {
  fill: rgba(255, 255, 255, 0.34);
}

.ship-svg .ha-light {
  fill: rgba(255, 255, 255, 0.82);
}

.ship-svg .ha-outline {
  stroke: rgba(0, 0, 0, 0.38);
  stroke-width: 5;
  stroke-linejoin: round;
}

.ship-svg .ha-line {
  fill: none;
  stroke: rgba(0, 0, 0, 0.4);
  stroke-width: 5;
  stroke-linecap: round;
}

.ship-svg .ha-foam {
  fill: none;
  stroke: rgba(255, 255, 255, 0.7);
  stroke-width: 5;
  stroke-linecap: round;
}

/* The hull code, painted once on the hull instead of once per cell, so it
   still tells the ships apart without relying on hue alone. */
.ship-svg .ha-code {
  fill: rgba(255, 255, 255, 0.92);
  font-family: system-ui, sans-serif;
  font-size: 26px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

/* A cell with a boat over it gets out of the boat's way: no ripple texture,
   no border. These come after .cell:hover on purpose, since they carry the
   same specificity and the boat has to win. Background stays var(--water),
   not transparent -- the ship-overlay's SVG art doesn't cover every pixel of
   its own rectangular footprint (rounded hull ends, and the board-grid's 2px
   gap between cells), so a literally transparent background here used to let
   .board-panel's background (white) show through in those gaps, reading as a
   pale rectangle boxing in every placed ship. */
.cell.over-boat {
  background: var(--water);
  border-color: transparent;
}

/* Damage over a hull is a translucent wash rather than a solid block, so the
   boat stays visible through it and a sinking reveals the whole ship. Cells
   on open water keep the solid markers above, where there is no hull to show
   through and legibility is all that matters. */
.cell.hit.over-boat {
  background: var(--hit-wash);
  box-shadow: inset 0 0 0 2px var(--hit);
}

.cell.sunk.over-boat {
  background: var(--sunk-wash);
  box-shadow: inset 0 0 0 2px var(--sunk-wash-edge);
}

.cell.hit.over-boat::after,
.cell.sunk.over-boat::after {
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.65);
}

/* Ship tray. Ships leave the tray as they are placed, and the one currently
   held by the cursor stays visible and highlighted so it is obvious what is
   in hand. */
.ship-tray {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  flex-wrap: wrap;
  margin: 0.75rem 0 0;
}

/* touch-action: none stops the browser from starting a page-scroll gesture
   the instant a finger touches a tray ship, so the touchstart/touchmove drag
   handlers in ui.js get to decide what the gesture means instead of racing
   native scrolling for it. */
.tray-ship {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.35rem 0.6rem;
  font: inherit;
  font-size: 0.85rem;
  border: 1px solid var(--water-border);
  border-radius: 8px;
  background: var(--surface-bg);
  cursor: pointer;
  touch-action: none;
}

.tray-ship:hover {
  background: var(--surface-bg-hover);
}

.tray-ship.attached {
  border-color: var(--ink);
  background: var(--attached-bg);
  box-shadow: 0 0 0 2px var(--attached-ring);
}

.tray-name {
  text-transform: capitalize;
  font-weight: 600;
}

.tray-pips {
  display: flex;
  gap: 2px;
}

.tray-pip {
  width: 9px;
  height: 9px;
  border-radius: 2px;
  background: var(--ship-color, var(--ship));
}

/* The tray's own boat graphic, same idea as .fleet-ship-art: a fixed row
   height with width scaled to that ship's length, so the tray shows the
   same theme art and size hierarchy as the board and the fleet panel. */
.tray-ship-art {
  display: inline-flex;
  align-items: center;
  height: 22px;
  flex-shrink: 0;
}

.tray-length {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* The held ship, drawn next to the cursor so it reads as picked up rather
   than as a mode the player has to remember being in. No box-shadow: this
   div's own box is the ship's full rectangular footprint (width/height set
   in JS to length * GHOST_CELL_PX), which is bigger than the boat SVG's
   actual painted silhouette inside it -- a box-shadow shadows that whole
   rectangle regardless of the SVG's transparent areas, which read as a
   pale rectangle framing the ghost rather than a shadow following the
   boat's shape. (An earlier version used box-shadow here instead of
   filter: drop-shadow for repaint performance -- the ghost repaints on
   every mousemove/touchmove while a ship is held, and drop-shadow has to
   rasterize and blur the SVG's actual alpha shape on every one of those
   repaints. That tradeoff is what caused the rectangle, so it's dropped
   rather than swapped for drop-shadow.) */
.ship-ghost {
  position: fixed;
  z-index: 50;
  pointer-events: none;
}

/* Placement preview. These come after .cell:hover and the boat rules on
   purpose, since they carry the same specificity and the preview has to win,
   and they lift above the boat overlay so a footprint stays readable when it
   crosses a ship that is already on the board. */
/* touch-action: none stops the browser from starting a page-scroll gesture
   the instant a finger touches a board cell while a ship is held, so the
   touchstart/touchmove handlers in ui.js get to decide tap vs. drag instead
   of racing native scrolling for it (mirrors .tray-ship's own touch-action,
   scoped to only while a ship is actually held so firing shots on the enemy
   board during battle is unaffected). */
.board-grid.holding .cell {
  cursor: crosshair;
  touch-action: none;
}

.cell.preview-valid,
.cell.preview-invalid,
.cell.rejected {
  z-index: 2;
}

.cell.preview-valid {
  background: var(--preview-ok);
  box-shadow: inset 0 0 0 2px var(--preview-ok-edge);
}

.cell.preview-invalid {
  background: var(--preview-bad);
  box-shadow: inset 0 0 0 2px var(--preview-bad-edge);
}

.cell.rejected {
  background: var(--reject-bg) !important;
  box-shadow: inset 0 0 0 2px var(--preview-bad-edge);
}

/* Opponent fleet status: one entry per ship class, marked sunk the instant
   the tracker confirms it, no location or placement information anywhere in
   it. Same badge language as the tray, so a class reads the same way whether
   it is being placed or being hunted. */
.fleet-status {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin-top: 0.75rem;
}

.fleet-ship {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--water-border);
  border-radius: 8px;
  background: var(--surface-bg);
  font-size: 0.85rem;
}

/* The boat graphic itself, sized to a fixed row height with width scaled to
   that ship's length, so the same size hierarchy the board shows (a 5 cell
   carrier reads as visibly longer than a 2 cell destroyer) carries over to
   this panel at a much smaller scale. */
.fleet-ship-art {
  display: inline-flex;
  align-items: center;
  height: 22px;
  flex-shrink: 0;
}

.fleet-name {
  text-transform: capitalize;
  font-weight: 600;
}

.fleet-ship.sunk {
  opacity: 0.7;
}

.fleet-ship.sunk .fleet-name {
  text-decoration: line-through;
  color: var(--muted);
}

.fleet-ship.sunk .fleet-ship-art {
  filter: grayscale(70%);
}

/* Ship count badge in board panel headings. Shows how many ships each side
   still has floating, so the shrinking numbers track the actual progress
   of the battle at a glance. */
.ship-count {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 2px 8px;
  background: var(--water);
  border-radius: 10px;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* Stats bar below the boards. Three numbers summarizing how the player is
   doing so far: shots taken, hits landed, and accuracy. */
.stats {
  display: flex;
  gap: 1rem;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 1.25rem;
}

.stat {
  background: var(--surface-bg);
  padding: 0.6rem 1.25rem;
  border-radius: 8px;
  box-shadow: 0 1px 3px var(--panel-shadow);
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 90px;
}

.stat-label {
  font-size: 0.7rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  overflow-wrap: break-word;
}

.stat-value {
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* Hot-seat's per-player equivalent of .stats: one block under each fixed
   board panel instead of one shared bar, since there is no single "you"
   perspective once a panel is bound to a fixed player. Reuses .stat/
   .stat-label/.stat-value as-is. */
.panel-stats {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 0.75rem;
}

/* .stat's own min-width: 90px (sized for .stats's short, fixed "Shots"/
   "Hits"/"Accuracy" labels) is too narrow a floor for panel-stats's longer,
   name-prefixed labels ("Tam's Accuracy"), and with no ceiling on .stat
   either, three of them together needed more width than the 394px panel
   provides, wrapping one or more onto their own row below the board panel
   is fixed to. Splitting the row three ways instead, with min-width: 0 so
   flex-shrink can actually apply, keeps all three on one row at any name
   length.
   align-items: stretch replaces .stat's own center: .stat is a column flex
   container, so with the default center its children (the label span) size
   to their own content and are never actually constrained to the box's
   width, leaving overflow-wrap on .stat-label (above) nothing to wrap
   against -- confirmed directly, a long enough single word overflowed
   visibly into the next stat box even with overflow-wrap set. Stretching
   the children to the box's now-fixed third-width makes the wrap apply;
   .game's inherited text-align: center keeps the (now full width) label
   and value looking centered same as before. */
.panel-stats .stat {
  flex: 1 1 0;
  min-width: 0;
  align-items: stretch;
}

/* Sitewide footer (Task 6). Same markup/classes as the rest of the site,
   but styled from Warboat's own theme tokens (re-skins with every theme
   file, like everything else here) instead of the main site's design
   system, which this page never loads. */
.site-footer {
  max-width: 900px;
  margin: 1.5rem auto 0;
  padding: 1rem 1rem 0;
  border-top: 1px solid var(--water-border);
  text-align: center;
}

.footer-meta,
.footer-privacy {
  margin: 0 0 0.4rem;
  font-size: 0.7rem;
  color: var(--muted);
}

.footer-meta a {
  color: var(--ink);
}

.footer-meta a:hover {
  text-decoration: underline;
}

.footer-sep {
  color: var(--muted);
}

.footer-privacy {
  max-width: 60ch;
  margin-inline: auto;
}
