/*
 * playtest.css — the solo playtester's board (/tools/playtest/).
 *
 * A page-scoped stylesheet with its own letter token, following
 * life-counter.css's precedent: styles.css rides ONE site-wide date token, so
 * putting a single page's board layout there would bust the cache on all 670
 * pages every time this file is touched during a multi-session build.
 *
 *  ⚠ THE BOARD IS A BOUNDED REGION IN NORMAL FLOW, NOT A FIXED VIEWPORT LAYER.
 *    That is a deliberate layout decision, made before this file was written,
 *    and it buys two things at once. (1) AdSense is required on every page and
 *    must never overlay a play surface — with the board in flow the ads are
 *    simply page furniture above and below it. (2) The hand is pinned to the
 *    bottom of the BOARD rather than the bottom of the screen, so it cannot
 *    land under a phone's system navigation bar — which is the single loudest
 *    complaint about the playtester this one is measured against, fixed
 *    structurally instead of with a padding value somebody has to maintain.
 *
 *  ⚠ EVERY TAP TARGET IS >= 44px. Touch is the primary input here, not a
 *    port — see playtest.js's header.
 */

.pt-loader { margin: 1.5rem 0 2rem; }

.pt-load-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: 1fr;
}
@media (min-width: 780px) {
  .pt-load-grid { grid-template-columns: 1fr 1fr; align-items: start; }
}

.pt-load-card h2 { margin-top: 0; font-size: 1.15rem; }
.pt-load-card textarea,
.pt-load-card select {
  width: 100%;
  font: inherit;
}
.pt-load-card textarea {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9rem;
  resize: vertical;
}
.pt-load-actions { margin: 0.75rem 0 0; }
.pt-load-mine { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--line, #d9d5cc); }
.pt-load-mine h3 { margin: 0 0 0.35rem; font-size: 1rem; }
.pt-load-status { margin: 0 0 1rem; font-weight: 600; }
.pt-load-status.is-error,
.pt-load-signin.is-error { color: var(--danger, #b3261e); }

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

.pt-board {
  border: 1px solid var(--line, #d9d5cc);
  border-radius: 10px;
  background: var(--surface-2, #f3f0e9);
  overflow: hidden;
  margin: 1.5rem 0 2rem;
  display: flex;
  flex-direction: column;
  /* Tall enough to play in, bounded enough to leave the page around it. */
  min-height: min(78vh, 760px);
}
.pt-board:fullscreen { min-height: 100vh; border-radius: 0; border: 0; }

.pt-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  padding: 0.5rem 0.65rem;
  background: var(--surface, #fff);
  border-bottom: 1px solid var(--line, #d9d5cc);
}
.pt-bar-group { display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap; }
.pt-bar-id { font-weight: 600; gap: 0.6rem; }
.pt-deck-name { max-width: 22ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pt-turn { font-variant-numeric: tabular-nums; color: var(--muted, #6b6459); font-weight: 500; }
.pt-bar-life { margin-left: auto; }

/*
 * ⚠ The More toggle exists ONLY below 640px. Measured 2026-09-07: a flat bar
 * was 226px over five rows on a 390x844 phone, so the toolbar was the biggest
 * thing on the board and the battlefield sat at its minimum height. On a wide
 * screen there is room for everything, so the toggle disappears and the
 * secondary group is simply inline — no state, nothing to get stuck open.
 */
.pt-more-toggle { display: none; }
.pt-bar-more { display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap; }

.pt-life {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  border: 1px solid var(--line, #d9d5cc);
  border-radius: 999px;
  padding: 0.1rem;
  background: var(--surface, #fff);
}
.pt-life--opp { opacity: 0.85; }
.pt-opp-label { font-size: 0.75rem; color: var(--muted, #6b6459); padding: 0 0.3rem 0 0.5rem; }
.pt-life-n { min-width: 2.2ch; text-align: center; font-variant-numeric: tabular-nums; font-weight: 700; }
.pt-life-btn {
  width: 30px; height: 30px;
  border: 0; border-radius: 999px;
  background: transparent;
  font-size: 1.05rem; line-height: 1;
  cursor: pointer;
  color: inherit;
}
.pt-life-btn:hover { background: var(--surface-2, #f3f0e9); }
.pt-opps { display: inline-flex; gap: 0.35rem; flex-wrap: wrap; }

/* ---------- the mana pool ---------- */

.pt-mana {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.3rem;
  padding: 0.35rem 0.65rem;
  background: var(--surface, #fff);
  border-bottom: 1px solid var(--line, #d9d5cc);
}
.pt-mana-label {
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--muted, #6b6459); margin-right: 0.15rem;
}
.pt-mana-btn {
  display: inline-flex; align-items: center; gap: 0.25rem;
  min-height: 34px; padding: 0.2rem 0.5rem;
  border: 1px solid var(--line, #d9d5cc);
  border-radius: 999px;
  background: transparent;
  font: inherit; color: inherit;
  cursor: pointer;
}
.pt-mana-btn:hover { background: var(--surface-2, #f3f0e9); }
/* A colour holding mana is the one thing you scan this strip for. */
.pt-mana-btn.has-mana { border-color: var(--accent, #b8860b); background: var(--accent-soft, #fdf5e3); font-weight: 700; }
.pt-mana-n { font-variant-numeric: tabular-nums; min-width: 1ch; text-align: center; }
.pt-mana-empty { margin-left: 0.2rem; }
.pt-mana-hint { font-size: 0.75rem; color: var(--muted, #6b6459); margin-left: auto; }
@media (max-width: 640px) { .pt-mana-hint { display: none; } }

/* ---------- the game log and the shortcut sheet ---------- */

.pt-log { list-style: none; margin: 0; padding: 0; max-height: 55vh; overflow-y: auto; }
.pt-log-row {
  display: flex; gap: 0.6rem; align-items: baseline;
  padding: 0.3rem 0.2rem;
  border-bottom: 1px solid var(--line, #d9d5cc);
  font-size: 0.9rem;
}
.pt-log-row:last-child { border-bottom: 0; }
.pt-log-turn {
  flex: none; min-width: 2.5ch;
  font-variant-numeric: tabular-nums;
  font-size: 0.75rem; font-weight: 700;
  color: var(--muted, #6b6459);
}
/* An undo is part of the record, and it reads as a different kind of line. */
.pt-log-row.is-undo .pt-log-text { font-style: italic; color: var(--muted, #6b6459); }

.pt-keys { list-style: none; margin: 0; padding: 0; }
.pt-keys li { display: flex; gap: 0.75rem; align-items: baseline; padding: 0.35rem 0.2rem; }
.pt-keys kbd {
  flex: none; min-width: 4.5ch; text-align: center;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.8rem;
  border: 1px solid var(--line, #d9d5cc);
  border-bottom-width: 2px;
  border-radius: 4px;
  padding: 1px 5px;
  background: var(--surface-2, #f3f0e9);
}

/* ---------- the selection bar ---------- */

.pt-selbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.3rem;
  padding: 0.4rem 0.65rem;
  background: var(--accent-soft, #fdf5e3);
  border-bottom: 1px solid var(--accent, #b8860b);
}
.pt-sel-n { font-weight: 700; margin-right: 0.35rem; font-variant-numeric: tabular-nums; }
/* Select mode changes what a tap MEANS, so the button has to look latched
   rather than merely focused — a mode you cannot see is a mode you fight. */
#pt-selectmode.is-on {
  background: var(--accent, #b8860b);
  border-color: var(--accent, #b8860b);
  color: #fff;
}
.pt-picking .pt-card.is-selected { z-index: 5; }

.pt-prompt {
  margin: 0;
  padding: 0.45rem 0.75rem;
  background: var(--accent-soft, #fdf5e3);
  border-bottom: 1px solid var(--line, #d9d5cc);
  font-size: 0.9rem;
}

.pt-play {
  flex: 1;
  display: flex;
  min-height: 0;
}

/* ---------- battlefield ---------- */

.pt-field {
  position: relative;
  flex: 1;
  min-height: 300px;
  /* A faint grid so an empty board reads as a surface rather than as a bug. */
  background:
    repeating-linear-gradient(0deg, transparent 0 39px, rgba(0,0,0,0.04) 39px 40px),
    repeating-linear-gradient(90deg, transparent 0 39px, rgba(0,0,0,0.04) 39px 40px);
  overflow: hidden;
  touch-action: manipulation;
}
.pt-field-empty {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  margin: 0; padding: 1rem;
  color: var(--muted, #6b6459);
  text-align: center;
  pointer-events: none;
}

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

.pt-card {
  position: relative;
  cursor: pointer;
  border-radius: 5px;
  line-height: 0;
  transition: transform 120ms ease, box-shadow 120ms ease;
}
.pt-card img { display: block; border-radius: 5px; width: 100%; height: auto; }
/*
 * ⚠ ONE VARIABLE DRIVES EVERY CARD, and the default moved UP. The board
 * shipped at 96px (116px on a wide screen), which is about 134px of card
 * height — a Magic card's rules text is unreadable at that size, and the owner
 * said so the day it shipped. `m` is the new default at 132px; the stepper
 * moves between four steps and the choice persists per device, because "many
 * cards visible" and "one card readable" are a real trade-off that belongs to
 * the player rather than to this file.
 *
 * The hand runs slightly larger than the battlefield: it holds at most a
 * handful of cards, it scrolls sideways, and it is the zone you actually read.
 */
.pt-board { --pt-card-w: 132px; }
.pt-board[data-size="s"]  { --pt-card-w: 100px; }
.pt-board[data-size="m"]  { --pt-card-w: 132px; }
.pt-board[data-size="l"]  { --pt-card-w: 168px; }
.pt-board[data-size="xl"] { --pt-card-w: 210px; }

.pt-card--field { position: absolute; width: var(--pt-card-w); }
.pt-card--field.is-tapped { transform: rotate(90deg); }
.pt-card.is-selected {
  outline: 3px solid var(--accent, #b8860b);
  outline-offset: 2px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.25);
}
.pt-card:focus-visible { outline: 3px solid var(--accent, #b8860b); outline-offset: 2px; }

/*
 * ⚠ TOUCH-ACTION IS SPLIT BY ZONE, and it is the difference between a drag
 * that works and a gesture the browser takes for itself. A battlefield card
 * owns every direction. A HAND card is `pan-y`: a sideways swipe still scrolls
 * the hand — which has to keep working, it is how you reach cards 8 to 12 —
 * while a drag away from the hand is ours. Playing a card is a movement OUT of
 * the hand, so the axis split matches the gesture people already make.
 */
.pt-card--field { touch-action: none; }
.pt-card--hand { touch-action: pan-x; }

/* The original stays put and dims; the thing that moves is the ghost. */
.pt-card.is-dragging { opacity: 0.32; }

.pt-ghost {
  position: fixed;
  z-index: 1400;
  pointer-events: none;              /* ⚠ invisible to elementFromPoint */
  border-radius: 5px;
  box-shadow: 0 16px 40px rgba(0,0,0,0.45);
  transform: rotate(-2deg) scale(1.04);
  line-height: 0;
}
.pt-ghost img { width: 100%; height: 100%; border-radius: 5px; display: block; }
/* The flight home. Short enough not to be in the way, long enough to read as
   an answer — "it went back" rather than "nothing happened". */
.pt-ghost.is-returning {
  transition: left 170ms ease-out, top 170ms ease-out, transform 170ms ease-out;
  transform: rotate(0deg) scale(1);
}

/* Where it would land, while it is in the air. */
.pt-zone.is-drop-target,
.pt-hand.is-drop-target { background: var(--accent-soft, #fdf5e3); box-shadow: inset 0 0 0 2px var(--accent, #b8860b); }
.pt-field.is-drop-target { box-shadow: inset 0 0 0 3px var(--accent, #b8860b); }

/* A drag must not also select the article text underneath it. */
body.pt-dragging { user-select: none; -webkit-user-select: none; }
body.pt-dragging .pt-card { cursor: grabbing; }

.pt-card-name {
  display: block;
  padding: 0.5rem;
  font-size: 0.75rem;
  line-height: 1.25;
  border: 1px solid var(--line, #d9d5cc);
  border-radius: 5px;
  background: var(--surface, #fff);
  min-height: 130px;
}
.pt-card-back {
  display: block;
  aspect-ratio: 488 / 680;
  border-radius: 5px;
  border: 1px solid #2b2116;
  background:
    radial-gradient(ellipse at 50% 45%, #6b563a 0%, #3a2c1c 55%, #201811 100%);
}

/* The ⋮ affordance. It exists because a long-press menu that only SOMETIMES
   appears is the reference implementation's other standing complaint — a
   visible button cannot fail to appear, and long-press can be added on top of
   it rather than being the only way in. */
.pt-card-more {
  position: absolute;
  top: 2px; right: 2px;
  width: 26px; height: 26px;
  border: 0; border-radius: 999px;
  background: rgba(20, 16, 12, 0.72);
  color: #fff;
  font-size: 15px; line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity 120ms ease;
}
.pt-card:hover .pt-card-more,
.pt-card:focus-within .pt-card-more { opacity: 1; }
/* On touch there is no hover, so it is always visible — and always 26px. */
@media (hover: none) { .pt-card-more { opacity: 1; } }

.pt-ctrs {
  position: absolute;
  left: 2px; bottom: 2px; right: 2px;
  display: flex; flex-wrap: wrap; gap: 2px;
  line-height: 1;
}
.pt-ctr {
  font-size: 0.62rem;
  padding: 2px 4px;
  border-radius: 3px;
  background: rgba(20, 16, 12, 0.82);
  color: #fff;
  font-weight: 700;
}

/* ---------- the zone rail ---------- */

.pt-rail {
  width: 108px;
  flex: none;
  display: flex;
  flex-direction: column;
  border-left: 1px solid var(--line, #d9d5cc);
  background: var(--surface, #fff);
}
.pt-zone {
  flex: 1;
  min-height: 56px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.1rem;
  border: 0;
  border-bottom: 1px solid var(--line, #d9d5cc);
  background: transparent;
  cursor: pointer;
  font: inherit;
  color: inherit;
  padding: 0.4rem;
}
.pt-zone:last-child { border-bottom: 0; }
.pt-zone:hover { background: var(--surface-2, #f3f0e9); }
.pt-zone-name { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted, #6b6459); }
.pt-zone-n { font-size: 1.35rem; font-weight: 700; font-variant-numeric: tabular-nums; }

/* While a card is picked up, every legal destination announces itself. */
.pt-picking .pt-zone { background: var(--accent-soft, #fdf5e3); box-shadow: inset 0 0 0 2px var(--accent, #b8860b); }
.pt-picking .pt-field { box-shadow: inset 0 0 0 3px var(--accent, #b8860b); }

/* ---------- hand ---------- */

.pt-hand {
  flex: none;
  border-top: 1px solid var(--line, #d9d5cc);
  background: var(--surface, #fff);
  padding: 0.4rem 0.6rem 0.6rem;
}
.pt-hand-head {
  display: flex; align-items: center; gap: 0.5rem;
  margin-bottom: 0.35rem;
}
.pt-hand-label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted, #6b6459); }
.pt-hand-n { font-weight: 700; font-variant-numeric: tabular-nums; }
.pt-owe {
  margin-left: auto;
  font-size: 0.8rem; font-weight: 600;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  background: var(--accent-soft, #fdf5e3);
  border: 1px solid var(--accent, #b8860b);
}
/*
 * The bottoming step. A picked card is dimmed and marked rather than merely
 * outlined: at a glance you have to be able to tell which cards are LEAVING,
 * and an outline reads as "selected", which on this board already means
 * something else (picked up, about to be played).
 */
.pt-card--hand.is-bottoming { opacity: 0.55; }
.pt-card--hand.is-bottoming img { filter: grayscale(0.6); }
.pt-bottom-mark {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%) rotate(-8deg);
  background: rgba(20, 16, 12, 0.86);
  color: #fff;
  font-size: 0.7rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 4px;
  line-height: 1;
  pointer-events: none;
}
.pt-owe-n { font-variant-numeric: tabular-nums; opacity: 0.75; }
.pt-keep { margin-left: 0.4rem; }

.pt-hand-empty { margin: 0; color: var(--muted, #6b6459); font-size: 0.9rem; }
.pt-hand-cards {
  display: flex;
  gap: 0.35rem;
  overflow-x: auto;
  padding-bottom: 0.25rem;
  scrollbar-width: thin;
}
.pt-card--hand { flex: none; width: calc(var(--pt-card-w) * 1.08); }

/* ---------- the size stepper ---------- */

.pt-size { display: inline-flex; align-items: center; gap: 0.15rem; }
.pt-size-label {
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--muted, #6b6459); padding: 0 0.1rem;
}
.pt-size-btn { min-width: 34px; padding-left: 0.5rem; padding-right: 0.5rem; }
.pt-size-btn[disabled] { opacity: 0.4; cursor: default; }

/* ---------- the hover preview (mouse only; see playtest.js) ---------- */

.pt-preview {
  position: fixed;
  z-index: 1300;
  width: 320px;
  height: auto;
  border-radius: 12px;
  box-shadow: 0 18px 48px rgba(0,0,0,0.42);
  pointer-events: none;   /* it must never be a hit target of its own */
}

/* ---------- the action menu ---------- */

.pt-menu {
  position: absolute;
  z-index: 1200;
  min-width: 200px;
  max-width: min(280px, calc(100vw - 16px));
  max-height: min(60vh, 420px);
  overflow-y: auto;
  background: var(--surface, #fff);
  border: 1px solid var(--line, #d9d5cc);
  border-radius: 8px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.22);
  padding: 0.25rem;
}
.pt-menu-head {
  margin: 0;
  padding: 0.4rem 0.6rem;
  font-weight: 700;
  font-size: 0.85rem;
  border-bottom: 1px solid var(--line, #d9d5cc);
}
.pt-menu button {
  display: block;
  width: 100%;
  text-align: left;
  border: 0;
  background: transparent;
  font: inherit;
  color: inherit;
  padding: 0.55rem 0.6rem;
  border-radius: 5px;
  cursor: pointer;
  min-height: 44px;
}
.pt-menu button:hover,
.pt-menu button:focus-visible { background: var(--surface-2, #f3f0e9); }

/* ---------- the zone viewer ---------- */

.pt-zlist { list-style: none; margin: 0; padding: 0; max-height: 55vh; overflow-y: auto; }
.pt-zrow {
  display: flex; align-items: center; gap: 0.6rem;
  width: 100%;
  min-height: 48px;
  padding: 0.3rem 0.4rem;
  border: 0; border-radius: 5px;
  background: transparent;
  font: inherit; color: inherit; text-align: left;
  cursor: pointer;
}
.pt-zrow:hover { background: var(--surface-2, #f3f0e9); }
.pt-zrow img { border-radius: 3px; }
.pt-zrow-noart { width: 40px; height: 56px; border-radius: 3px; background: var(--surface-2, #f3f0e9); flex: none; }
.pt-zrow-name { flex: 1; }
.pt-zrow-pos { font-size: 0.78rem; color: var(--muted, #6b6459); font-variant-numeric: tabular-nums; }
.pt-zrow-empty { padding: 1rem; color: var(--muted, #6b6459); }

/* ---------- phone ---------- */

@media (max-width: 640px) {
  .pt-more-toggle { display: inline-flex; }
  .pt-bar-more { display: none; width: 100%; }
  .pt-bar-more.is-open { display: flex; }
  /* Tighter everything too — the split alone left the bar at 122px over three
     rows, with the deck name pushing the life control onto its own line. */
  .pt-bar { gap: 0.35rem 0.5rem; padding: 0.4rem 0.5rem; }
  .pt-bar .btn { padding: 0.35rem 0.55rem; font-size: 0.85rem; }
  .pt-deck-name { max-width: 11ch; font-size: 0.9rem; }
  .pt-bar-id { gap: 0.4rem; }
  .pt-life-btn { width: 28px; height: 28px; }
  /*
   * ⚠ THE SIZE STEPPER LIVES IN THE `More` GROUP, WHICH IS WHY IT IS NOT HERE.
   * It sat in the primary row first and cost a whole toolbar row on a phone —
   * 112px → 143px, and the battlefield fell straight back to its 300px
   * minimum, undoing the compaction two commits earlier bought. Two other
   * shapes were measured and rejected: the word "Cards" (same 143px) and a
   * 9px drawn-card glyph replacing it (also 143px — the buttons were the cost,
   * not the label). In the More group it is one tap away on a phone and
   * permanently inline on a desktop, using the collapse that already exists
   * rather than a second mechanism. The phone's DEFAULT card also went up
   * (92px → 112px), so the control is a preference rather than a repair.
   */
  /* A phone is narrow, so the default steps down one — the stepper still goes
     up, and the choice is remembered. */
  .pt-board { --pt-card-w: 112px; }
  .pt-board[data-size="m"] { --pt-card-w: 112px; }
  .pt-board[data-size="l"] { --pt-card-w: 140px; }
  .pt-board[data-size="xl"] { --pt-card-w: 176px; }
  .pt-play { flex-direction: column-reverse; }
  /* The rail becomes a row above the battlefield — never below it, where it
     would sit between the hand and the play area and get hit by accident. */
  .pt-rail {
    width: auto;
    flex-direction: row;
    border-left: 0;
    border-bottom: 1px solid var(--line, #d9d5cc);
  }
  .pt-zone { border-bottom: 0; border-right: 1px solid var(--line, #d9d5cc); min-height: 52px; }
  .pt-zone:last-child { border-right: 0; }
  .pt-zone-n { font-size: 1.1rem; }
  .pt-bar-life { margin-left: 0; width: 100%; }
  .pt-board { min-height: min(86vh, 720px); }
}
