/* ============================================================================
   styles.css — Net Game visual layer
   ============================================================================

   Visual model
   ------------
   The board is a CSS grid of fixed-size square cells. Each cell renders a
   tile's pipes by absolutely-positioning four rectangular "stubs" (N/E/S/W),
   one per direction the wires bitmask has set. The `.cell.has-{n|e|s|w}`
   classes are set once at board-build time and never change during gameplay.

   Rotation is purely visual: a child `.cell-inner` div has
   `transform: rotate(calc(var(--rot) * 90deg))`. JavaScript updates `--rot`
   (an integer counter) on each click; the CSS transition does the animation.
   The wires bitmask in board state is updated in lockstep, but the rendered
   stubs never need to be re-drawn — they spin with the inner div.

   Powered state is a single `.powered` class on the cell. Pipe color is
   driven by `--pipe-color` which the `.powered` rule overrides.
   ============================================================================ */

/* ---- Tokens --------------------------------------------------------------- */

:root {
  /* Palette keeps the original SWF's indigo/cyan energy, with warmer UI
     metals so the shell does not collapse into a single blue-purple wash. */
  --bg-deep:      #080816;
  --bg-panel:     #17142a;
  --bg-panel-2:   #211d34;
  --bg-board:     #101525;
  --bg-cell:      #202449;
  --bg-cell-2:    #252b55;
  --line:         #3e466c;
  --line-bright:  #66708f;

  /* Pipes — SWF-matched palette: dark red unpowered, cyan powered. */
  --pipe-dim:   #b03050;   /* unpowered (close to the original's red) */
  --pipe-warm:  #d96080;   /* unpowered hover */
  --pipe-hot:   #5be3ff;   /* powered (cyan neon) */
  --pipe-glow:  #00d4ff;

  /* Endpoint diamond colors (the "client devices") */
  --endpoint-dim:  #cc2a4b;
  --endpoint-hot:  #5cffb2;

  /* Hub: warm gold, recognizable as "the source" */
  --hub-core:   #ffd95e;
  --hub-glow:   #ff9d00;

  /* Wall cells: solid gray block, matches the original's "Wall blocks energy" */
  --wall-fill:  #9a93b8;
  --wall-edge:  #6f6892;

  /* Locked tiles read as "disabled": darker, desaturated background only.
     Pipes themselves keep their normal red/cyan so a powered locked tile
     still glows fully — only the cell fill changes. */
  --cell-locked-bg: #15172a;

  /* UI */
  --text:       #f3f0e8;
  --text-dim:   #aeb2c5;
  --accent:     #5be3ff;
  --accent-2:   #ffcc66;

  /* Cell size is set dynamically on .board to fill available viewport (the
     panel and chrome chew up fixed space, the board takes the rest). The
     root fallback is only used if something renders outside .board. */
  --cell-size:  46px;
  --pipe-w:     14px;

  /* Rotation animation timing */
  --rot-dur:    0.16s;
}

/* ---- Reset + page --------------------------------------------------------- */

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  color: var(--text);
  background:
    linear-gradient(120deg, rgba(255,204,102,0.12), transparent 35%),
    radial-gradient(ellipse at 50% 0%, #25215c 0%, transparent 58%),
    var(--bg-deep);
  height: 100vh;
  display: flex;
  justify-content: center;
  padding: 10px;
  overflow: hidden;   /* never show a page scrollbar */
  -webkit-font-smoothing: antialiased;
  user-select: none;
}

.app {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
}

/* ---- Panel header (logo + New Game) -------------------------------------
   The header used to sit above the board as a separate masthead. Now it's
   the top section of the side panel — keeps the play area edge-to-edge
   vertical and lets the board claim the full viewport height. */

.panel-header {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-bottom: 14px;
  border-bottom: 1px solid rgba(102,112,143,0.55);
}

.eyebrow {
  margin: 0;
  color: var(--accent-2);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.logo {
  margin: 0;
  font-size: 30px;
  line-height: 0.95;
  letter-spacing: 0;
  font-weight: 800;
  color: var(--text);
  text-shadow:
    0 0 18px rgba(91,227,255,0.35),
    0 2px 0 rgba(0,0,0,0.45);
}

/* ---- Game shell ---------------------------------------------------------- */

.game-shell {
  display: grid;
  grid-template-columns: 290px minmax(0, 1fr);
  gap: 12px;
  align-items: stretch;
  flex: 1;
  min-height: 0;          /* allow children to shrink and not blow out the row */
}

.panel {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background:
    linear-gradient(180deg, rgba(255,255,255,0.04), transparent 42%),
    linear-gradient(180deg, var(--bg-panel-2), var(--bg-panel));
  box-shadow:
    0 1px 0 rgba(255,255,255,0.06) inset,
    0 20px 50px rgba(0,0,0,0.28);
  overflow: hidden;       /* panel never scrolls; controls stay docked */
}

.hud {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.stat {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
  padding: 10px;
  border: 1px solid rgba(102,112,143,0.6);
  border-radius: 6px;
  background: rgba(8,8,22,0.36);
}
.stat-label {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.12em;
  color: var(--text-dim);
}
.stat-value {
  margin-top: 4px;
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: 20px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.status-block {
  display: grid;
  gap: 8px;
  padding-bottom: 16px;
  border-bottom: 1px solid rgba(102,112,143,0.55);
}

.power-readout {
  display: grid;
  gap: 8px;
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: 36px;
  font-weight: 800;
  color: var(--accent);
  text-shadow: 0 0 16px rgba(91,227,255,0.4);
}

.power-track {
  width: 100%;
  height: 10px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(8,8,22,0.82);
  box-shadow: inset 0 0 0 1px rgba(102,112,143,0.7);
}

#progress-fill {
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--accent-2), var(--endpoint-hot), var(--accent));
  box-shadow: 0 0 16px rgba(91,227,255,0.45);
  transition: width 0.18s ease-out;
}

.controls {
  display: grid;
  gap: 12px;
  margin-top: auto;
}

.field {
  display: grid;
  gap: 6px;
  color: var(--text-dim);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

select, .btn, .toggle {
  font: inherit;
  color: var(--text);
}

select {
  width: 100%;
  background: rgba(8,8,22,0.72);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 10px 12px;
  font-size: 14px;
  cursor: pointer;
}
select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.btn {
  border: 1px solid var(--line);
  background: rgba(23,20,42,0.94);
  border-radius: 6px;
  padding: 10px 16px;
  font-size: 14px;
  font-weight: 800;
  cursor: pointer;
  transition: background 0.1s, border-color 0.1s, transform 0.05s;
}
.btn:hover { background: #242039; border-color: var(--accent); }
.btn:active { transform: translateY(1px); }
.btn.primary {
  background: linear-gradient(180deg, #263b48, #15242f);
  color: #eafcff;
  border-color: rgba(91,227,255,0.65);
  text-shadow: 0 0 8px rgba(91,227,255,0.45);
  box-shadow: 0 0 18px rgba(91,227,255,0.12);
}

.toggle {
  display: inline-flex;
  width: 100%;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid rgba(102,112,143,0.62);
  border-radius: 6px;
  background: rgba(8,8,22,0.36);
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  cursor: pointer;
}
.toggle input { accent-color: var(--accent); }
.toggle input { width: 18px; height: 18px; }

/* ---- Board --------------------------------------------------------------- */

.board-wrap {
  position: relative;
  display: grid;
  place-items: center;
  min-width: 0;
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background:
    linear-gradient(180deg, rgba(91,227,255,0.06), transparent 45%),
    #0d1020;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.05),
    0 20px 50px rgba(0,0,0,0.34);
}

.board {
  /* Fill the available viewport. Reserve ~330px horizontally for the side
     panel + gaps + body padding (290 + 12 + 20 = 322px, plus slop).
     Reserve only ~30px vertically for body padding now that the masthead
     is gone — the board claims the full viewport height. */
  --cell-size: min(
    calc((100vw - 330px) / var(--cols, 13)),
    calc((100vh - 30px) / var(--rows, 11))
  );
  --pipe-w:        calc(var(--cell-size) * 0.30);
  --endpoint-size: calc(var(--cell-size) * 0.60);
  --diamond-size:  calc(var(--cell-size) * 0.28);
  --hub-size:      calc(var(--cell-size) * 0.40);

  display: grid;
  grid-template-columns: repeat(var(--cols, 13), var(--cell-size));
  grid-template-rows:    repeat(var(--rows, 11), var(--cell-size));
  justify-self: center;
  align-self: center;
  gap: 0;
  padding: 8px;
  background: var(--bg-board);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.04) inset,
    0 12px 36px rgba(0,0,0,0.45),
    0 0 42px rgba(91,227,255,0.07);
}

/* ---- Cell ---------------------------------------------------------------- */

.cell {
  position: relative;
  width: var(--cell-size);
  height: var(--cell-size);
  background: var(--bg-cell);
  cursor: pointer;
  box-shadow: inset 0 0 0 1px rgba(8,8,22,0.42);
  /* Subtle checker so the grid is visible even at unpowered state. */
}
.cell:nth-child(even) { background: var(--bg-cell-2); }

/* Inner div that rotates. Pipes are positioned inside this. */
.cell-inner {
  position: absolute;
  inset: 0;
  transform: rotate(calc(var(--rot, 0) * 90deg));
  transition: transform var(--rot-dur) cubic-bezier(0.4, 0.0, 0.2, 1);
  transform-origin: 50% 50%;
}

/* Pipes ---------------------------------------------------------- */

.pipe {
  position: absolute;
  display: none;                /* shown only when corresponding has-* class is set */
  background: var(--pipe-color, var(--pipe-dim));
  border-radius: 2px;
  /* No transition on background — when a chain of cells lights up, having
     every pipe in the chain run a 180ms color transition simultaneously
     was the main source of frame stutter. Color now flips instantly. */
}
/* N: stub from top edge to center */
.pipe-n {
  top: 0;
  left: calc(50% - var(--pipe-w) / 2);
  width: var(--pipe-w);
  height: 50%;
}
.pipe-s {
  bottom: 0;
  left: calc(50% - var(--pipe-w) / 2);
  width: var(--pipe-w);
  height: 50%;
}
.pipe-e {
  top: calc(50% - var(--pipe-w) / 2);
  right: 0;
  width: 50%;
  height: var(--pipe-w);
}
.pipe-w {
  top: calc(50% - var(--pipe-w) / 2);
  left: 0;
  width: 50%;
  height: var(--pipe-w);
}

/* Show the matching stub for each direction the cell has. */
.cell.has-n .pipe-n,
.cell.has-e .pipe-e,
.cell.has-s .pipe-s,
.cell.has-w .pipe-w {
  display: block;
}

/* Center cap — covers the join between stubs, gives a clean look on T/cross. */
.cell-inner::after {
  content: "";
  position: absolute;
  top: calc(50% - var(--pipe-w) / 2);
  left: calc(50% - var(--pipe-w) / 2);
  width: var(--pipe-w);
  height: var(--pipe-w);
  border-radius: 3px;
  background: var(--pipe-color, var(--pipe-dim));
  /* No transition — see .pipe comment. */
}
/* Empty cells: hide the center cap. */
.cell:not(.has-n):not(.has-e):not(.has-s):not(.has-w) .cell-inner::after {
  display: none;
}

/* ---- Wall cells ---------------------------------------------------------
   In the SWF, walls aren't barriers *between* cells — they ARE cells. A
   wall cell is a fully-blocked square with no pipes; the energy can't
   pass through it. Wall cells emerge naturally from the 3-wire cap during
   generation (a cell that couldn't get any wire because all its potential
   parents were capped). */

.cell.wall-cell {
  background:
    repeating-linear-gradient(45deg,
      var(--wall-fill) 0,
      var(--wall-fill) 4px,
      var(--wall-edge) 4px,
      var(--wall-edge) 5px);
  cursor: not-allowed;
  box-shadow:
    inset 0 0 0 1px var(--wall-edge),
    inset 0 1px 0 rgba(255,255,255,0.08);
}
.cell.wall-cell:hover { background-color: var(--wall-fill); }

/* ---- Edge walls (the 1/30 pre-placed barriers) ---------------------------
   Small stubs at the cell boundary marking a permanent no-cross barrier.
   Sparse by design (matches bytecode: ~9 per Doctor board). */

.wall {
  position: absolute;
  background: var(--wall-fill);
  border: 1px solid var(--wall-edge);
  pointer-events: none;
  z-index: 3;
  border-radius: 2px;
}
.wall-n { top: -3px;    left: 22%; right: 22%; height: 6px; }
.wall-s { bottom: -3px; left: 22%; right: 22%; height: 6px; }
.wall-e { right: -3px;  top:  22%; bottom: 22%; width:  6px; }
.wall-w { left: -3px;   top:  22%; bottom: 22%; width:  6px; }

/* ---- Powered state -------------------------------------------------------
   Performance: NO box-shadow on individual pipes or the center cap. A blurred
   shadow gets repainted for each element every frame, and with ~3 pipes per
   powered cell across a chain of 50 cells, that's hundreds of expensive
   shadow paints. The cyan color alone reads as "lit" — the glow is preserved
   on the much-fewer endpoint devices (kind=1 cells) where it actually
   represents "client powered." */

.cell.powered {
  --pipe-color: var(--pipe-hot);
}

/* Endpoint diamonds — kind=1 tiles render a rotated-square "client device"
   instead of a pipe stub. The diamond sits at the open end of the wire and
   rotates with the cell-inner via the parent's --rot transform.
   The pipe stub for the wire direction is still drawn — the diamond simply
   overlays its open end. Visually similar to the original SWF's red/green
   device icons. */

/* Endpoint = "client device": a circle centered in the cell with a diamond
   inside it. The pipe stub still extends from cell center to the wire
   direction — visually it looks like the wire emerges from the device.
   Centered, so the device is rotation-invariant; only the pipe direction
   changes when the player rotates the tile. */

.endpoint {
  display: none;
  position: absolute;
  width:  var(--endpoint-size, 28px);
  height: var(--endpoint-size, 28px);
  top:    calc(50% - var(--endpoint-size, 28px) / 2);
  left:   calc(50% - var(--endpoint-size, 28px) / 2);
  background:
    radial-gradient(circle at 30% 30%, rgba(255,255,255,0.22), transparent 55%),
    var(--bg-cell);
  border: 2px solid var(--endpoint-dim);
  border-radius: 50%;
  z-index: 3;
  box-shadow: inset 0 0 4px rgba(0,0,0,0.55);
}

/* The diamond inside the circle — a rotated square. */
.endpoint::after {
  content: "";
  position: absolute;
  width:  var(--diamond-size, 13px);
  height: var(--diamond-size, 13px);
  top:    calc(50% - var(--diamond-size, 13px) / 2);
  left:   calc(50% - var(--diamond-size, 13px) / 2);
  background: var(--endpoint-dim);
  transform: rotate(45deg);
  border-radius: 2px;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.35);
}

/* Only show for kind=1 (single-wire ends). */
.cell[data-kind="1"] .endpoint { display: block; }

/* Powered device — circle border + inner diamond both light up cyan-green,
   with a soft outer glow. */
.cell.powered[data-kind="1"] .endpoint {
  border-color: var(--endpoint-hot);
  box-shadow:
    inset 0 0 4px rgba(0,0,0,0.4),
    0 0 8px rgba(92,255,178,0.55),
    0 0 16px rgba(92,255,178,0.35);
}
.cell.powered[data-kind="1"] .endpoint::after {
  background: var(--endpoint-hot);
}

/* ---- Hub: the central "Energy source" -----------------------------------
   Matches the SWF: a small gray box at the center of the hub cell with a
   little diamond marker inside indicating the energy source. The wires
   poke out of it. */

.hub-core {
  position: absolute;
  width:  var(--hub-size, 18px);
  height: var(--hub-size, 18px);
  top:    calc(50% - var(--hub-size, 18px) / 2);
  left:   calc(50% - var(--hub-size, 18px) / 2);
  background: linear-gradient(180deg, var(--wall-fill), var(--wall-edge));
  border: 1px solid #4a4470;
  border-radius: 2px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.18),
    0 0 4px rgba(0,0,0,0.45);
  z-index: 2;
}
.hub-core::before {
  /* Inner diamond marker — colored by the powered state. */
  content: "";
  position: absolute;
  width:  calc(var(--hub-size, 18px) * 0.45);
  height: calc(var(--hub-size, 18px) * 0.45);
  top:    calc(50% - var(--hub-size, 18px) * 0.225);
  left:   calc(50% - var(--hub-size, 18px) * 0.225);
  background: var(--endpoint-hot);
  transform: rotate(45deg);
  box-shadow: 0 0 4px rgba(92,255,178,0.7);
}

/* ---- Locked tile --------------------------------------------------------- */
/* Background-only "disabled" state. Pipes, endpoint diamonds, and the powered
   cyan glow all keep their normal colors — the dimmer fill is the only
   signal that the cell is frozen. No padlock icon. */

.cell.locked,
.cell.locked:nth-child(even) {
  background: var(--cell-locked-bg);
  cursor: not-allowed;
}

/* ---- Hover feedback ------------------------------------------------------ */

.cell:hover:not(.locked) {
  background: #30386a;
}
.cell.hub:hover { cursor: pointer; }

/* ---- Win banner ---------------------------------------------------------- */

.win-banner {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(13, 8, 50, 0.78);
  backdrop-filter: blur(6px);
  border-radius: 12px;
  z-index: 10;
  animation: win-fade-in 0.25s ease-out;
}
.win-banner[hidden] { display: none; }
@keyframes win-fade-in {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: scale(1);    }
}
.win-card {
  background: linear-gradient(180deg, var(--bg-panel-2), #11101d);
  border: 1px solid var(--accent);
  border-radius: 8px;
  padding: 22px 28px;
  box-shadow: 0 0 32px rgba(91,227,255,0.35);
  text-align: center;
  min-width: 320px;
}
.win-card h2 {
  margin: 0 0 10px;
  font-size: 28px;
  letter-spacing: 0.28em;
  color: var(--hub-core);
  text-shadow: 0 0 14px rgba(255,217,94,0.65);
}
.win-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px 14px;
  margin: 14px 0;
  font-size: 14px;
}
.win-stats > div {
  display: flex;
  justify-content: space-between;
  border-bottom: 1px solid var(--line);
  padding: 4px 0;
}
.win-label { color: var(--text-dim); font-size: 11px; letter-spacing: 0.1em; }
.hi-scores {
  text-align: left;
  font-size: 12px;
  padding: 0 0 0 22px;
  margin: 8px 0 14px;
  color: var(--text-dim);
  max-height: 120px;
  overflow-y: auto;
}
.hi-scores li.current {
  color: var(--accent);
  font-weight: bold;
}

/* ---- Solved-board win celebration ---------------------------------------- */

/* Hub-centered ripple expansion when the board is solved. Each cell's pulse
   is delayed by its Manhattan distance from the hub (set as --hub-dist via
   JavaScript), producing a wave that radiates outward. */
body.solved .cell.powered .cell-inner::after {
  animation: solved-throb 1.4s ease-out infinite;
  animation-delay: calc(var(--hub-dist, 0) * 0.05s);
}
@keyframes solved-throb {
  0%   { transform: scale(1);    box-shadow: 0 0 6px var(--pipe-glow); }
  35%  { transform: scale(1.35); box-shadow: 0 0 18px var(--pipe-glow), 0 0 28px rgba(91,227,255,0.6); }
  100% { transform: scale(1);    box-shadow: 0 0 6px var(--pipe-glow); }
}
body.solved .cell.powered .cell-inner::before {
  animation: leaf-throb 1.4s ease-out infinite;
  animation-delay: calc(var(--hub-dist, 0) * 0.05s);
}
@keyframes leaf-throb {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.25); }
  100% { transform: scale(1); }
}

/* ---- Footer -------------------------------------------------------------- */

/* ---- Responsive ---------------------------------------------------------- */

@media (max-width: 900px) {
  :root { --pipe-w: 10px; }
  body { padding: 14px; }
  .app { min-height: calc(100vh - 28px); }
  .game-shell { grid-template-columns: 1fr; }
  .panel {
    display: grid;
    grid-template-columns: minmax(160px, 0.8fr) 1.2fr minmax(180px, 0.8fr);
    align-items: end;
  }
  .status-block { padding: 0; border: 0; }
  .controls { margin: 0; }
}

@media (max-width: 620px) {
  :root { --cell-size: min(25px, calc((100vw - 64px) / 13)); --pipe-w: 8px; }
  .masthead { grid-template-columns: 1fr; }
  .masthead .btn { width: 100%; }
  .panel { grid-template-columns: 1fr; }
  .board-wrap { padding: 10px; overflow-x: auto; place-items: start center; }
  .hud { grid-template-columns: 1fr 1fr; }
}
