*,
*::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. */
.header-row {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 1rem;
}

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;
}

/* 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. */
.board-panel {
  background: var(--surface-bg);
  padding: 1rem;
  border-radius: var(--panel-radius);
  box-shadow: 0 1px 4px var(--panel-shadow);
  width: 394px;
}

.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);
}

.board-grid {
  position: relative;
  display: grid;
  grid-template-columns: 22px repeat(10, 32px);
  grid-auto-rows: 32px;
  gap: 2px;
}

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

.cell {
  position: relative;
  width: 32px;
  height: 32px;
  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 water, no border.
   These come after .cell:hover on purpose, since they carry the same
   specificity and the boat has to win. */
.cell.over-boat {
  background: transparent;
  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;
}

.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;
}

.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. */
/* box-shadow, not filter: drop-shadow. The ghost repaints on every
   mousemove while a ship is held; drop-shadow has to rasterize and blur the
   actual alpha shape of whatever SVG is inside it on every one of those
   repaints, which got measurably heavier as ship art grew more detailed
   (some themes' boats are several times the path count Classic's are).
   box-shadow only shadows the element's own box, a compositor level
   operation the browser does not have to redo per repaint the same way. */
.ship-ghost {
  position: fixed;
  z-index: 50;
  pointer-events: none;
  box-shadow: 0 2px 3px rgba(0, 0, 0, 0.35);
}

/* 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. */
.board-grid.holding .cell {
  cursor: crosshair;
}

.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;
}
