/*
 * 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-upg { margin: 0.6rem 0 0; display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.pt-upg-note { margin: 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);
}
/*
 * ⚠ FOCUS MODE IS DRIVEN BY `.pt-fs` ON <html>, NOT BY `:fullscreen` ON THE
 * BOARD. The board used to be the fullscreen element, which meant every
 * overlay appended to <body> — menus, modals, the hover preview, the drag
 * ghost — was outside the rendered subtree and simply never painted. The
 * document is the fullscreen element now, so this hides everything else
 * instead. See the Focus handler in playtest.js.
 *
 * ⚠ IT NAMES THE SHELL RATHER THAN HIDING EVERY SIBLING, and that was the
 * first version's bug: `body > *:not(main)` also matched the OVERLAYS this page
 * appends to <body> — the card menu, the modals, the ghost — so the fix for
 * "the menu does not render in Focus" hid the menu. Measured as a 0x0 box.
 * Naming the shell is safe precisely here: nav and footer markup is
 * byte-identical across every page and CI enforces it (--strict-shell), so
 * these three selectors cannot quietly drift, while anything appended to <body>
 * later keeps working without being remembered.
 */
.pt-fs, .pt-fs body {
  margin: 0;
  background: var(--surface-2, #f3f0e9);
  /* ⚠ THE BOARD IS EXACTLY 100vh, SO ANY PADDING AROUND IT IS A SCROLLBAR.
     `main` carries `padding: 32px 0 48px` from the site shell — 100vh + 80px —
     which is precisely what the owner saw. Zeroing main's padding is the real
     fix; `overflow: hidden` here is the belt to its braces, because focus mode
     has nowhere to scroll TO and a stray margin should never be able to
     reintroduce a bar. */
  height: 100%;
  overflow: hidden;
}
.pt-fs main { padding: 0 !important; margin: 0 !important; }
.pt-fs .site-header,
.pt-fs .site-footer,
.pt-fs .skip-link { display: none !important; }
.pt-fs main > .container > *:not(.pt-board) { display: none !important; }
.pt-fs main > .container { max-width: none; padding: 0; margin: 0; }
.pt-fs .pt-board {
  min-height: 100vh;
  height: 100vh;
  margin: 0;
  border: 0;
  border-radius: 0;
}
/* ⚠ Not merely covered — an ad rendered where nobody can see it is the shape
   of an invalid impression; one that is not rendered cannot be. */
.pt-fs .ad-slot { display: none !important; }

/* ⚠ A card image must never start the browser's own drag: it cancels the
   pointer, and the board's drag ends through the cancel path with the card
   flying home. The attribute in cardImgHtml is the fix; this covers the
   WebKit-only property that the attribute does not. */
.pt-card img, .pt-ghost img { -webkit-user-drag: none; user-select: none; }

.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; }
/* The secondary groups sit on their own line, aligned to the start, so the
   blocks form a tidy band rather than trailing off the primary row. */
.pt-bar-more { width: 100%; align-items: flex-start; }
.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 0.9rem; flex-wrap: wrap; }

/*
 * ⚠ THE LABEL SITS ABOVE ITS BUTTONS, NOT BESIDE THEM. Inline, every group
 * began with a small word and then jumped to full-height buttons, so the row
 * had a bumpy baseline and wrapped mid-thought. Stacked, each group is a
 * self-contained block that wraps as a unit — which is what makes five groups
 * read as five things rather than as seventeen buttons with captions.
 *
 * ⚠ AND THE SECONDARY BUTTONS ARE OUTLINED, NOT FILLED. Every control in this
 * bar was solid, so the three you press every turn (New turn, Draw, Undo) had
 * no more weight than "Keys" — a wall of identical brown. `.btn-secondary` is
 * DESIGN.md's adopted contract name for exactly this, so the calm state is the
 * site's own, not a variant invented here.
 */
/*
 * ⚠ THE LABEL IS INLINE AND THE GROUP NEVER SPLITS. Stacking the label above
 * its buttons was tried and measured: it read well but pushed the bar from
 * 145px to 194px, because each block became two lines and the groups then
 * wrapped into two rows of blocks — and the Game group was squeezed until its
 * two buttons stacked. Board height is the scarce resource here, so the label
 * sits inline and `nowrap` on the row is what buys the tidiness instead: a
 * group wraps as a UNIT or not at all, which is what stops the bar reading as
 * one ragged list.
 */
.pt-group {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  flex: 0 0 auto;
  padding-left: 0.8rem;
  border-left: 1px solid var(--line, #d9d5cc);
}
.pt-group:first-child { padding-left: 0; border-left: 0; }
.pt-group-row {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  flex-wrap: nowrap;   /* ⚠ a group is one unbroken run of controls */
}
.pt-group-label {
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted, #6b6459);
  white-space: nowrap;
  line-height: 1;
}

/* One height and one rhythm for everything in the bar, so the blocks line up
   whatever their labels say. */
.pt-bar .btn-sm,
.pt-bar .pt-check,
.pt-bar .pt-life { min-height: 32px; }
.pt-bar .btn-sm { padding: 0.3rem 0.65rem; font-size: 0.85rem; line-height: 1.2; }

/* An inline checkbox that sits at button height, so a group reads as one row. */
.pt-check {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  min-height: 34px;
  padding: 0 0.45rem;
  border: 1px solid var(--line, #d9d5cc);
  border-radius: 999px;
  cursor: pointer;
  font-size: 0.85rem;
  white-space: nowrap;
}
.pt-check input { margin: 0; cursor: pointer; }
.pt-check:has(input:checked) {
  border-color: var(--accent, #b8860b);
  background: var(--accent-soft, #fdf5e3);
  font-weight: 700;
}

.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-x`, and the value is the opposite of what it sounds
 * like: `pan-x` means the BROWSER keeps horizontal panning, so a sideways
 * swipe still scrolls the hand — which has to keep working, it is how you
 * reach cards 8 to 12 — while everything vertical is ours. Playing a card is
 * a movement OUT of the hand, so the axis split matches the gesture people
 * already make. ⚠ Both of these comments said `pan-y` until 2026-09-07 while
 * describing `pan-x` behaviour; the code was right and the prose was wrong,
 * which matters because this is the line someone reads when deciding whether
 * a new hand gesture is safe to add.
 */
.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 count badge on a group drag. It is the ONLY thing on screen saying the
 * other selected cards are coming with this one — without it a group drag looks
 * exactly like a single-card drag right up until the drop, which is the moment
 * it is too late to be told.
 */
.pt-ghost-n {
  position: absolute;
  top: -9px;
  right: -9px;
  min-width: 26px;
  height: 26px;
  padding: 0 7px;
  border-radius: 13px;
  background: var(--accent, #b8860b);
  color: #fff;
  font: 700 0.82rem/26px system-ui, -apple-system, sans-serif;
  text-align: center;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
}
/* 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; }
/* Order sits in the hand's own bar, where the hand is — not in the toolbar,
   which it cost a whole row at 1024px and 768px. Pushed to the right so it
   never crowds the count, and it yields the spot to the mulligan's own
   controls, which replace it while a decision is outstanding. */
.pt-hand-order { margin-left: auto; }
.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 gap a drag opens slides rather than jumps — a hole that appears in
   one frame reads as the hand glitching, not as a place being made. Margin
   and width only: the drag layer sets those inline, and transitioning
   `transform` instead would move the card without moving its layout box,
   so the pointer would land in the wrong slot. */
.pt-card--hand { transition: margin 130ms ease, width 130ms ease; }


/* ---------- 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); }

/* ---------- the missed land drop ---------- */

/*
 * One line, dismissible, and it appears only after two turn advances with no
 * new land. It is deliberately styled as a note rather than an error: it is a
 * suggestion about a deck, and a board that scolds you for a bad draw is a
 * board you stop using.
 */
.pt-tip {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.5rem;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--accent, #b8860b);
  border-radius: 6px;
  background: var(--accent-soft, #fdf5e3);
  font-size: 0.88rem;
}
.pt-tip-text { flex: 1; }
.pt-tip-x {
  flex: none;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  font-size: 1.15rem;
  line-height: 1;
  color: inherit;
  cursor: pointer;
}
.pt-tip-x:hover { background: rgba(0, 0, 0, 0.07); }

/* ---------- add a card, and order the hand ---------- */

.pt-add-q {
  width: 100%;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--line, #d9d5cc);
  border-radius: 6px;
  font: inherit;
  background: var(--surface, #fff);
  color: inherit;
}
.pt-add-list { list-style: none; margin: 0.4rem 0 0; padding: 0; max-height: 30vh; overflow-y: auto; }
.pt-add-list:empty { margin: 0; }
/* A THUMB TARGET, NOT A LINK. These are the suggestions, and the whole reason
   this is not a <datalist> is that a finger has to be able to use it. */
.pt-add-hit {
  display: block;
  width: 100%;
  min-height: 44px;
  padding: 0.5rem 0.6rem;
  border: 0;
  border-radius: 5px;
  background: transparent;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.pt-add-hit:hover,
.pt-add-hit:focus-visible { background: var(--surface-2, #f3f0e9); }
.pt-add-where { display: flex; align-items: center; gap: 0.6rem; margin: 0.9rem 0 0; }
.pt-add-where label { flex: none; font-weight: 600; }
.pt-add-where select {
  flex: 1;
  padding: 0.45rem 0.5rem;
  border: 1px solid var(--line, #d9d5cc);
  border-radius: 6px;
  font: inherit;
  background: var(--surface, #fff);
  color: inherit;
}
.pt-add-status { margin: 0.6rem 0 0; min-height: 1.2em; font-size: 0.88rem; }
.pt-add-status.is-error { color: var(--danger, #b3261e); }

.pt-order-sorts { display: flex; gap: 0.4rem; flex-wrap: wrap; margin: 0.9rem 0 0.5rem; }
.pt-order { list-style: none; margin: 0; padding: 0; max-height: 50vh; overflow-y: auto; }
.pt-order-row {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  min-height: 48px;
  padding: 0.25rem 0.3rem;
  border-bottom: 1px solid var(--line, #d9d5cc);
}
.pt-order-row:last-child { border-bottom: 0; }
.pt-order-pos {
  flex: none;
  min-width: 2ch;
  font-variant-numeric: tabular-nums;
  color: var(--muted, #6b6459);
  font-size: 0.8rem;
}
.pt-order-row img { border-radius: 3px; flex: none; }
.pt-order-noart { width: 34px; height: 48px; }
/* The mana value, because sorting by it is only trustworthy if you can see it.
   Blank rather than 0 where the card never resolved: omitted, never zero. */
.pt-order-mv {
  flex: none;
  min-width: 2ch;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--muted, #6b6459);
  font-size: 0.85rem;
}
.pt-order-btns { flex: none; display: flex; gap: 0.25rem; }
.pt-order-btns .btn { min-width: 38px; min-height: 38px; padding: 0.2rem 0.4rem; }

/* ---------- 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; flex-direction: column; align-items: stretch; gap: 0.5rem; }
  /* Stacked on a phone a vertical rule separates nothing, so the divider turns
     horizontal. The label already leads each block, so nothing else changes. */
  .pt-group {
    padding-left: 0;
    border-left: 0;
    border-top: 1px solid var(--line, #d9d5cc);
    padding-top: 0.45rem;
    flex-wrap: wrap;            /* a phone is too narrow to keep a run intact */
  }
  .pt-group-row { flex-wrap: wrap; }
  .pt-group:first-child { border-top: 0; padding-top: 0; }
  /* 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); }
}

/* ---------- the loader on the tool stage (2026-10-25) ----------
 * The two load panels sit on the dark ground the other tools' inputs use
 * (styles.css → Tool stage, which colours the fields, buttons and links).
 * Here only the frame: the section is the stage, the panels are glass on it.
 */
.pt-loader.tool-stage { padding: clamp(16px, 2.6vw, 28px); border-radius: 16px; box-shadow: var(--rf-lift); }
.tool-stage .pt-load-card { margin: 0; background: rgba(247, 244, 236, 0.05); border-color: rgba(247, 244, 236, 0.12); box-shadow: none; }
.tool-stage .pt-load-mine { border-top-color: rgba(247, 244, 236, 0.14); }
.tool-stage .pt-load-status { color: var(--parchment); }
.tool-stage :is(.pt-load-status, .pt-load-signin).is-error { color: #F0A090; }
.tool-stage .pt-check { border-color: rgba(247, 244, 236, 0.22); }
.tool-stage .pt-check:has(input:checked) { border-color: var(--accent); background: rgba(200, 135, 58, 0.18); }
