/*
 * Pour Decisions.
 *
 * One stylesheet, no framework — the whole visual is stacked rectangles behind
 * a glass highlight, and a utility framework would be more bytes than the game.
 *
 * The board sizes itself from the tube count via `--tubes`, so a five-tube
 * level and a twelve-tube level both fill the screen without media queries per
 * level. Tubes wrap to a second row when they no longer fit.
 */

:root {
  --bg: #0d1220;
  --bg-2: #141c30;
  --panel: #1b2440;
  --line: #2b3757;
  --text: #e8edf8;
  --dim: #8fa0c4;
  --accent: #4a9ae8;
  --good: #48c98a;
  --star: #f5c451;
  --tube-w: 54px;
  --tube-h: 216px;
  --radius: 14px;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  height: 100%;
  overscroll-behavior: none;
}

body {
  background: radial-gradient(120% 100% at 50% 0%, var(--bg-2) 0%, var(--bg) 65%);
  color: var(--text);
  font: 500 15px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}

#app {
  min-height: 100%;
  display: flex;
  flex-direction: column;
  padding: max(10px, env(safe-area-inset-top)) 12px 16px;
  gap: 10px;
}

/* ------------------------------------------------------------------ top bar */

.hud-top {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.pill {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 12px;
  font-size: 13px;
  color: var(--dim);
  white-space: nowrap;
}

.pill b {
  color: var(--text);
  font-weight: 700;
}

.pill-name {
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.pill .dim {
  color: var(--dim);
  font-weight: 500;
}

/* Over par: three stars is gone, and it should be visible that it is gone. */
#pill-moves.over b {
  color: #f0a02a;
}

.pill-btn {
  cursor: pointer;
  color: var(--text);
  font-size: 15px;
  line-height: 1;
  padding: 7px 12px;
  transition: background 0.15s, transform 0.1s;
}

.pill-btn:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.13);
}

.pill-btn:active:not(:disabled) {
  transform: scale(0.94);
}

.pill-btn:disabled {
  opacity: 0.35;
  cursor: default;
}

.pill-btn.off {
  color: var(--dim);
}

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

.board-wrap {
  flex: 1;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

.board {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: center;
  gap: 18px 22px;
  max-width: 780px;
  padding: 8px;
}

/* The overlay hosts units in flight. It must not intercept clicks, and it must
   not clip — a poured unit arcs well above the tube it came from. */
.overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: visible;
}

.tube {
  position: relative;
  width: var(--tube-w);
  height: var(--tube-h);
  padding: 0;
  border: 2px solid rgba(255, 255, 255, 0.22);
  border-top: none;
  border-radius: 6px 6px calc(var(--tube-w) / 2) calc(var(--tube-w) / 2);
  background: rgba(255, 255, 255, 0.05);
  cursor: pointer;
  overflow: hidden;
  /* Tubes pivot about their base, not their middle. A pour tips the source
     toward the destination (see `animatePour`), and about the default centre
     origin the tube see-saws — the lip travels barely further than the closed
     end, so it reads as a wobble rather than as pouring. */
  transform-origin: 50% 88%;
  transition: transform 0.16s cubic-bezier(.34, 1.4, .64, 1), border-color 0.16s;
}

.tube:hover {
  border-color: rgba(255, 255, 255, 0.4);
}

/* Selected: the tube lifts. This is the only state the player must read at a
   glance mid-puzzle, so it is movement rather than a colour change. */
.tube.selected {
  transform: translateY(-12px);
  border-color: var(--accent);
  box-shadow: 0 8px 22px rgba(74, 154, 232, 0.28);
}

.tube.done {
  border-color: rgba(72, 201, 138, 0.65);
}

.stack {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column-reverse; /* first child is the bottom of the tube */
}

.unit {
  display: block;
  width: 100%;
  background: linear-gradient(to bottom, var(--fill) 0%, var(--fill) 62%, var(--shade) 100%);
  /* A hairline between units so four of the same colour still read as four
     units and not one tall block — which is the difference between seeing a
     pour of three and seeing the level change shape for no reason. */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16);
}

.unit.flying {
  position: absolute;
  border-radius: 3px;
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.35);
  z-index: 5;
}

/* The glass: a highlight down the left and a soft sheen. Purely decorative,
   and above the liquid so it reads as being in front of it. */
.glass {
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
  background: linear-gradient(
    100deg,
    rgba(255, 255, 255, 0.22) 0%,
    rgba(255, 255, 255, 0.05) 18%,
    rgba(255, 255, 255, 0) 42%,
    rgba(255, 255, 255, 0.09) 92%
  );
}

/* --------------------------------------------------------------------- hint */

.hint {
  margin: 0 auto;
  max-width: 620px;
  text-align: center;
  color: var(--dim);
  font-size: 13px;
  min-height: 2.6em;
}

/* -------------------------------------------------------------------- cards */

.scrim {
  position: fixed;
  inset: 0;
  background: rgba(6, 10, 20, 0.72);
  backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
  z-index: 20;
}

.scrim.open {
  opacity: 1;
  pointer-events: auto;
}

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px 26px 20px;
  width: min(400px, 100%);
  text-align: center;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
  transform: translateY(12px) scale(0.97);
  transition: transform 0.24s cubic-bezier(.34, 1.4, .64, 1);
}

.scrim.open .card {
  transform: none;
}

.card-wide {
  width: min(560px, 100%);
}

.card h2 {
  margin: 6px 0 6px;
  font-size: 22px;
}

.card p {
  margin: 0 0 14px;
  color: var(--dim);
  font-size: 14px;
}

.stars {
  font-size: 30px;
  letter-spacing: 6px;
  color: rgba(255, 255, 255, 0.16);
}

.stars .on {
  color: var(--star);
  text-shadow: 0 0 16px rgba(245, 196, 81, 0.5);
}

.res-line {
  display: flex;
  justify-content: center;
  gap: 26px;
  color: var(--dim);
  font-size: 14px;
  margin-bottom: 18px;
}

.res-line b {
  color: var(--text);
  font-size: 17px;
  margin-left: 6px;
}

.card-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
}

.btn {
  border: 1px solid transparent;
  border-radius: 10px;
  padding: 10px 18px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  background: var(--accent);
  color: #08101f;
  transition: transform 0.1s, filter 0.15s;
}

.btn:hover {
  filter: brightness(1.1);
}

.btn:active {
  transform: scale(0.96);
}

.btn-ghost {
  background: transparent;
  border-color: var(--line);
  color: var(--text);
}

/* ------------------------------------------------------------ level picker */

.level-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
  gap: 10px;
  margin-bottom: 18px;
  max-height: 46vh;
  overflow-y: auto;
}

.level-cell {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 9px 4px 7px;
  color: var(--text);
  font: inherit;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  transition: background 0.15s, transform 0.1s;
}

.level-cell:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.12);
}

.level-cell:active:not(:disabled) {
  transform: scale(0.95);
}

.level-cell:disabled {
  opacity: 0.32;
  cursor: default;
}

.level-cell b {
  font-size: 16px;
}

.cell-stars {
  font-size: 9px;
  letter-spacing: 1px;
  color: rgba(255, 255, 255, 0.18);
}

.cell-stars .on {
  color: var(--star);
}

.cell-lock {
  font-size: 10px;
  opacity: 0.6;
}

/* --------------------------------------------------------------------- boot */

.boot {
  position: fixed;
  inset: 0;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  z-index: 40;
  transition: opacity 0.35s;
}

.boot.gone {
  opacity: 0;
  pointer-events: none;
}

.boot .flask {
  font-size: 46px;
}

.boot h1 {
  margin: 0;
  font-size: 26px;
  letter-spacing: 0.5px;
}

.boot p {
  margin: 0;
  color: var(--dim);
  font-size: 14px;
}

/* ------------------------------------------------------------------- small */

@media (max-width: 560px) {
  :root {
    --tube-w: 42px;
    --tube-h: 168px;
  }

  .board {
    gap: 14px 16px;
  }

  .pill-name {
    order: 10;
    flex-basis: 100%;
    text-align: center;
  }
}

/* Respect a stated preference for less motion: the pour still happens and the
   board still updates, it just stops arcing and tipping.

   Only half of that promise can be kept here. The pour is animated by script,
   so a stylesheet cannot flatten it — `reducedMotion()` in `ui.js` is the other
   half, and the two have to agree. The flourish on a finished tube and the
   shake on a refused click are deliberately left alone: they are short, and the
   shake is the only feedback an illegal click gets besides sound. */
@media (prefers-reduced-motion: reduce) {
  .tube,
  .card {
    transition: none;
  }
}
