/* ---------------------------------------------------------------------------
   The table: chrome around the game, and the coordinate system the cards live
   in. Every pile position is derived from one variable, --card-w, so the whole
   layout scales as a unit from an iPhone SE to a desktop.
   --------------------------------------------------------------------------- */

.table {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

/* Top bar ----------------------------------------------------------------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: calc(var(--safe-top) + 9px) 14px 9px;
  background: color-mix(in srgb, var(--bg-sunken) 78%, transparent);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--separator);
}

.topbar__back {
  flex: none;
  font-size: 16px;
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  gap: 2px;
}

.topbar__back:hover { text-decoration: none; opacity: 0.7; }

.topbar__center {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-variant-numeric: tabular-nums;
}

.topbar__stat {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--label);
}

.topbar__divider {
  width: 1px;
  height: 13px;
  background: var(--separator);
}

.topbar__actions {
  flex: none;
  display: flex;
  align-items: center;
  gap: 2px;
}

.topbar__actions form { margin: 0; display: inline-flex; }

.icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--accent);
  cursor: pointer;
  transition: background-color 0.16s var(--ease-out), opacity 0.16s var(--ease-out);
}

.icon-button svg { width: 20px; height: 20px; }
.icon-button:hover { background: var(--accent-soft); }
.icon-button:active { transform: scale(0.92); }
.icon-button[disabled] { color: var(--label-tertiary); cursor: default; }
.icon-button[disabled]:hover { background: transparent; }

/* Playing surface --------------------------------------------------------- */

.board {
  --card-w: min(
    104px,
    calc((min(100vw, 1000px) - 24px) / 7.72),
    calc((100dvh - 186px) / 6.4)
  );
  --card-h: calc(var(--card-w) * 1.4);
  --gap: calc(var(--card-w) * 0.12);
  --row-gap: calc(var(--card-w) * 0.34);
  --stack: calc(var(--card-w) * 0.335);
  --stack-down: calc(var(--card-w) * 0.125);
  --fan: calc(var(--card-w) * 0.30);

  position: relative;
  flex: 1;
  padding: 16px 12px 96px;
  background:
    radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--felt) 60%, transparent), transparent 70%),
    var(--bg-sunken);
  overflow-x: hidden;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
}

/* Phones -------------------------------------------------------------------
   Seven columns have to fit across the screen, so the width of a card is
   arithmetic, not taste: viewport divided by seven-and-a-bit. No amount of CSS
   makes them meaningfully wider.

   What was going to waste was the height. The board used barely half the
   screen and the cards looked stranded in it. So they get taller rather than
   wider — 1.52 rather than the 1.4 of a real playing card, which is roughly a
   bridge deck — the gutters and gaps give back what little they can, and the
   columns fan further down into the space they were leaving empty. Together
   that is about a fifth more card, and it reads as considerably more. */
@media (max-width: 700px) {
  .board {
    --card-w: min(
      calc((100vw - 16px) / 7.42),
      calc((100dvh - 170px) / 7.2)
    );
    --card-h: calc(var(--card-w) * 1.52);
    --gap: calc(var(--card-w) * 0.07);
    --stack: calc(var(--card-w) * 0.42);
    --stack-down: calc(var(--card-w) * 0.16);

    padding-inline: 8px;
  }
}

.board__form { display: none; }

.board__surface {
  position: relative;
  width: calc(7 * var(--card-w) + 6 * var(--gap));
  min-height: calc(var(--card-h) * 2 + var(--row-gap) + var(--stack) * 11);
  margin-inline: auto;
}

/* Empty pile outlines ----------------------------------------------------- */

.slot,
.card {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--card-w);
  height: var(--card-h);
  border-radius: calc(var(--card-w) * 0.11);
  transform: translate3d(
    calc(var(--col) * (var(--card-w) + var(--gap)) + var(--dx, 0px) + var(--drag-x, 0px)),
    calc(var(--row) * (var(--card-h) + var(--row-gap)) + var(--dy, 0px) + var(--drag-y, 0px)),
    0
  );
}

.slot {
  display: grid;
  place-items: center;
  border: 1.5px solid var(--felt-edge);
  background: color-mix(in srgb, var(--felt) 55%, transparent);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.03);
  transition: border-color 0.2s var(--ease-out), background-color 0.2s var(--ease-out),
              box-shadow 0.2s var(--ease-out);
}

.slot--stock { cursor: pointer; }

.slot__glyph {
  font-size: calc(var(--card-w) * 0.42);
  line-height: 1;
  color: var(--label-tertiary);
  opacity: 0.5;
}

.slot__glyph--red { color: color-mix(in srgb, var(--red) 45%, transparent); }
.slot__glyph--black { color: var(--label-tertiary); }

/* Highlighted while a card is being dragged over a legal target. */
.slot.is-target,
.slot.is-hinted {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 14%, transparent);
}

.slot.is-hinted { animation: pulse 1.1s var(--ease-out) 2; }

@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 26%, transparent); }
  50%      { box-shadow: 0 0 0 8px color-mix(in srgb, var(--accent) 0%, transparent); }
}

/* Bottom toolbar ---------------------------------------------------------- */

.toolbar {
  position: fixed;
  left: 50%;
  bottom: calc(var(--safe-bottom) + 14px);
  transform: translateX(-50%);
  z-index: 25;
  display: flex;
  gap: 4px;
  padding: 4px;
  border-radius: 16px;
  background: color-mix(in srgb, var(--bg-elevated) 84%, transparent);
  -webkit-backdrop-filter: saturate(180%) blur(24px);
  backdrop-filter: saturate(180%) blur(24px);
  border: 1px solid var(--separator);
  box-shadow: var(--shadow-panel);
}

.toolbar form { margin: 0; }

.toolbar__button {
  border: 0;
  white-space: nowrap;
  background: transparent;
  color: var(--label);
  font-size: 15px;
  font-weight: 500;
  padding: 9px 16px;
  border-radius: 12px;
  cursor: pointer;
  transition: background-color 0.16s var(--ease-out);
}

.toolbar__button:hover { background: var(--bg-sunken); }
.toolbar__button:active { transform: scale(0.96); }
.toolbar__button--accent { color: var(--accent); font-weight: 600; }
.toolbar__button[disabled] { color: var(--label-tertiary); cursor: default; }
.toolbar__button[disabled]:hover { background: transparent; }

/* Win state --------------------------------------------------------------- */

.victory {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  padding: 24px;
  background: color-mix(in srgb, var(--bg-sunken) 38%, transparent);
  -webkit-backdrop-filter: blur(7px);
  backdrop-filter: blur(7px);
  /* Held back until the cards have finished. See the delays below — the
     panel arriving over a board still in motion is the one moment in the
     game where two animations fight each other. */
  animation: fade-in 0.5s var(--ease-out) var(--victory-delay, 1.25s) both;
}

.victory__panel {
  width: min(340px, 100%);
  display: grid;
  gap: 10px;
  padding: 28px 24px 20px;
  border-radius: 22px;
  background: var(--bg-elevated);
  box-shadow: var(--shadow-lift);
  text-align: center;
  animation: panel-in 0.5s var(--ease-spring) var(--victory-delay, 1.25s) both;
}

.victory__eyebrow {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--green);
}

.victory__title {
  font-family: var(--font-rounded);
  font-size: 27px;
  font-weight: 700;
  letter-spacing: -0.03em;
}

.victory__meta {
  font-size: 14px;
  color: var(--label-secondary);
  margin-bottom: 8px;
}

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

@keyframes panel-in {
  from { opacity: 0; transform: translateY(14px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}

.nudge {
  position: fixed;
  bottom: calc(var(--safe-bottom) + 72px);
  z-index: 24;
  width: min(260px, calc(100vw - 48px));

  /* Centred with auto margins rather than translateX(-50%), because the
     animation below ends on `transform: none` and fill-mode `both` keeps that
     applied for good — which silently threw the button half its own width to
     the right, forever. Layout and animation must not fight over transform. */
  left: 0;
  right: 0;
  margin-inline: auto;

  animation: panel-in 0.4s var(--ease-spring) both;
}

/* Legal targets, surfaced only while a card is in the air. */
.slot.is-available {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}

.topbar__back--placeholder { width: 56px; }

.toolbar__button--quiet { color: var(--label-secondary); }

/* A surrendered game keeps its board visible — the point is to look at it —
   so the panel sits at the bottom instead of covering everything. */
.victory--quiet {
  background: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  align-items: end;
  padding-bottom: calc(var(--safe-bottom) + 78px);
  pointer-events: none;
  animation-delay: 0.15s;
}

.victory--quiet .victory__panel {
  pointer-events: auto;
  animation-delay: 0.15s;
}

.victory__eyebrow--quiet { color: var(--label-tertiary); }

.victory__note {
  font-size: 13px;
  color: var(--label-tertiary);
  margin: -4px 0 8px;
}

.victory--quiet .victory__panel {
  width: min(420px, calc(100vw - 28px));
  padding: 16px 20px 16px;
  gap: 4px;
}

.victory--quiet .victory__title { font-size: 21px; }
.victory--quiet .victory__meta { margin-bottom: 0; }

.victory__actions {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

.victory__actions > * { flex: 1; margin: 0; }
.victory__actions .button { padding: 11px 16px; font-size: 16px; }

/* Sound toggle ------------------------------------------------------------ */

.toolbar__button--icon {
  display: grid;
  place-items: center;
  padding: 9px 12px;
  color: var(--label-secondary);
}

/* One icon, two states: the waves and the cross swap places. */
.toolbar__slash { display: none; }
.toolbar__button.is-muted .toolbar__wave { display: none; }
.toolbar__button.is-muted .toolbar__slash { display: block; }

/* Native chrome ------------------------------------------------------------
   Inside the iOS app these controls are drawn by UIKit — a real navigation bar
   and a real bottom toolbar — so the web versions are hidden. They stay in the
   DOM on purpose: the native buttons work by clicking them, which keeps Turbo,
   the CSRF token and the give-up confirmation exactly as they are in a
   browser. */

.is-native .topbar,
.is-native .toolbar { display: none; }

/* The web view does not inset itself for the native bars — see
   contentInsetAdjustmentBehavior in AppDelegate — so the page has to leave
   room, or the stock, waste and foundations sit underneath the navigation bar
   where they cannot be seen or tapped. 44pt is a standard navigation bar;
   49pt a standard toolbar. */
.is-native .board {
  padding-top: calc(var(--safe-top) + 44px);
  padding-bottom: calc(var(--safe-bottom) + 60px);
}

/* Phones on their side -----------------------------------------------------
   Landscape is bound by height, not width: at 852x393 the width term allows a
   107px card while the height term allows 32px, so the cards came out a third
   of the size they could be and the table sat marooned in whitespace.

   The default divisor of 6.4 reserves room for two rows plus a full thirteen
   card fan. There is not the height for that lying down, so this reserves room
   for two rows plus eight and lets a deep column scroll — which is rare, and
   better than shrinking every card in every game for the worst case.

   --stack stays at 0.36 rather than going tighter. Below roughly a third of a
   card the rank at the top of a buried card starts being clipped, which is the
   bug that made queens read as O and jacks as I. */
@media (orientation: landscape) and (max-height: 560px) {
  .board {
    /* 118px of chrome, not 88: a navigation bar is 44pt, a toolbar 49pt, and
       the home indicator wants another 21. Budgeting 88 sized the cards for
       thirty points of room that does not exist, which is how a long column
       ended up drawn straight through the Hint button.

       The divisor covers two rows plus the deepest column somebody actually
       builds — six face-down at 0.13 apart, then a run of eight. Rarer than
       that scrolls, which is the right thing to make rare rather than to make
       every card smaller for. */
    --card-w: min(
      104px,
      calc((100vw - 20px) / 7.5),
      calc((100dvh - 118px) / 6.2)
    );

    /* Slightly squatter than the 1.4 of a real card. Lying down, height is the
       scarce dimension and every point of it buys width across seven columns. */
    --card-h: calc(var(--card-w) * 1.34);
    --gap: calc(var(--card-w) * 0.07);
    --row-gap: calc(var(--card-w) * 0.22);
    --stack: calc(var(--card-w) * 0.34);
    --stack-down: calc(var(--card-w) * 0.13);

    padding: 10px 10px 56px;
  }
}
