/* Play-by-web client. Server-rendered, no JavaScript.
   Deliberately plain and document-shaped: readable at any width, printable,
   and usable with images off. */

:root {
  --ink: #241a12;
  --paper: #f4ece0;
  --panel: #fffaf2;
  --rule: #cbb89c;
  --accent: #8c3b12;
  --accent-soft: #f0d9c4;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: Georgia, 'Iowan Old Style', 'Times New Roman', serif;
  background: var(--paper);
  color: var(--ink);
  line-height: 1.5;
}

a { color: var(--accent); }

header.site {
  background: #2c1a10;
  color: #f3e3d0;
  padding: 10px 20px;
  display: flex;
  align-items: baseline;
  gap: 16px;
  flex-wrap: wrap;
}
header.site h1 {
  margin: 0; font-size: 1.15rem; letter-spacing: 0.22em; text-transform: uppercase;
}
header.site a { color: #f0c9a4; }
header.site .spacer { flex: 1; }

/* Wide enough for the enlarged board window plus the side column (#21). */
.wrap { max-width: 1560px; margin: 0 auto; padding: 18px 20px 60px; }

.columns { display: flex; gap: 22px; align-items: flex-start; flex-wrap: wrap; }
.col-board { flex: 1 1 1180px; min-width: 320px; }
.col-side { flex: 0 1 300px; min-width: 260px; }

.card {
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 12px 14px;
  margin-bottom: 16px;
}
.card h2 {
  margin: 0 0 8px; font-size: 0.82rem; text-transform: uppercase;
  letter-spacing: 0.14em; color: #6b533a; border-bottom: 1px solid var(--rule);
  padding-bottom: 5px;
}

/* ---------- the board ---------- */

.board-frame {
  background: #17435f;
  background-image:
    radial-gradient(ellipse at 30% 20%, #1d5a7e 0%, transparent 60%),
    radial-gradient(ellipse at 70% 80%, #10314a 0%, transparent 60%);
  border: 1px solid #0d2537;
  border-radius: 4px;
  padding: 10px;
  /* No scrolling on the board. The view window is a fixed size and the zoom is
     chosen so everything the turn needs is inside it, so a scrollbar here would
     only ever mean something had gone wrong. */
  overflow: hidden;
}
.board { position: relative; }
.board img, .board span, .board a { position: absolute; }
.board img { display: block; }
.board img.riser { filter: brightness(0.72) saturate(0.5); }
.board img.piece { width: 82px; height: 82px; }
.board img.lava { width: 120px; height: 128px; pointer-events: none; }
.board img.ghost { opacity: 0.6; outline: 3px dashed #ffd54f; }
.board img.ghost-bad { opacity: 0.45; outline-color: #ff5252; }

.board span.level {
  width: 22px; height: 22px; line-height: 22px;
  text-align: center; font-size: 12px; font-family: system-ui, sans-serif;
  font-weight: 700; color: #fff; background: rgba(0,0,0,0.62);
  border-radius: 50%;
}

.board span.cell-highlight {
  width: 120px; height: 104px;
  clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
  background: var(--hi-fill, rgba(255, 213, 79, 0.28));
  box-shadow: inset 0 0 0 3px var(--hi, #ffd54f);
}

/* Legal-move targets: <a> for navigation, <form><button> for actual moves.
   Both are styled identically as hex overlays — this is the whole no-JS
   interaction model. */
.board form.marker-form { position: absolute; margin: 0; padding: 0; }
.board a.marker, .board button.marker {
  font: inherit; cursor: pointer; border: 0;
  width: 120px; height: 104px;
  clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
  /* Transparent by default: early in a game almost every nearby hex is a
     legal spot, and filled overlays merge into one unreadable mass. The hex
     stays the (large) hit area; only a small chip is drawn. */
  background: transparent;
  display: flex; align-items: center; justify-content: center;
  text-decoration: none;
}
.board a.marker:hover, .board a.marker:focus,
.board button.marker:hover, .board button.marker:focus {
  background: rgba(126, 217, 87, 0.42);
  box-shadow: inset 0 0 0 4px #7ed957;
}
.board a.marker span, .board button.marker span {
  position: static;
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%;
  font-family: system-ui, sans-serif; font-size: 15px; font-weight: 700;
  background: rgba(255, 252, 245, 0.92);
  color: #17435f;
  border: 2px solid rgba(13, 37, 55, 0.65);
  box-shadow: 0 2px 5px rgba(0,0,0,0.45);
}
.board a.marker:hover span, .board button.marker:hover span,
.board a.marker:focus span, .board button.marker:focus span {
  background: #7ed957; border-color: #2b6b1c;
}
.board button.marker-erupt span, .board a.marker-erupt span {
  background: #ffd7c2; border-color: #7f2412;
}
.board a.marker-erupt:hover, .board button.marker-erupt:hover { background: rgba(244,81,30,0.38); }

/* ---------- players / status ---------- */

table.players { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
table.players th, table.players td { text-align: left; padding: 4px 6px; }
table.players thead th {
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.1em; color: #6b533a;
  border-bottom: 1px solid var(--rule);
}
table.players tr.turn { background: var(--accent-soft); font-weight: 700; }
table.players tr.out { opacity: 0.5; text-decoration: line-through; }
.swatch {
  display: inline-block; width: 12px; height: 12px; border-radius: 2px;
  border: 1px solid rgba(0,0,0,0.5); vertical-align: -1px; margin-right: 6px;
}

.prompt {
  background: var(--accent-soft); border-left: 4px solid var(--accent);
  padding: 10px 14px; margin-bottom: 16px; border-radius: 0 4px 4px 0;
}
.prompt strong { color: var(--accent); }

.choices { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.choice, button.choice {
  font: inherit; display: inline-block; padding: 7px 14px;
  background: #fff; border: 1px solid var(--rule); border-radius: 3px;
  text-decoration: none; color: var(--ink); cursor: pointer;
}
.choice:hover { background: var(--accent-soft); border-color: var(--accent); }
.choice.on { background: var(--accent); color: #fff; border-color: var(--accent); }

/* Rotation chooser: six previews of the drawn tile. */
.rotations { display: flex; flex-wrap: wrap; gap: 14px; }
.rotations .rot { text-align: center; }
.rotations .rot .mini {
  position: relative; width: 230px; height: 200px;
  background: #17435f; border: 1px solid #0d2537; border-radius: 3px; overflow: hidden;
}
.rotations .rot .mini .board { transform-origin: 0 0; }
.rotations .rot.illegal { opacity: 0.5; }
.rotations .rot.illegal .mini { filter: grayscale(0.7); }
.rotations .rot form { margin-top: 6px; }

ol.log { margin: 0; padding-left: 20px; font-size: 0.84rem; color: #4a3a2a; }
ol.log li { margin-bottom: 2px; }

.muted { color: #6b533a; font-size: 0.85rem; }
.tile-preview { display: flex; align-items: center; gap: 10px; }
.tile-preview .mini { position: relative; width: 150px; height: 130px; }

footer.site { margin-top: 30px; font-size: 0.78rem; color: #6b533a; text-align: center; }

/* Scaled board wrapper: transform:scale leaves layout size unchanged, so this
   box carries the scaled dimensions and keeps the board inside its frame. */
.board-scale { position: relative; }

/* ---------- tile piece (tri-hex) ---------- */

.tile-piece { position: relative; }
.tile-piece img { position: absolute; display: block; }
.tile-piece img.lava { width: 120px; height: 128px; }
.tile-piece-box { position: relative; }
.tile-preview { display: block; }

/* ---------- hover placement preview (no JavaScript) ----------
   Pointing at a space reveals a ghost of the tile plus a ring of rotation
   wedges. The wedges live inside the hex footprint so neighbouring spaces
   never fight over the pointer. Touch and keyboard users get none of this,
   which is why the marker link to the rotation page always remains. */

.board .place-hover {
  position: absolute;
  width: 120px; height: 104px;
  /* Markers are emitted before the scenery so hover ghosts can be later
     siblings; z-index is what keeps them on top and clickable. */
  z-index: 6;
  /* The box is a rectangle and these overlap their neighbours, so the
     container itself must never take the pointer — only the hex-clipped link
     inside it does. Otherwise a space swallows clicks aimed next door. */
  pointer-events: none;
}
.board .place-hover > a.marker { pointer-events: auto; }
/* A hovered space is raised above its neighbours so its ring isn't clipped
   behind them. The ring layer itself stays inert — only the buttons take the
   pointer — otherwise it covers the hex and swallows clicks on the link that
   leads to the rotation page. */
.board .place-hover:hover, .board .place-hover:focus-within { z-index: 7; }
/* Only standalone markers need raising — scoped with > so it never applies to
   the link nested inside .place-hover, which would otherwise outrank the
   wedges in that element's own stacking context and swallow their clicks. */
.board > a.marker, .board > form.marker-form { z-index: 6; }
.board .place-hover .wedges {
  position: absolute;
  transform-origin: 50% 50%;
  opacity: 0; visibility: hidden;
  transition: opacity 0.12s ease;
}
.board .place-hover:hover .wedges,
.board .place-hover:focus-within .wedges {
  opacity: 1; visibility: visible;
}

/* Ghost of the tile as it would land. It is NOT inside .place-hover: it sits
   out in the scenery at its own depth so tiles in front of it occlude it, and
   the per-space reveal rules (generated in board-html.js) switch it on via the
   sibling combinator. Gold rim so it reads as "this is what will land here". */
.board img.hover-ghost {
  position: absolute;
  opacity: 0; visibility: hidden;
  transition: opacity 0.12s ease;
  filter: drop-shadow(0 0 0 #ffd54f) drop-shadow(0 0 4px #ffd54f)
          drop-shadow(0 0 9px rgba(255,213,79,0.85));
  pointer-events: none;
}

/* The wedge layer spans the whole hex, so it must not swallow clicks aimed at
   the marker link beneath it — only the buttons themselves are clickable. */
.board .wedges { z-index: 3; pointer-events: none; }
.board form.wedge-form { position: absolute; margin: 0; pointer-events: auto; }
.board button.wedge {
  width: 30px; height: 30px; padding: 0;
  border-radius: 50%;
  border: 2px solid #2b6b1c;
  background: #eaffe0;
  color: #1d4d10;
  font-size: 14px; line-height: 1;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 6px rgba(0,0,0,0.5);
}
.board button.wedge span { display: block; }
.board button.wedge:hover, .board button.wedge:focus {
  background: #7ed957; transform: scale(1.18);
}
.board button.wedge-erupt {
  background: #ffe0d0; border-color: #7f2412; color: #7f2412;
}
.board button.wedge-erupt:hover, .board button.wedge-erupt:focus { background: #ffab80; }

/* A hovered space should sit above its neighbours, ghost and all. */
.board .place-hover:hover, .board .place-hover:focus-within { z-index: 4; }

/* Take back: sits with the turn prompt, since that is where you look when
   deciding what to do next. */
.prompt .takeback { margin-top: 8px; }
.prompt .takeback .choice { font-size: 0.85rem; padding: 5px 12px; }

/* Fixed viewport with the island centroid pinned to its centre (#19). The
   board slides behind this window rather than being re-fitted each turn, so
   the position you were just looking at stays where it was. */
.board-view { position: relative; overflow: hidden; }
.board-pan { position: absolute; }

/* The turn prompt holds wildly different amounts of content — a one-line
   "waiting for X", or three lines plus a row of build buttons plus Take back.
   Letting it size to its content pushed the board down by ~88px the moment you
   placed a tile, which is jarring precisely when you are looking at the board.
   Reserve the space instead, so the board never moves. Scrolls internally in
   the rare case content exceeds it, so an action can never become unreachable. */
.prompt.turn-prompt {
  height: 148px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* ---------- stepped view controls (#21) ---------- */

.view-controls {
  display: flex; align-items: center; gap: 26px;
  margin-top: 10px; padding: 8px 12px;
  background: var(--panel); border: 1px solid var(--rule); border-radius: 4px;
}
.vc-pad {
  display: grid; grid-template-columns: repeat(3, 30px);
  grid-auto-rows: 26px; gap: 2px;
}
.vc-blank { display: block; }
.vc-zoom { display: flex; align-items: center; gap: 8px; }
.vc-label, .vc-note {
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.1em; color: #6b533a;
}
.vc-note { text-transform: none; letter-spacing: 0; font-style: italic; }
.vc-pct {
  min-width: 52px; text-align: center; font-variant-numeric: tabular-nums;
  font-weight: 700;
}
.vc {
  display: flex; align-items: center; justify-content: center;
  font: inherit; font-size: 0.9rem; line-height: 1;
  background: #fff; border: 1px solid var(--rule); border-radius: 3px;
  color: var(--ink); text-decoration: none; cursor: pointer;
  min-width: 30px; min-height: 26px;
}
.vc:hover { background: var(--accent-soft); border-color: var(--accent); }
.vc-off { opacity: 0.3; cursor: default; }
.vc-off:hover { background: #fff; border-color: var(--rule); }

/* ---------- what changed since your last turn (#23) ---------- */

/* The banner sits directly above the board, so any change to its line count
   (an opponent placing more pieces, or your own eruption destroying some of
   them mid-turn) used to shift the whole board up and down. Reserving a fixed
   height — the way .turn-prompt does below it — pins the board. Content that
   overflows the rare long summary scrolls inside the slot instead. */
.since-banner-slot { height: 60px; margin-bottom: 10px; overflow-y: auto; }
.since-banner {
  background: #fffaf2; border: 1px solid var(--rule);
  border-left: 4px solid #6b533a;
  padding: 8px 14px; border-radius: 0 4px 4px 0;
  font-size: 0.9rem;
}
.since-banner .lost { color: #a3320f; font-weight: 700; }

/* Rings marking pieces an opponent placed while you were away. Player colour
   comes in as --who. Deliberately distinct from the cyan move targets and the
   yellow settlement selection: a solid ring plus an outward glow, no fill, so
   the artwork underneath stays readable. */
.board .fresh { position: absolute; pointer-events: none; }

/* Tile provenance is painted on the extruded skirt, in the normal painter's
   order, so a tile in front covers a ring behind it. The whole skirt height
   is tinted in the placing player's colour and outlined rim-to-rim — both
   side drops as well as the lower rim — while the top hex edge is left clear
   of the level badge and any building. */
.board svg.fresh-tile-base { overflow: visible; }
.board .fresh-tile-depth { opacity: 0.32; stroke: none; }
.board .fresh-tile-rim {
  fill: none; stroke-width: 2.5px; stroke-linecap: round; stroke-linejoin: round;
  opacity: 0.85;
}
.board .fresh-piece {
  width: 52px; height: 52px; border-radius: 50%;
  border: 4px solid var(--who);
  box-shadow: 0 0 10px 3px var(--who), inset 0 0 8px rgba(0,0,0,0.35);
  opacity: 0.92;
}

/* --- Account pages ------------------------------------------------------
   Forms are the whole interface here, so they get the same document-shaped
   treatment as everything else: stacked labels, generous targets, and no
   reliance on colour alone to carry meaning. */

.stack { display: flex; flex-direction: column; gap: 14px; max-width: 26rem; }
.stack label { display: flex; flex-direction: column; gap: 4px; font-weight: 700; }
.stack .muted { font-weight: 400; }

.stack input, .card input[type="text"], .card input[type="email"],
.card input[type="password"] {
  font: inherit;
  padding: 7px 9px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: #fff;
  color: var(--ink);
}
.stack input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.stack button { align-self: flex-start; }

.error, .ok {
  padding: 8px 11px;
  border-radius: 4px;
  border-left: 4px solid var(--accent);
  background: var(--accent-soft);
  margin: 10px 0;
}
.ok { border-left-color: #4a7c2f; background: #e2efd8; }

/* Sign out sits in the header and must change state, so it is a form, not a
   link — styled to read as the link it looks like. */
button.linkish {
  font: inherit;
  background: none;
  border: 0;
  padding: 0;
  color: #f0c9a4;
  text-decoration: underline;
  cursor: pointer;
}

ul.invites { list-style: none; padding: 0; margin: 0; }
ul.invites li {
  padding: 10px 0;
  border-bottom: 1px solid var(--rule);
}
ul.invites li:last-child { border-bottom: 0; }
.row { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; }

/* ---------- rules page ---------- */

.legend-row { display: flex; flex-wrap: wrap; gap: 14px; margin: 12px 0; }
.legend { margin: 0; text-align: center; }
/* The building sprites (a direct child of the figure) are baked on
   transparency, so a faint frame keeps them visible on the cream panel.
   Scope to a direct child so composed tri-tile hexes don't each get a box. */
.legend > img {
  display: block; margin: 0 auto 4px;
  background: rgba(0, 0, 0, 0.06);
  border-radius: 3px;
}
/* A tri-tile is a sized block (renderTile's .tile-piece-box); centre it. */
.tile-legend .tile-piece-box { margin: 0 auto; }
.legend figcaption { font-size: 0.8rem; }

/* Numbered steps and plain sub-lists inside a card. */
ol.steps, ul.steps { margin: 8px 0 8px; padding-left: 22px; }
ol.steps > li, ul.steps > li { margin-bottom: 6px; }

.card h3 {
  margin: 14px 0 4px; font-size: 1.02rem; color: #5a3f28;
}

/* Quick-reference definition list. */
dl.rules-dl { margin: 8px 0 0; }
dl.rules-dl dt {
  font-weight: 700; margin-top: 10px; color: #5a3f28;
}
dl.rules-dl dd { margin: 2px 0 0 16px; }
