* { box-sizing: border-box; }

:root {
  --bg: #0d1017;
  --panel: #151a24;
  --line: #242c3a;
  --ink: #e8ecf4;
  --dim: #8c96aa;
  --steel: #46536b;
  --gold: #ffc857;
  --good: #5ddba4;
  --ball: #ff7a59;
}

html, body {
  margin: 0; height: 100%;
  background: var(--bg); color: var(--ink);
  font: 15px/1.5 ui-sans-serif, -apple-system, "SF Pro Text", Inter, system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}

/* One centred column: the board, with its controls directly underneath and
   exactly as wide.

   This was two columns — board on the left, a sidebar on the right. That made
   sense when the sidebar held the score, the multiplier bar and the save bar.
   All of those are drawn on the board now, so what was left was five aim
   buttons and Fire, parked off to one side of a centred board with a gap
   between them. The controls belong under the thing they control.

   --ctrl is the height the strip needs. The column's width is chosen so that
   the board's own height, derived from that width by its aspect ratio, already
   fits in what is left — so nothing is ever clamped on the other axis, which is
   what distorted the board the last two times this layout changed. */
main {
  height: 100%;
  display: grid; place-items: center;
  padding: 16px;
  container-type: size;
  --ctrl: 148px;   /* measured: strip 135.5 + 10 gap */
}

.col {
  height: 100%;
  width: min(100cqw, calc((100cqh - var(--ctrl)) * 560 / 900), 510px);
  display: flex; flex-direction: column;
  gap: 10px;
}

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

.stage {
  flex: 1 1 auto; min-height: 0; min-width: 0;
  display: grid; place-items: center;
  /* A size container, so the board falls back to fitting the height it was
     actually given if --ctrl under-estimates the control strip. When --ctrl is
     right this never binds and the board is exactly the column's width. */
  container-type: size;
}
/* The board and everything drawn over it, sized as one box, so the overlays can
   be positioned against the board's exact edges. It simply fills the column —
   the column width is already the answer. */
.boardWrap { position: relative; width: min(100%, calc(100cqh * 560 / 900)); }
/* One definite axis, computed from both container dimensions, and the other
   left to the aspect ratio. Anything that CLAMPS instead distorts the board: a
   fixed height with max-width:100% squeezed it horizontally on a narrow screen
   (width clamped, height did not, pegs went oval), and the mirror image —
   max-height with an auto width — overlapped the score line by 78px on a phone.
   With the width chosen so it already fits, no clamp ever fires. */
canvas {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 560 / 900;
  border-radius: 14px;
  touch-action: none;
  cursor: crosshair;
  background: #0a0d13;
  box-shadow: 0 18px 60px #0008;
}
canvas.dragging { cursor: grabbing; }

/* --- board overlays -------------------------------------------------------- */
/*
   Help, settings and the end-of-board card, drawn over the board rather than
   stacked above it. Nearly opaque, because they are read, not played through.
*/
.over {
  position: absolute; left: 12px; right: 12px; z-index: 2;
  background: rgba(10, 13, 19, 0.96);
  border: 1px solid var(--line); border-radius: 12px;
  padding: 14px;
  box-shadow: 0 12px 40px #000a;
}
#helpPanel, #setPanel { top: 12px; max-height: calc(100% - 24px); overflow-y: auto; }
/* The end card sits low, clear of the field, where the ball has just finished. */
.over.bottom { bottom: 12px; }
/* `hidden` must beat any display a class sets, or an element that sets
   `display: flex` is permanently visible however the attribute is toggled. The
   replay strip was, and the UA stylesheet's [hidden] rule loses on specificity
   every time. */
[hidden] { display: none !important; }

/* The replay strip. One line at the top of the board, out of the play area. */
.over.bar {
  top: 12px; display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 7px 10px; font-size: 13px; color: var(--dim);
}
.over.bar button { padding: 5px 11px; font-size: 12px; }

/* --- controls ------------------------------------------------------------- */

.controls { display: flex; flex-direction: column; gap: 8px; flex: 0 0 auto; }

/* Board number on the left, help and settings on the right. Below Fire, because
   neither is pressed during a shot and the top of the screen is the board's. */
.metaRow { display: flex; align-items: center; justify-content: space-between; }

h1 { font-size: 19px; margin: 0; letter-spacing: -0.01em; }
.sub { color: var(--dim); font-size: 13px; }

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 14px;
}

.iconRow { display: flex; gap: 6px; }
/* Round, small, and equal weight to each other — neither is a thing you press
   during a shot, and both have to stay out of the way of Fire. */
button.icon {
  width: 30px; height: 30px; padding: 0; border-radius: 50%;
  font-size: 14px; line-height: 1; display: grid; place-items: center;
}
button.icon.on { background: var(--gold); color: #0d1017; border-color: transparent; }

.panel { font-size: 13px; }
.panel p { margin: 0 0 9px; }
.panel p:last-child { margin-bottom: 0; }
.panel b { color: var(--ink); }
.panel ul { margin: 0 0 9px; padding-left: 17px; }
.panel li { margin-bottom: 5px; }
.panel li b { color: var(--gold); }

.stats { display: flex; gap: 14px; justify-content: space-between; }
.stat .k { font-size: 24px; font-variant-numeric: tabular-nums; }
.stat .l { font-size: 11px; color: var(--dim); text-transform: uppercase; letter-spacing: .07em; }

.tray { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.chip {
  width: 54px; height: 26px; border-radius: 6px;
  border: 1px dashed var(--steel);
}
.chip.full {
  border: none;
  background: linear-gradient(105deg, transparent 44%, #7d8ba6 44%, #7d8ba6 56%, transparent 56%);
  background-color: #2a3242;
}

button {
  font: inherit; font-weight: 550;
  color: #0d1017; background: var(--gold);
  border: 0; border-radius: 9px;
  padding: 10px 16px; cursor: pointer;
}
button:disabled { opacity: .35; cursor: default; }
button.ghost { background: transparent; color: var(--ink); border: 1px solid var(--line); }
.row { display: flex; gap: 8px; }
.row > button { flex: 1; }

/* Fine aim. Two step sizes, both reachable by thumb: the keyboard has shift for
   the finer one and a phone does not, so the only way to give touch the same
   control is a second pair of buttons. */
.aimRow { align-items: stretch; }
.aimBtn {
  flex: 1 1 0; min-width: 34px; font-size: 15px; padding: 9px 0;
  letter-spacing: -1px; line-height: 1;
  display: flex; align-items: center; justify-content: center; gap: 1px;
}
/* The step size lives ON the button. It was a separate legend row underneath,
   which cost a line of the one screen that has none to spare — and a `title`
   tooltip is invisible to the thumb that needs it most. */
.aimBtn i { font-style: normal; font-size: 9px; opacity: .6; letter-spacing: 0; }
.aimBtn.fine { color: var(--dim); font-size: 13px; }
button.wide { width: 100%; }

/* The cannon is holding the ball. Fire means something different for the next
   few seconds, so the button has to say so — the pulse is there because the
   window closes on its own. */
button.loaded {
  background: #ffc857; color: #17202f; font-weight: 800; letter-spacing: 0.06em;
  animation: loadedPulse 0.7s ease-in-out infinite;
}
@keyframes loadedPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 200, 87, 0.55); }
  50%      { box-shadow: 0 0 0 7px rgba(255, 200, 87, 0); }
}
@media (prefers-reduced-motion: reduce) { button.loaded { animation: none; } }
.aimRead {
  flex: 1.7 1 0; min-width: 76px;
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 1px;
  border: 1px solid var(--line); border-radius: 8px; padding: 4px 0;
}
/* Two decimals, because the fine step IS 0.05 degrees — at one decimal half the
   presses moved a number that did not change, which reads as a dead button. */
.aimRead span { font-variant-numeric: tabular-nums; font-size: 15px; font-weight: 600; }
.aimRead small { color: var(--dim); font-size: 9px; letter-spacing: .12em; }

/* Board navigation. Deliberately quieter than the game's own controls — it is
   a debug affordance sitting in the same column as the real ones. */
.row.nav > button { flex: 0 0 auto; padding: 6px 12px; }
.row.nav > #rerollRig { flex: 1; }
/* min-width:0 is load-bearing. A flex item's automatic minimum size is its
   content size, and a number input's intrinsic width is ~166px, which floors
   the 68px basis and pushes the row into overflow. */
.nav input {
  flex: 0 0 68px; min-width: 0; width: 68px;
  text-align: center; font: inherit; font-size: 14px;
  background: transparent; color: var(--ink);
  border: 1px solid var(--line); border-radius: 8px; padding: 6px 4px;
}
.row.nav > #rerollRig { white-space: nowrap; }
.navHint { font-size: 12px; opacity: .75; }

.hint { color: var(--dim); font-size: 12.5px; }

/* The per-ball history, newest first. Debug only. */
.log {
  margin: 8px 0 0; font: 11px ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--dim); white-space: pre; max-height: 130px; overflow: auto;
}
.win { color: var(--good); }
footer { color: var(--dim); font-size: 12px; }

/* --- shooting prototype --------------------------------------------------- */

.tgt { color: #ff9b32; }
.endTitle { font-size: 17px; font-weight: 600; margin-bottom: 4px; }
.endTitle.win { color: var(--good); }
/* The share grid. Wide letter-spacing so ten squares read as ten separate
   balls rather than one bar, and it must not wrap — a grid that breaks across
   two lines stops being comparable with the one somebody posted next to it. */
.endGrid {
  font-size: 15px; letter-spacing: 2px; line-height: 1.3;
  margin: 2px 0 5px; white-space: nowrap; overflow-x: auto;
}
.stats .stat { min-width: 46px; }

.pur { color: #c07bff; }

/* The multiplier and save bars used to live here. They are painted on the
   board's own walls now — a meter beside the ball gets read while it matters. */
#potVal {
  font-size: 24px; font-variant-numeric: tabular-nums;
  color: var(--ink); line-height: 1;
  transition: color .12s, transform .12s;
}
#potVal.live { color: var(--gold); }
#potVal.pop { transform: scale(1.18); }

/* --- smaller screens -------------------------------------------------------
   One column everywhere it fits: board on top, controls beneath, the same width.
   The only layout that differs is a short landscape screen, where a strip under
   the board would leave nothing for the board.

   --ctrl is the height of the control strip at each size. It is the one number
   the column width is derived from, so it is set here and nowhere else. */

@media (max-width: 860px) and (orientation: portrait) {
  main { padding: 6px 10px calc(8px + env(safe-area-inset-bottom)); --ctrl: 162px; }   /* strip 151.5 + 8 gap */
  .col { gap: 8px; }
  /* Thumb targets. 44px is the smallest a thumb hits reliably, and the fine pair
     get the same height as the coarse pair — a 0.05 degree nudge is needed most
     in the endgame, which is exactly when a mis-tap costs the board. */
  .aimBtn { padding: 13px 0; font-size: 17px; }
  .aimBtn i { font-size: 10px; }
  .aimRead span { font-size: 17px; }
  #fireBtn { padding: 15px; font-size: 17px; }
}

/* Short screens. The control strip is a fixed cost and the board pays for it,
   so everything in it gets tighter. */
@media (orientation: portrait) and (max-height: 720px) {
  main { --ctrl: 152px; }   /* strip 143.5 + 6 gap — it was 136, and 13px short
                              made the board fall back to fitting the height it had,
                              leaving it narrower than its own controls */
  .col { gap: 6px; }
  .aimBtn { padding: 10px 0; }
  #fireBtn { padding: 11px; }
  .over { padding: 10px; }
}

/* Landscape phone. Wide and very short: a strip under the board leaves nothing
   for the board, so the column turns on its side. */
@media (orientation: landscape) and (max-height: 620px) {
  main { padding: 8px 10px; }
  .col { width: 100%; flex-direction: row; gap: 12px; }
  .controls { width: min(250px, 36%); justify-content: center; }
  .aimBtn { padding: 9px 0; }
  #fireBtn { padding: 10px; }
  .metaRow .sub { display: none; }
  .over { padding: 10px; }
}

/* Debug disclosure. Collapsed by default everywhere: on desktop the keyboard
   does all of it without opening this at all. */
.debug > summary {
  cursor: pointer; color: var(--dim); font-size: 12px;
  letter-spacing: .06em; text-transform: uppercase; list-style: none;
}
.debug > summary::-webkit-details-marker { display: none; }
.debug > summary::before { content: '▸ '; }
.debug > .row { margin-top: 8px; }
.debug[open] > summary::before { content: '▾ '; }
.debug > * + * { margin-top: 8px; }
