/*
 * Application styles
 */

/* ── Type scale ─────────────────────────────────────────────────────────────
 * Every font size in the app is one of these (no one-off sizes): */
:root {
  --fs-micro: 0.75rem;  /* 12px — what's written on the cards themselves: power, counters, marks, the mat's labels */
  --fs-small: 0.875rem; /* 14px — labels, hints, secondary text, small buttons */
  --fs-body:  1rem;     /* 16px — text to read: the status bar, the log, panels, fields */
  --fs-large: 1.2rem;   /* an effect's question, titles */
  --fs-xl:    1.5rem;   /* the deck count */
}

/* ── Reset / base ─────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: system-ui, sans-serif;
  background: #0f0f0f;
  color: #e8e8e8;
}

a { color: inherit; text-decoration: none; }

/* Browsers default <button> to a UA font (commonly Arial, not the page's
 * system-ui stack) unless told otherwise — every .btn-primary/secondary/
 * danger applied to a <button> (button_to) rendered at a different font,
 * and therefore a different height, than the identical class applied to
 * an <a> (link_to) sitting right next to it. */
button, input, select, textarea { font: inherit; } /* (fields too: their text, and a submit's) */

/* ── Card grid ────────────────────────────────────────────────────────────── */
/*
 * Responsive grid: cards fill the available width.
 * Each card is at least 130px wide; at wider viewports more fit per row.
 * Breakpoints are implicit via auto-fill — no media queries needed.
 */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 8px;
  padding: 12px 0;
}

/* ── Card thumbnail ───────────────────────────────────────────────────────── */
.card-thumb {
  display: flex;
  flex-direction: column;
  background: #1a1a1a;
  border-radius: 6px;
  overflow: hidden;
  border: 2px solid transparent;
  transition: border-color 0.15s, transform 0.1s;
}

.card-thumb--addable {
  cursor: pointer;
}

.card-thumb--addable:hover {
  border-color: #f0c040;
  transform: translateY(-2px);
}

/* Fixed aspect ratio for the image area — real OPTCG card art is 63:88mm
 * (≈0.716), not the classic US-card 2.25:3.5 (9:14 ≈ 0.643) this used to
 * assume. That mismatch didn't crop anything here directly (this box just
 * displays whatever Card#thumbnail already is), but it must stay in sync
 * with Card::THUMBNAIL_TRANSFORM's own ratio — if the two ever disagree,
 * `object-fit: cover` crops the already-correctly-cropped thumbnail a
 * second time. */
.card-thumb__image-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 63 / 88;
  background: #111;
  overflow: hidden;
}

.card-thumb__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.card-thumb__placeholder {
  width: 100%;
  aspect-ratio: 63 / 88;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #222;
  padding: 8px;
  text-align: center;
  font-size: var(--fs-small);
  color: #888;
}

.card-thumb__name {
  margin: 0;
  padding: 4px 6px;
  font-size: var(--fs-micro);
  line-height: 1.2;
  color: #ccc;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Filter form ──────────────────────────────────────────────────────────── */
.filter-group {
  margin-bottom: 14px;
}

.filter-group label,
.filter-group > label {
  display: block;
  font-size: var(--fs-small);
  color: #aaa;
  margin-bottom: 4px;
}

/* Colors is the one filter that gates whether anything renders at all —
 * called out in the accent color so it doesn't read as just another
 * optional filter next to cost/category. */
.filter-group__required {
  color: #f0c040;
  font-weight: 600;
  text-transform: none;
}

.filter-group input[type="text"],
.filter-group input[type="number"],
.filter-group select {
  width: 100%;
  height: 36px; /* (fields and the select alike) */
  padding: 6px 8px;
  background: #1e1e1e;
  border: 1px solid #333;
  border-radius: 4px;
  color: #e8e8e8;
  font-size: var(--fs-small);
}

.filter-ranges { display: flex; flex-wrap: wrap; column-gap: 12px; grid-column: 1 / -1; }
.filter-group--cost  { flex: 2 1 130px; }
.filter-group--power { flex: 3 1 190px; }
.filter-range { display: flex; align-items: center; gap: 6px; }
.filter-range input { min-width: 0; flex: 1 1 0; }
.filter-range__dash { color: #666; }

.filter-group--checkbox label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-small);
  color: #e8e8e8;
}

/* Single row of compact color-swatch toggles (not text-labeled chips) —
 * the 220px filter sidebar isn't wide enough to fit 6 labeled checkboxes
 * on one line, so color is the label. Name is still exposed to assistive
 * tech via aria-label on the checkbox itself, and to sighted mouse users
 * via the wrapping <label>'s title tooltip. */
.color-swatches {
  display: flex;
  flex-wrap: nowrap;
  gap: 6px;
}

.color-swatch {
  position: relative;
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  cursor: pointer;
}

.color-swatch__input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.color-swatch__fill {
  position: absolute;
  inset: 0;
  border-radius: 4px;
  border: 2px solid transparent;
  transition: border-color 0.15s, transform 0.1s;
  pointer-events: none; /* purely decorative — let clicks fall through to the checkbox beneath it */
}

.color-swatch__input:checked ~ .color-swatch__fill {
  border-color: #f0c040;
  transform: scale(0.82);
}

.color-swatch__input:focus-visible ~ .color-swatch__fill {
  outline: 2px solid #f0c040;
  outline-offset: 2px;
}

.color-swatch--red    .color-swatch__fill { background: #e53e3e; }
.color-swatch--green  .color-swatch__fill { background: #38a169; }
.color-swatch--blue   .color-swatch__fill { background: #3182ce; }
.color-swatch--purple .color-swatch__fill { background: #805ad5; }
.color-swatch--black  .color-swatch__fill { background: #718096; }
.color-swatch--yellow .color-swatch__fill { background: #d69e2e; }

.btn-clear {
  font-size: var(--fs-small);
  color: #888;
  text-decoration: underline;
  cursor: pointer;
  /* (on a <button>: none of the browser's button box) */
  background: none;
  border: none;
  padding: 0;
}

/* Buttons: one box for all three looks, whether a link (link_to), a
 * <button> (button_to) or a submit — so side by side they're the same
 * height and line up. (The match bar and the decision panel size theirs
 * further down.) */
.btn-primary,
.btn-secondary,
.btn-danger,
input[type="submit"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 38px;
  padding: 0 16px;
  border: 1px solid transparent;
  border-radius: 6px;
  font-size: var(--fs-body);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.btn-primary, input[type="submit"] { background: #f0c040; color: #111; }
.btn-primary:hover, input[type="submit"]:hover { background: #f5cd5c; }
.btn-secondary { background: #2a2a2a; color: #e8e8e8; border-color: #444; }
.btn-secondary:hover { background: #333; border-color: #555; }
.btn-danger { background: #742a2a; color: #f3dede; }
.btn-danger:hover { background: #8a3333; }
/* (button_to wraps its button in a form: no box of its own) */
form.button_to { display: contents; }

/* ── Result / pagination ──────────────────────────────────────────────────── */
.result-count {
  font-size: var(--fs-small);
  color: #888;
  margin: 0 0 8px;
}

.pagination {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  font-size: var(--fs-small);
}

.pagination__disabled { color: #555; }
.pagination__info     { color: #888; }

/* ── Empty states ─────────────────────────────────────────────────────────── */
.empty-state {
  color: #666;
  padding: 32px 0;
  text-align: center;
}

/* ── Flash messages ───────────────────────────────────────────────────────── */
.flash {
  padding: 10px 16px;
  font-size: var(--fs-body);
  max-height: 200px;
  overflow: hidden;
  transition: opacity 0.3s, max-height 0.3s, padding 0.3s;
}
/* (going away: fades and folds up, so the page doesn't jump) */
.flash--leaving { opacity: 0; max-height: 0; padding-top: 0; padding-bottom: 0; }
.flash--alert { display: flex; align-items: center; gap: 12px; }
.flash__close { margin-left: auto; background: none; border: none; color: inherit; font-size: 1.4rem; line-height: 1; cursor: pointer; padding: 0 4px; }
.flash--notice { background: #1a3a1a; color: #68d391; }
.flash--alert  { background: #3a1a1a; color: #fc8181; }

/* ── Deck builder — full-height sidebar | drag handle | workspace ─────────
 * The sidebar (filters + hovered card) runs the full screen height, so a
 * deck strip that grows as you build never eats into the card preview.
 * Its width comes from sidebar_resize_controller.js (380px until dragged).
 * The workspace stacks topbar / errors / deck strip / card grid.
 */
.deck-builder {
  display: grid;
  grid-template-columns: var(--db-sidebar-width, 380px) 6px minmax(0, 1fr);
  height: 100vh;
  overflow: hidden;
}
.deck-builder--resizing { cursor: col-resize; user-select: none; }

.db-workspace {
  display: grid;
  grid-template-rows: 52px auto auto minmax(0, 1fr);
  min-width: 0;
  overflow: hidden;
}

/* ── Top bar ──────────────────────────────────────────────────────────────── */
.db-topbar {
  grid-row: 1;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 16px;
  background: #141414;
  border-bottom: 1px solid #2a2a2a;
}

.db-name-input {
  background: transparent;
  border: none;
  border-bottom: 1px solid #444;
  color: #e8e8e8;
  font-size: var(--fs-body);
  font-weight: 600;
  padding: 4px 0;
  /* (gives up room first, so the buttons — Save above all — always fit) */
  flex: 0 1 260px;
  min-width: 100px;
  outline: none;
}

.db-name-input:focus { border-bottom-color: #f0c040; }

.db-count {
  margin-left: auto;
  font-size: var(--fs-xl);
  font-weight: 700;
  color: #f0c040;
  white-space: nowrap;
}

.db-topbar__actions { display: flex; gap: 8px; flex-shrink: 0; }

/* ── Errors bar ───────────────────────────────────────────────────────────── */
/* The builder's messages: over the page, under its top bar — they never
   push the deck and the grid down (nor pull them back up when gone); a
   tap closes one. */
.db-errors {
  position: fixed; top: 60px; left: 50%; transform: translateX(-50%); z-index: 1200;
  width: max-content; max-width: min(560px, calc(100vw - 24px));
  border-radius: 8px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6); cursor: pointer;
  background: #3a1a1a;
  color: #fc8181;
  padding: 8px 16px;
  font-size: var(--fs-small);
  overflow: hidden;
}
.db-errors p { margin: 2px 0; }
.db-errors--notice { background: #1a3a1a; color: #68d391; }
/* A challenge they're building for: it stays, so it's in the page. */
.db-invite { grid-row: 2; margin: 0; padding: 6px 16px; background: #1a3a1a; color: #68d391; font-size: var(--fs-small); }

/* ── Deck display strip (full workspace width) ────────────────────────────
 * A CSS grid, not flex-wrap: every stack (leader included — same size as
 * everything else, see .deck-stack below) sits in a uniform-width column, so
 * column boundaries stay fixed across every row regardless of how many
 * cards you've added. Padding here is the strip's outer edge, kept
 * comfortably wider than the tight 6px gap between stacks themselves.
 *
 * Every stack row is exactly --stack-row tall (124px pile + 3px gap + 14px
 * quantity line, see .deck-stack__images/__qty), so the stack area can be
 * capped at exactly two full rows. Past two rows it scrolls a row at a
 * time. Only the stack area scrolls: the strip's own padding stays put
 * around it, so no scroll position shows part of a row (or its "1×"
 * labels) at either edge. A bare max-height on the strip used to cut the
 * second row's labels off.
 */
.db-deckstrip {
  --stack-row: 141px;
  --stack-gap: 6px;
  grid-row: 3;
  background: #161208;
  border-bottom: 1px solid #2a2a2a;
  padding: 14px 16px;
}

.db-display__inner {
  display: grid;
  grid-template-columns: repeat(auto-fill, 95px);
  grid-auto-rows: var(--stack-row);
  gap: var(--stack-gap);
  align-content: start;
  /* Always two rows tall, even with one row of cards: if it grew when a
     card starts the second row, everything below — the card grid being
     clicked — would jump down under the pointer. Past two rows it scrolls. */
  height: calc(2 * var(--stack-row) + var(--stack-gap));
  overflow-y: auto;
  scroll-snap-type: y mandatory;
}
.db-display__inner > * { scroll-snap-align: start; }

/* Filters on top, the hovered card filling whatever height is left. On a
   short screen the preview keeps a minimum height and the sidebar scrolls
   rather than shrinking the card to nothing. */
.db-sidebar {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow-y: auto;
  padding: 12px;
  background: #131313;
}

.db-sidebar__filters {
  flex: 0 0 auto;
  container-type: inline-size;
}

/* A widened sidebar lays the filters out in two columns, so they take
   less height and the card preview below gets more. */
@container (min-width: 340px) {
  .db-sidebar__filters form {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 12px;
  }
  /* The search box needs the full width; everything else pairs up. */
  .db-sidebar__filters .filter-group:first-child { grid-column: 1 / -1; }
  .db-sidebar__filters .filter-group--checkbox label { white-space: nowrap; }
}

.db-preview {
  flex: 1 1 auto;
  min-height: 240px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 4px;
  border-top: 1px solid #2a2a2a;
  padding-top: 12px;
}

.db-preview__image {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: top center;
  border-radius: 8px;
}

.db-preview__empty {
  margin: 0;
  font-size: var(--fs-small);
  color: #666;
  text-align: center;
}

.db-resize-handle {
  cursor: col-resize;
  background: #131313;
  border-right: 1px solid #2a2a2a;
  touch-action: none;
}
.db-resize-handle:hover,
.db-resize-handle:focus-visible,
.deck-builder--resizing .db-resize-handle { background: #2a2a2a; outline: none; }

.db-sidebar__heading {
  margin: 0 0 8px;
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #888;
}

/* ── Card stacks inside the deck display ──────────────────────────────────── */
/* Leader and every regular stack render at the same size now — the card
 * itself (.deck-stack__img) is 80×112, and everything else here is derived
 * from that one number plus the fan's own reach, so nothing needs a
 * `--leader` size override any more (it keeps the class only for the
 * "Leader" label's text color, below).
 *
 * 80×112 is a 63:88 ratio (≈0.714) — matching Card::THUMBNAIL_TRANSFORM's
 * own real-card-art ratio, same as `.card-thumb__image-wrap` above. Getting
 * this out of sync with the thumbnail's actual ratio is exactly what
 * cropped the card's printed border and pushed its cost/power badges off
 * the edge in an earlier pass here — `object-fit: cover` will silently
 * crop *any* mismatch between a box's ratio and its image's real ratio, so
 * this number must track THUMBNAIL_TRANSFORM's, not the other way around.
 *
 * The fan (#stackHTML in deck_builder_controller.js) offsets each stacked
 * card `i*5px` right and, via FAN_MAX_LIFT there, `12-i*4px` up, so a full
 * 4-card pile's true footprint is 95×124 (80+3×5 wide, 112+12 tall) — not
 * 80×112. `.deck-stack__images` is sized to that true footprint: the back
 * card (i=0) always sits 12px down from the box's own top regardless of
 * pile size, which (a) reserves exactly the fan's max upward reach above it
 * so a full 4× pile's frontmost card lands flush with the box's top instead
 * of overflowing above it, and (b) puts every pile's back card — leader
 * included — on the exact same baseline, since that 12px offset is applied
 * uniformly rather than depending on how many cards are actually in a pile.
 */
.deck-stack {
  position: relative;
  cursor: pointer;
  flex-shrink: 0;
  width: 95px;
}

.deck-stack:hover .deck-stack__img { opacity: 0.85; }

.deck-stack--empty {
  width: 95px;
  opacity: 0.4;
  cursor: default;
}

.deck-stack__images {
  position: relative;
  width: 95px;
  height: 124px;
}

.deck-stack__img {
  position: absolute;
  width: 80px;
  height: 112px;
  border-radius: 4px;
  object-fit: cover;
  border: 1px solid #3a3a3a;
  transition: opacity 0.1s;
  background: #111;
}

.deck-stack__img--blank {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  text-align: center;
  font-size: var(--fs-micro);
  color: #666;
  background: #1e1e1e;
}

.deck-stack__qty {
  display: block;
  text-align: center;
  font-size: var(--fs-micro);
  line-height: 14px; /* fixed — part of --stack-row, see .db-deckstrip */
  font-weight: 700;
  color: #f0c040;
  margin-top: 3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.deck-stack--leader .deck-stack__qty { color: #80d4ff; }

/* ── Card browser (scrollable main area) ──────────────────────────────────── */
.db-main {
  grid-row: 4;
  overflow-y: auto;
  padding: 12px 16px;
}

.db-main turbo-frame { display: block; }

/* ── Decks index ──────────────────────────────────────────────────────────── */
.decks-index {
  padding: 24px;
  max-width: 1280px;
  margin: 0 auto;
}

.decks-index__header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
}
.decks-index__title { display: flex; align-items: baseline; gap: 12px; }
.decks-index__title h1 { margin: 0; }
.decks-index__count { color: #888; font-size: var(--fs-small); }
.decks-index__header-actions { display: flex; gap: 8px; }

.decks-index__tools { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 20px; }
.decks-index__search {
  flex: 1 1 260px;
  max-width: 420px;
  min-height: 38px;
  padding: 0 12px;
  background: #1e1e1e;
  border: 1px solid #333;
  border-radius: 6px;
  color: #e8e8e8;
}
.decks-index__search:focus { outline: 2px solid #f0c040; outline-offset: -1px; }
.decks-index__sort { display: flex; align-items: center; gap: 8px; color: #aaa; font-size: var(--fs-small); }
.decks-index__sort select {
  min-height: 38px;
  padding: 0 10px;
  background: #1e1e1e;
  border: 1px solid #333;
  border-radius: 6px;
  color: #e8e8e8;
}

/* The grid: as many columns of ~240px tiles as fit. */
.deck-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
}
.deck-tile {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #1a1a1a;
  border: 1px solid #2a2a2a;
  border-radius: 10px;
  transition: border-color 0.15s;
}
.deck-tile:hover { border-color: #444; }
.deck-tile[hidden] { display: none; }
/* The Leader's art: the top of the card, where the character is. */
.deck-tile__art { display: block; height: 150px; background: #111; overflow: hidden; }
.deck-tile__art img { width: 100%; height: 100%; object-fit: cover; object-position: center 18%; transition: transform 0.2s; }
.deck-tile__art:hover img { transform: scale(1.03); }
.deck-tile__no-leader { display: flex; height: 100%; align-items: center; justify-content: center; color: #666; font-size: var(--fs-small); }
.deck-tile__body { display: flex; flex-direction: column; gap: 4px; padding: 12px 14px 10px; flex: 1; }
.deck-tile__name { margin: 0; font-size: var(--fs-large); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.deck-tile__leader { display: flex; align-items: center; gap: 4px; margin: 0; color: #bbb; font-size: var(--fs-small); }
.deck-tile__color { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.deck-tile__color--red    { background: #e53e3e; }
.deck-tile__color--green  { background: #38a169; }
.deck-tile__color--blue   { background: #3182ce; }
.deck-tile__color--purple { background: #805ad5; }
.deck-tile__color--black  { background: #718096; }
.deck-tile__color--yellow { background: #d69e2e; }
.deck-tile__leader .deck-tile__color:last-of-type { margin-right: 4px; }
.deck-tile__status { margin: 4px 0 0; font-size: var(--fs-small); }
.deck-tile__status--ready { color: #68d391; }
.deck-tile__status--unfinished { color: #f6ad55; }
.deck-tile__updated { margin: 0; color: #666; font-size: var(--fs-small); }
.deck-tile__actions { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 14px 14px; }
.deck-tile__actions > * { flex: 1 1 0; }
.deck-tile__actions .deck-tile__play { flex: 1 1 100%; }

.decks-index__empty { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 64px 0; color: #888; }

/* ── Forms (Devise etc.) ──────────────────────────────────────────────────── */
input[type="email"],
input[type="password"],
input[type="text"]:not(.db-name-input):not(.db-search-input) {
  display: block;
  width: 100%;
  padding: 8px;
  background: #1e1e1e;
  border: 1px solid #333;
  border-radius: 4px;
  color: #e8e8e8;
  font-size: var(--fs-body);
  margin-bottom: 12px;
}



/* ── Match board (T10 — counter-window moment) ───────────────────────────────
 * Palette reused as-is from the rest of the app (Design review Pass 5):
 * background #1a1a1a, gold accent #f0c040, red #e53e3e. Contrast verified
 * during implementation (Design review Pass 6): #f0c040 on #1a1a1a clears
 * 4.5:1 easily; #e53e3e on #1a1a1a measures ~4.2:1 — comfortably over the
 * 3:1 minimum for large/bold text and borders, so red is only ever used
 * that way below (attack banner, glows), never for small body text.
 */

.match-waiting,
.match-join {
  max-width: 480px;
  margin: 48px auto;
  padding: 0 16px;
  text-align: center;
}

.match-waiting__link { display: flex; gap: 8px; align-items: stretch; }
/* (field and button the same height, side by side: the app's text fields
   carry a margin below them, which here made the button taller) */
.match-waiting__link input {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  box-sizing: border-box;
  height: 40px;
  text-align: center;
  font-size: var(--fs-small);
}
.match-waiting__link .btn-primary { flex: none; min-width: 110px; height: 40px; min-height: 0; padding-top: 0; padding-bottom: 0; }

.match-waiting__hint {
  color: #888;
  font-size: var(--fs-small);
}

.match-join__form {
  text-align: left;
}

/* Match and replay pages: the enlarged card in its own column on the left
   (same side as the deck builder's), the board on the right. The panel
   sticks to the viewport so the card stays in view while scrolling. */
.match-layout {
  display: grid;
  /* The board is only as wide as the table needs, so the pair is centred
     rather than the board floating in a wide column. */
  --side-w: clamp(300px, 24vw, 480px);
  grid-template-columns: var(--side-w) minmax(0, max-content);
  justify-content: center;
  gap: 16px;
  margin: 0 auto;
  padding: 0 16px;
  align-items: start;
}

/* The column beside the board: the enlarged card at a fixed size on top,
   and the opened trash filling what's left below it. */
.match-preview {
  position: sticky;
  top: 12px;
  height: calc(100vh - 24px);
  display: flex;
  flex-direction: column;
  gap: 12px;
  overflow-y: auto; /* only on short windows with a big hand */
}

.match-preview__panel,
.hand-panel,
.trash-panel {
  padding: 12px;
  background: #131313;
  border: 1px solid #2a2a2a;
  border-radius: 8px;
}

/* The enlarged card takes whatever height the hands leave; an opened
   trash floats over it rather than taking room from it. */
.match-preview__stage {
  position: relative;
  flex: 1 1 0;
  min-height: 160px;
  display: flex;
}
.match-preview__panel {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
}

/* The effect being resolved, where the enlarged card goes (the side
   column has the room the bar below the table doesn't): its card, the
   question in full, the card's text, and "Choose one" options as wide
   buttons. A hovered card covers it (the preview has a background then);
   once the pointer leaves, it's back. */
.question-panel {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px;
  background: #131313;
  border: 1px solid #f0c040;
  border-radius: 8px;
}
.question-panel:empty { display: none; }
.question-panel--waiting { border-color: #2a2a2a; }
.match-preview__panel { position: relative; z-index: 2; }
.question-panel:not(:empty) ~ .match-preview__panel:not(:has(img)) { visibility: hidden; } /* (no "Hover a card" over it) */
.match-preview__panel:has(img) { background: #131313; }
.question-panel__body { display: flex; flex-direction: column; gap: 10px; }
.question-panel__source { margin: 0; font-size: var(--fs-small); color: #aaa; text-transform: uppercase; letter-spacing: 0.06em; }
.question-panel__prompt { margin: 0; font-size: var(--fs-large); line-height: 1.4; color: #e8e8e8; font-weight: 600; text-wrap: pretty; }
.question-panel__text { margin: 0; padding-top: 10px; border-top: 1px solid #2a2a2a; font-size: var(--fs-body); line-height: 1.5; color: #aaa; }
.question-panel__options { display: flex; flex-direction: column; gap: 8px; }
.question-panel__options .btn-secondary { justify-content: flex-start; text-align: left; white-space: normal; min-height: 44px; padding: 8px 12px; line-height: 1.35; }

/* The hand, in the column: its own card size, as the column is outside
   .match-board (where the table's sizes are set). */
.hand-panel {
  flex: none;
  --hand-h: min(130px, 12vh);
  --hand-w: calc(var(--hand-h) * 0.716);
}
.hand-panel .match-board__hand-header { margin-bottom: 6px; }
.hand-panel:empty { visibility: hidden; } /* before the first render; still "shown" for sidePanel */

/* A face-down card in the opponent's hand: the size of one of yours. */
.hand-card--back .card-back { display: block; width: var(--hand-w); height: var(--hand-h); }

.trash-panel {
  position: absolute;
  z-index: 5;
  bottom: 8px; left: 8px; right: 8px; /* at the bottom: the card's cost and power stay in view */
  max-height: calc(100% - 16px);
  overflow-y: auto;
  background: rgba(19, 19, 19, 0.96);
  border-color: #3a3a3a;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.7);
}
.trash-panel:empty { display: none; }
/* Hovering a card in the trash shows it in the preview, fitted into the
   room above the trash (--trash-h is set by lib/side_column.js). */
.match-preview__stage:has(.trash-panel__card:hover) .match-preview__panel {
  padding-bottom: calc(var(--trash-h, 0px) + 20px);
}
.trash-panel__cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
  gap: 6px;
}
.trash-panel__card { width: 100%; height: auto; aspect-ratio: 63 / 88; }
.trash-panel__empty { margin: 0; font-size: var(--fs-small); color: #666; text-align: center; }

.trash-pile { cursor: pointer; border-radius: 6px; }
.trash-pile:hover .card-face,
.trash-pile:hover .card-slot-empty,
.trash-pile:focus-visible .card-face,
.trash-pile:focus-visible .card-slot-empty { outline: 2px solid #f0c040; outline-offset: 2px; }

/* Too narrow for a side column: hide it, and the preview falls back to
   its overlay (card_preview_controller checks the panel's display). */
@media (max-width: 1100px) {
  .match-layout { grid-template-columns: minmax(0, 1fr); }
  .match-preview { display: none; }
  .match-preview__panel { display: none; }
  .trash-panel { display: none; }
  .hand-panel { display: none; }
}

.match-board {
  margin: 0 auto;
  padding: 6px 0 0;
}

.match-board__loading,
.match-board__error {
  text-align: center;
  color: #888;
  padding: 48px 0;
}

/* The one bar below the table: the status, then the decision at hand
   (End Turn, attach DON!!, block, ...) or the result, then the links.
   It wraps only for the rare long decision (several blockers). */
.match-board__status {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
  font-size: var(--fs-small);
  letter-spacing: 0.02em;
  color: #e8e8e8;
  background: #1a1a1a;
  border: 1px solid #333;
  border-radius: 6px;
  padding: 4px 10px;
  margin-top: 6px; /* (below the table) */
}
/* The status gives way first (the hint is cut short) so the decision and
   the links stay on the same line. */
.match-board__status-text { flex: 1 1 0; min-width: 180px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* ... except a card effect's question to this player: that's the decision
   itself (what's K.O.'d, what it costs), so it wraps — up to 2 lines, the
   height of the buttons beside it, so the table below doesn't shrink (the
   rest, rarely, on hover). */
.match-board__status--asking .match-board__status-text {
  min-width: 260px;
  white-space: normal;
  line-height: 1.25;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}
.match-board__status-actions { display: flex; gap: 10px; align-items: center; }
.match-board__hint { color: #999; font-size: var(--fs-small); }
/* Back to My Decks, at the far left of the status bar. */
.match-board__back {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px;
  border-radius: 6px;
  color: #ccc; text-decoration: none; font-size: var(--fs-large);
  border: 1px solid #333;
}
.match-board__back:hover, .match-board__back:focus-visible { color: #fff; border-color: #666; background: #262626; }

.match-board__end-turn { flex: none; min-height: 28px; padding: 3px 14px; font-size: var(--fs-small); }
.match-board__status .match-board__controls { padding-top: 0; gap: 6px 8px; }
.match-board__status .filter-select { max-width: 140px; }
.match-board__status .db-cost-input { width: 3.5em; }
.match-board__status .match-board__result { margin: 0; padding: 2px 10px; font-size: var(--fs-body); }

/* Positioned parent for the Phaser overlay (dim/arrow/counter ring) — the
 * arena is exactly what gets visually dimmed during an attack; the status
 * bar below (persistent chrome) is a sibling and is never touched. */
.match-board__arena {
  position: relative;
}

.match-board__overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 5;
}

.match-board__overlay canvas {
  width: 100%;
  height: 100%;
}

.match-board__zone {
  position: relative;
  z-index: 1; /* sits above the dim overlay — opaque card backgrounds read as "not dimmed" */
  background: #141414;
  border: 1px solid #2a2a2a;
  border-radius: 8px;
  padding: 4px 8px 6px;
  margin-bottom: 4px;
}

.match-board__zone-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  font-size: var(--fs-small);
  color: #aaa;
  margin-bottom: 3px;
  min-height: 18px;
}

.don-track {
  display: inline-flex;
  gap: 3px;
}

/* Text only for screen readers (the board shows card images). */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ── Cards on the board — real OPTCG proportions (63×88mm ≈ 0.716) ─────── */
/* Card sizes follow the window, as big as it allows, so both halves of
   the table and the status bar always fit without scrolling (both hands
   are in the column beside it):
   - height: measured, the table is about 6 card heights (two card rows
     and a DON!! row per player) plus ~196px of fixed chrome (status bar,
     zone headers, labels) — 206px leaves a little slack;
   - width: the table (see `width` below) must fit beside that column. */
.match-board {
  --card-h: max(48px, min(calc((100vh - 214px) / 6),
                          calc((100vw - var(--side-w, 0px) - 48px - 140px) / 6.45)));
  --card-w: calc(var(--card-h) * 0.716);
  --hand-h: calc(var(--card-h) * 0.9);
  --hand-w: calc(var(--hand-h) * 0.716);
  --don-h:  calc(var(--card-h) * 0.72);
  --don-w:  calc(var(--don-h) * 0.716);
  /* As wide as the fullest mat needs: the cost area with all 10 DON!!
     turned sideways (as wide as 5 Characters) between the two pile
     columns, plus the zone's padding. Never so narrow that the status bar
     (status, decision, links) can't keep to one line, though. */
  width: max(860px, calc(var(--card-h) * 5 + var(--card-w) * 2 + 140px));
  max-width: 100%;
}
/* The replay keeps its scrubber below the table. */
.match-board[data-controller~="replay-board"] {
  --card-h: max(48px, min(calc((100vh - 266px) / 6),
                          calc((100vw - var(--side-w, 0px) - 48px - 140px) / 6.45)));
}
/* Narrow screens: no column beside the board, so the hand is back below
   the table and the cards are smaller. */
@media (max-width: 1100px) {
  .match-layout .match-board { --card-h: max(48px, min(calc((100vh - 270px) / 7.4), calc((100vw - 32px - 140px) / 6.45))); }
}

.card-face {
  display: block;
  width: var(--card-w);
  height: var(--card-h);
  border-radius: 6px;
  overflow: hidden;
  background: #111;
  transition: transform 0.2s;
}
.card-face__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.card-face__text {
  display: flex; align-items: center; justify-content: center; height: 100%;
  padding: 6px; text-align: center; font-size: var(--fs-micro); font-weight: 600; color: #ddd;
  border: 1px solid #333; border-radius: 6px;
}

/* The official back of a deck card (the navy one; Leaders are red, DON!!
   white), from Bandai's rule manual. */
.card-back {
  width: var(--card-w);
  height: var(--card-h);
  border-radius: 6px;
  background: url("/assets/card_back-b4fc156b.webp") center / 100% 100% no-repeat;
}
/* The opponent's hand, face down in their zone header, fanned. */
.card-back--hand { height: calc(var(--card-h) * 0.38); width: calc(var(--card-h) * 0.38 * 0.716); border-radius: 3px; flex: none; }
.card-back--hand + .card-back--hand { margin-left: calc(var(--card-h) * 0.38 * 0.716 * -0.45); }
.card-slot-empty {
  width: var(--card-w); height: var(--card-h);
  border: 1px dashed #333; border-radius: 6px;
}

/* ── The playmat — laid out like the official One Piece mat ─────────────
 * Your half, from the table's edge up: DON!! deck · cost area · trash;
 * Leader · Stage · Deck; the Character area (5 slots), with
 * Life in a tall column on the left. The opponent's half is the same mat
 * turned 180°, so both Character areas meet in the middle of the table. */
.playmat {
  display: grid;
  grid-template-columns: calc(var(--card-w) + 16px) repeat(2, minmax(0, 1fr)) calc(var(--card-w) + 16px);
  gap: 4px;
  grid-template-areas:
    "life    chars  chars  chars"
    "life    leader stage  deck"
    "dondeck cost   cost   trash";
}
.match-board__zone--opponent .playmat {
  grid-template-areas:
    "trash cost  cost   dondeck"
    "deck  stage leader life"
    "chars chars chars  life";
}

.mat-area {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: calc(var(--card-h) + 8px);
  padding: 4px;
  background: #1a1a1a;
  border: 1px solid #262626;
  border-radius: 8px;
}
.mat-area__label {
  position: absolute;
  top: 3px; left: 8px;
  z-index: 1;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #555;
  pointer-events: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: calc(100% - 16px);
}
/* The narrow pile areas only name themselves while empty — over a card
   the label just clutters it. */
.mat-area--trash:has(.card-face) .mat-area__label,
.mat-area--deck:has(.card-back) .mat-area__label,
.mat-area--life:has(.card-back) .mat-area__label,
.mat-area--dondeck:has(.don-card) .mat-area__label { display: none; }
.mat-area--cost { min-height: 0; }

.card-slot-empty--character { width: var(--card-w); height: var(--card-h); margin: 0 calc((var(--card-h) - var(--card-w)) / 2); }

/* Life: the top card whole, the rest peeking out beneath it. */
/* Life: whole cards stacked one on top of the other, each peeking out a
   little below the one before, like the pile on the table. */
.life-stack { position: relative; display: flex; flex-direction: column; align-items: center; }
.card-back--life { flex: none; box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.6); }
.card-back--life + .card-back--life { margin-top: calc(var(--card-h) * -0.8); }

/* DON!! cards: the official front (from Bandai's rule manual), standing
   when active, sideways and dimmed once rested. */
/* Each DON!! sits in a slot as wide as it shows (sideways when rested).
   With room to spare the slots are 6px apart; with less they overlap just
   enough to fit the row (--active / --rested are set by zoneHTML). */
.cost-area { container-type: inline-size; display: flex; align-items: center; width: 100%; min-height: var(--don-h); }
.don-slot { flex: none; width: var(--don-w); height: var(--don-h); display: flex; align-items: center; justify-content: center; }
.don-slot--rested { width: var(--don-h); }
.don-slot + .don-slot {
  margin-left: clamp(calc(var(--don-w) * -0.85),
                     calc((100cqw - var(--active) * var(--don-w) - var(--rested) * var(--don-h)) / (var(--active) + var(--rested) - 1)),
                     6px);
}
.don-card {
  width: var(--don-w); height: var(--don-h);
  display: flex; align-items: center; justify-content: center;
  border-radius: 4px;
  background: url("/assets/don_card-4d4d74d7.webp") center / 100% 100% no-repeat;
  transition: transform 0.2s, filter 0.2s;
}
.don-card { flex: none; box-shadow: -1px 0 3px rgba(0, 0, 0, 0.5); }
.don-card--rested { transform: rotate(90deg); filter: brightness(0.55); }
.don-card--back { background-image: url("/assets/don_card_back-39251f13.webp"); }
.card-slot-empty--don { width: var(--don-w); height: var(--don-h); }

/* DON!! given to a Leader/Character: real DON!! cards tucked under it,
   fanned out to its right (the slot is wider than the card), each a
   little further out — with a count chip on top. */
.combatant__don { position: absolute; inset: 0; pointer-events: none; }
.combatant .card-face { position: relative; z-index: 1; }
.combatant__power { z-index: 2; }
.don-card--given {
  position: absolute; z-index: 0;
  width: var(--card-w); height: var(--card-h);
  left: 50%; top: 50%;
  transform: translate(calc(-50% + (var(--card-h) - var(--card-w)) * 0.3 + var(--i) * 5px), calc(-50% + var(--i) * 2px));
  box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.7);
}
.combatant__don-count {
  position: absolute; z-index: 2; right: 0; bottom: 18%;
  min-width: 20px; padding: 1px 5px; border-radius: 10px;
  background: #1a1a1a; border: 1px solid #f0c040; color: #f0c040;
  font-size: var(--fs-micro); font-weight: 700; text-align: center;
}

/* Dragging a DON!! from the cost area onto one of your cards. */
.don-card--draggable { cursor: grab; touch-action: none; }
.don-card--draggable:hover, .don-card--draggable:focus-visible { outline: 2px solid #f0c040; outline-offset: 1px; }
.don-card--picked { outline: 2px solid #f0c040; box-shadow: 0 0 10px rgba(240, 192, 64, 0.9); }
/* The order picked, when it matters ("place them back in any order"). */
.trash-panel__card { position: relative; }
.pick-order {
  position: absolute; top: 4px; left: 4px; z-index: 2;
  min-width: 1.4em; padding: 1px 5px; border-radius: 999px;
  background: #81e6d9; color: #1a202c; font-weight: 700; font-size: var(--fs-small); text-align: center;
}

/* An effect's choice can pick DON!! too (same colours as a chosen card). */
.don-card--choosable { cursor: pointer; outline: 2px solid #38b2ac; box-shadow: 0 0 10px rgba(56, 178, 172, 0.7); }
.don-card--chosen    { cursor: pointer; outline: 2px solid #81e6d9; box-shadow: 0 0 12px rgba(129, 230, 217, 0.9); }
.don-card--ghost {
  position: fixed; z-index: 1000; pointer-events: none;
  transform: translate(-50%, -50%) rotate(-6deg) scale(1.15);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.6);
}
/* Dragging several picked DON!!: how many go. */
.don-card--ghost[data-count]::after {
  content: attr(data-count);
  position: absolute; right: -8px; bottom: -8px;
  padding: 1px 6px; border-radius: 10px;
  background: #1a1a1a; border: 1px solid #f0c040; color: #f0c040;
  font-size: var(--fs-micro); font-weight: 700;
}
.match-board--don-dragging { cursor: grabbing; }
.match-board--don-dragging [data-don-target],
.combatant--don-target { border-color: #f0c040; box-shadow: 0 0 10px rgba(240, 192, 64, 0.5); cursor: pointer; }
.combatant--don-hover { border-color: #fff; box-shadow: 0 0 16px rgba(240, 192, 64, 1); }

.pile__card { position: relative; }
.pile__count {
  position: absolute; right: 4px; bottom: 4px;
  background: rgba(0, 0, 0, 0.8); color: #f0c040;
  font-size: var(--fs-micro); font-weight: 700; border-radius: 4px; padding: 0 5px;
}

.hand-backs { display: flex; }

/* The Character area: its 5 places always in one row (on a phone, a
   Character takes the table's card size, not the Leader's minimum — see
   the 480px rules). */
.match-board__combatants {
  display: flex;
  flex-wrap: nowrap;
  gap: 6px;
  align-items: center;
  justify-content: center;
}

.combatant {
  position: relative;
  /* Room for the card turned sideways when rested. */
  width: var(--card-h);
  height: var(--card-h);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid transparent;
  border-radius: 8px;
  transition: border-color 0.2s, box-shadow 0.2s;
}

.combatant__label { font-size: var(--fs-micro); color: #888; text-transform: uppercase; }
.combatant__name  { font-size: var(--fs-body); font-weight: 600; }

/* Current power (with DON!! and counters) — not on the printed card. */
.combatant__power {
  position: absolute;
  left: 50%; bottom: 2px;
  transform: translateX(-50%);
  background: rgba(0, 0, 0, 0.82);
  color: #f0c040;
  font-size: var(--fs-micro); font-weight: 700;
  border-radius: 4px; padding: 1px 6px;
  white-space: nowrap;
}

/* Each change to its power, on top of the card (powerChangesHTML): the
   amount (green up, red down) and how long it lasts, in words — the tag's
   tint only backs the word up. */
.combatant__changes {
  position: absolute; z-index: 3;
  left: 50%; top: 2px;
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  pointer-events: none;
}
.combatant:has(.combatant__negated) .combatant__changes { top: 22px; } /* (under the "Negated" badge) */
.power-change {
  display: inline-flex; align-items: baseline; gap: 4px;
  padding: 1px 5px; border-radius: 4px;
  background: rgba(0, 0, 0, 0.85);
  font-size: var(--fs-micro); line-height: 1.2; white-space: nowrap;
  pointer-events: auto; cursor: help;
}
.power-change__amount { font-weight: 700; font-variant-numeric: tabular-nums; }
.power-change__amount--up   { color: #68d391; }
.power-change__amount--down { color: #fc8181; }
.power-change__amount--set  { color: #e8e8e8; }
/* (cost: its own color — a higher cost is neither good nor bad) */
.power-change--cost .power-change__amount,
.power-change--cost-total .power-change__amount { color: #f0c040; }
.power-change--cost-total { border: 1px solid #f0c040; }
.power-change__tag { font-size: var(--fs-micro); color: #ccc; }
.power-change--battle .power-change__tag,
.power-change--counter .power-change__tag { color: #fca5a5; }
.power-change--turn .power-change__tag    { color: #f0c040; }
.power-change--until .power-change__tag   { color: #93c5fd; }
.power-change--always .power-change__tag  { color: #81e6d9; }
.power-change--don .power-change__tag     { color: #f0c040; }

/* Its restrictions and protections (statusMarksHTML), at the bottom of the
   card above its power: what (and how long), in words. Restrictions read
   in the danger color, protections in teal. */
.combatant__marks {
  position: absolute; z-index: 3;
  left: 50%; bottom: 22px;
  transform: translateX(-50%);
  display: flex; flex-direction: column-reverse; align-items: center; gap: 2px;
  pointer-events: none;
}
.status-mark {
  display: inline-flex; align-items: baseline; gap: 4px;
  padding: 1px 5px; border-radius: 4px;
  background: rgba(0, 0, 0, 0.85); border: 1px solid #fc8181;
  color: #fc8181; font-size: var(--fs-micro); font-weight: 700; line-height: 1.2; white-space: nowrap;
  pointer-events: auto; cursor: help;
}
.status-mark--frozen, .status-mark--no_refresh { border-color: #93c5fd; color: #93c5fd; }
.status-mark[class*="status-mark--cannot_be_"], .status-mark--can_attack_active { border-color: #81e6d9; color: #81e6d9; }
.status-mark__when { font-weight: 400; color: #ccc; font-size: var(--fs-micro); }

/* "Negate the effect of ...": the printed text doesn't apply for now. */
.combatant__negated {
  position: absolute; z-index: 2;
  left: 50%; top: 2px;
  transform: translateX(-50%);
  background: rgba(0, 0, 0, 0.82);
  color: #e07070;
  font-size: var(--fs-micro); font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  border-radius: 4px; padding: 1px 6px;
  white-space: nowrap;
}

/* Rested: turned sideways, like on the table. */
.combatant--rested .card-face { transform: rotate(90deg); filter: brightness(0.8); }


/* ⚡ — a card of yours with an [Activate: Main] ability usable now. */
.stage-card { position: relative; }
.card-activate {
  position: absolute; top: 2px; right: 2px; z-index: 2;
  width: 24px; height: 24px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-small); line-height: 1;
  color: #1a1a1a; background: #f0c040;
  border: 1px solid #1a1a1a; border-radius: 50%;
  box-shadow: 0 0 8px rgba(240, 192, 64, 0.8);
  cursor: pointer;
}
.card-activate:hover, .card-activate:focus-visible { background: #ffd966; outline: 2px solid #fff; }
.card-face--selected { outline: 2px solid #f0c040; }
/* An ability or an effect's option: the whole text, to read before
   choosing — wrapped, from the left. (A button is an inline flexbox, where
   an ellipsis doesn't apply: cut to one line, its centred text showed only
   its middle.) */
.match-board__activate,
.match-board__option {
  flex: 1 1 100%; justify-content: flex-start; text-align: left;
  white-space: normal; overflow-wrap: anywhere; line-height: 1.35;
  height: auto; padding-top: 8px; padding-bottom: 8px;
}

/* Attacking, step by step: a ready attacker glows gold; the picked one is
   solid gold; valid targets glow red. */
.combatant--selectable,
.combatant--targetable,
.combatant--selected { cursor: pointer; }
.combatant--selectable { border-color: #f0c040; box-shadow: 0 0 10px rgba(240, 192, 64, 0.6); }
.combatant--selected   { border-color: #f0c040; background: rgba(240, 192, 64, 0.15); }
.combatant--targetable { border-color: #e53e3e; box-shadow: 0 0 8px rgba(229, 62, 62, 0.6); }
/* Would be K.O.'d / removed unless its owner uses a replacement effect. */
.combatant--at-stake   { border-color: #e53e3e; box-shadow: 0 0 8px rgba(229, 62, 62, 0.6); }
.combatant--selectable:focus-visible,
.combatant--targetable:focus-visible { outline: 2px solid #fff3c4; outline-offset: 2px; }



/* Card effects: cards a Choice lets you pick glow teal, picked ones are
   solid; the card whose effect is resolving pulses gold. */
.combatant--choosable,
.combatant--chosen,
.card-face--choosable,
.card-face--chosen { cursor: pointer; }
.combatant--choosable { border-color: #38b2ac; box-shadow: 0 0 10px rgba(56, 178, 172, 0.7); }
.combatant--chosen    { border-color: #81e6d9; background: rgba(56, 178, 172, 0.25); box-shadow: 0 0 12px rgba(129, 230, 217, 0.9); }
.card-face--choosable { box-shadow: 0 0 0 2px #38b2ac, 0 0 10px rgba(56, 178, 172, 0.7); }
.card-face--dim       { filter: brightness(0.45); }
.card-face--chosen    { box-shadow: 0 0 0 3px #81e6d9, 0 0 12px rgba(129, 230, 217, 0.9); }
.hand-card--choosable { cursor: pointer; }
.hand-card--chosen    { cursor: pointer; }
.hand-card--choosable .card-face { box-shadow: 0 0 0 2px #38b2ac, 0 0 8px rgba(56, 178, 172, 0.7); }
.hand-card--chosen .card-face    { box-shadow: 0 0 0 3px #81e6d9, 0 0 12px rgba(129, 230, 217, 0.9); transform: translateY(-6px); }
.combatant--resolving { animation: effect-resolving 1.2s ease-in-out infinite; }
@keyframes effect-resolving {
  0%, 100% { box-shadow: 0 0 6px rgba(240, 192, 64, 0.5); }
  50%      { box-shadow: 0 0 16px rgba(240, 192, 64, 0.95); }
}
.match-board__pick-count { color: #81e6d9; font-size: var(--fs-small); font-variant-numeric: tabular-nums; }


.combatant--attacking {
  border-color: #e53e3e;
  box-shadow: 0 0 10px rgba(229, 62, 62, 0.6);
}

.combatant--waiting {
  animation: match-board-pulse 1.2s ease-in-out infinite;
}

@keyframes match-board-pulse {
  0%, 100% { border-color: #e53e3e; }
  50%      { border-color: #f0a0a0; }
}

/* In the middle of your zone's header, between the two halves. */
.match-board__attack-banner {
  position: relative;
  z-index: 1;
  text-align: center;
  font-weight: 700;
  font-size: var(--fs-small);
  color: #e53e3e;
  white-space: nowrap;
}

/* Below the table: the hand, only on narrow screens (otherwise it's in the
   column beside the board), or the replay's scrubber. */
.match-board__dock {
  position: relative;
  z-index: 1;
  display: flex;
  gap: 16px;
  align-items: flex-start;
}
.match-board__dock-side { flex: 1 1 auto; }

.match-board__hand {
  position: relative;
  z-index: 1;
  flex: 1 1 0;
  min-width: 0;
}

.match-board__hand-header {
  font-size: var(--fs-small);
  color: #aaa;
  margin-bottom: 3px;
}

/* The hand is always one row — a second row would push the table off the
   screen. With room to spare the cards sit 6px apart; with less, they
   overlap just enough to fit (up to 90% of a card), like a hand held in
   fan, and the one under the pointer comes to the front. `--n` is the
   number of cards (set by handHTML); 100cqw is the row's width. */
.match-board__hand-cards {
  container-type: inline-size;
  display: flex;
  flex-wrap: nowrap;
  padding-top: 4px; /* room for the hover lift */
}
.match-board__hand-cards > .hand-card + .hand-card {
  margin-left: clamp(calc(var(--hand-w) * -0.9),
                     calc((100cqw - var(--n) * (var(--hand-w) + 4px)) / (var(--n) - 1)),
                     6px);
}
/* Only the hovered card's picture comes to the front — not its button,
   which stays where it is under the next card. The raised picture lets
   the pointer through, so each card is still hovered by its own visible
   strip, and moving onto the next card's strip moves the highlight. */
.match-board__hand-cards > .hand-card { position: relative; }
.match-board__hand-cards > .hand-card .card-face { position: relative; }
.match-board__hand-cards > .hand-card:hover .card-face,
.match-board__hand-cards > .hand-card:focus-visible .card-face { z-index: 2; pointer-events: none; }

.hand-card {
  padding: 0;
  background: none;
  border: 2px solid transparent;
  border-radius: 8px;
  color: #e8e8e8;
  font-family: inherit;
  cursor: default;
  transition: border-color 0.3s, box-shadow 0.3s, opacity 0.3s, transform 0.15s;
}
.hand-card .card-face { width: var(--hand-w); height: var(--hand-h); }

/* Cards you can't use right now are dimmed; usable ones stay bright. */
/* Unusable cards look like any other (no dimming — they overlap, and a
   see-through or darkened hand reads badly); usable ones glow instead. */
.hand-card--playable:hover .card-face, .hand-card--counterable:hover .card-face { transform: translateY(-4px); }

.hand-card__name {
  font-size: var(--fs-small);
  font-weight: 600;
}

.hand-card__tag {
  font-size: var(--fs-micro);
  color: #888;
}

.hand-card__counter {
  font-size: var(--fs-micro);
  color: #f0c040;
}

/* The glows are on the picture, not the button, so they come to the
   front with it. */
.hand-card:focus-visible .card-face { box-shadow: 0 0 0 2px #fff; }
.hand-card--counterable { cursor: pointer; }
/* (a card the defender can counter with: its own edge glows gold, pulsing) */
.hand-card--counterable .card-face { box-shadow: 0 0 0 2px #f0c040, 0 0 8px rgba(240, 192, 64, 0.7); animation: counter-glow 1.4s ease-in-out infinite; }
@keyframes counter-glow { 50% { box-shadow: 0 0 0 3px #ffd966, 0 0 16px rgba(240, 192, 64, 0.95); } }
@media (prefers-reduced-motion: reduce) { .hand-card--counterable .card-face { animation: none; } }
.hand-card--counterable:hover .card-face,
.hand-card--counterable:focus-visible .card-face { box-shadow: 0 0 0 2px #fff3c4, 0 0 0 4px #f0c040; }

.hand-card__cost {
  font-size: var(--fs-micro);
  color: #90cdf4;
}

/* Clicked once to play: raised and ringed, waiting for Play (or a second click). */
.match-board__hand-cards > .hand-card--selected .card-face,
.hand-card--selected .card-face { transform: translateY(-10px); box-shadow: 0 0 0 3px #f0c040, 0 0 14px rgba(240, 192, 64, 0.8); z-index: 2; }
.play-sheet__actions { display: flex; gap: 10px; margin-top: 10px; }
.play-sheet__actions > * { flex: 1; min-height: 46px; }
.hand-card--playable { cursor: pointer; }
.hand-card--playable .card-face { box-shadow: 0 0 0 2px #3182ce; }
.hand-card--playable:hover .card-face,
.hand-card--playable:focus-visible .card-face { box-shadow: 0 0 0 2px #90cdf4, 0 0 0 4px #3182ce; }
.hand-card:focus-visible { outline: none; }

.hand-card--fading .card-face { box-shadow: 0 0 0 2px #333; }
.hand-card--fading { opacity: 0.7; }

.match-board__result {
  position: relative;
  z-index: 1;
  padding: 12px 16px;
  margin: 8px 0;
  border-radius: 6px;
  font-size: var(--fs-body);
}
.match-board__result--won  { background: #1a3a1a; color: #68d391; }
.match-board__result--lost { background: #3a1a1a; color: #fc8181; }


.match-board__controls {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding-top: 4px;
}

.match-board__controls .btn-primary,
.match-board__controls .btn-secondary {
  min-height: 44px; /* Design review Pass 6 — mobile touch target floor */
}
/* With a mouse, the touch floor isn't needed — and low buttons keep the
   status bar one line. */
@media (pointer: fine) {
  .match-board__controls .btn-primary,
  .match-board__controls .btn-secondary { min-height: 28px; padding: 3px 12px; font-size: var(--fs-small); }
}

/* A move on its way to the server (sendCommand): the board says so at
   once — the pointer waits, what was clicked dims and pulses, the bar's
   buttons can't be pressed again. */
.match-board--waiting, .match-board--waiting * { cursor: progress !important; }
.match-board--waiting .match-board__status button,
.match-board--waiting .match-board__status .btn-clear { pointer-events: none; opacity: 0.6; }
.is-pending { animation: move-pending 0.8s ease-in-out infinite; }
@keyframes move-pending { 50% { opacity: 0.45; } }
@media (prefers-reduced-motion: reduce) { .is-pending { animation: none; opacity: 0.6; } }

/* An effect's cards with a trash opened below them: a line between. */
.choice-cards:not(:only-child) { padding-bottom: 8px; margin-bottom: 8px; border-bottom: 1px solid #333; }

/* The connection dropped: said at the top of the board, moves held. */
/* No side column (a phone, a narrow window): the table is taller than the
   screen, so the bar with the decision at hand (End Turn, Play, Done
   countering, which Character leaves) stays at the bottom of the screen
   instead of below the table, out of sight. Messages show above it. */
@media (max-width: 1100px) {
  .match-board__status { position: sticky; bottom: 0; z-index: 30; box-shadow: 0 -6px 16px rgba(0, 0, 0, 0.6); }
  .match-board__toast { bottom: auto; top: 12px; z-index: 1100; }
}

/* [Activate: Main]'s ⚡ on a touch screen: big enough for a finger, and
   its tap area bigger still. */
@media (hover: none) {
  /* (a tap leaves :hover stuck on the card: the card in front takes the
     tap where it shows, not the one under it) */
  .match-board__hand-cards > .hand-card:hover .card-face { pointer-events: auto; }
  .card-activate { width: 34px; height: 34px; top: -8px; right: -8px; font-size: 1rem; }
  .card-activate::after { content: ""; position: absolute; inset: -8px; border-radius: 50%; }
}

.connection-banner {
  position: fixed; top: 10px; left: 50%; transform: translateX(-50%); z-index: 1100; /* (over the table: it takes no room) */
  padding: 6px 16px; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.6);
  background: #3a1a1a; border: 1px solid #e53e3e; border-radius: 6px;
  color: #fc8181; font-weight: 700; text-align: center;
}
.match-board--offline .match-board__status button { pointer-events: none; opacity: 0.5; }

/* The chess clock, in each zone's header: the one running stands out;
   extra time is red. */
.match-clock {
  margin-left: auto; margin-right: 12px; padding: 1px 8px; border-radius: 4px;
  font-variant-numeric: tabular-nums; font-weight: 700; font-size: var(--fs-small);
  color: #888; border: 1px solid #333;
}
.match-clock--running { color: #f0c040; border-color: #f0c040; }
.match-clock--extra { color: #fc8181; border-color: #e53e3e; }
.match-clock--extra.match-clock--running { background: #3a1a1a; }

/* Whether the opponent's page is open: a word, with a dot. */
.presence { margin-right: 8px; font-size: var(--fs-small); font-weight: 600; }
.presence::before { content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 4px; border-radius: 50%; vertical-align: middle; }
.presence--online { color: #68d391; }
.presence--online::before { background: #68d391; }
.presence--offline { color: #888; }
.presence--offline::before { background: #555; }

/* Cards in flight (board_motion.js): copies over the whole page, so the
   board's areas don't clip them; the real card shows once one lands. */
.board-motion-layer { position: fixed; inset: 0; pointer-events: none; z-index: 1000; }
.board-motion-ghost {
  position: absolute;
  margin: 0;
  transition: none;
  box-shadow: 0 8px 18px rgba(0, 0, 0, 0.55);
  will-change: transform, opacity;
}

/* Floats over the table instead of taking room below it. */
.match-board__life-reveal {
  position: absolute;
  z-index: 3;
  right: 12px;
  bottom: 12px;
  max-width: 320px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
  background: #141414;
  border: 1px solid #2a2a2a;
  border-radius: 8px;
  padding: 10px 12px;
  cursor: pointer;
  animation: life-reveal-in 0.2s ease-out;
}
@keyframes life-reveal-in { from { opacity: 0; transform: translateY(6px); } }

.life-reveal__title {
  font-size: var(--fs-small);
  color: #888;
  text-transform: uppercase;
}

.life-reveal__name {
  font-weight: 600;
  margin: 2px 0;
}

.life-reveal__trigger {
  font-size: var(--fs-small);
  color: #777; /* muted — Premise 3 caveat: a real trigger doesn't resolve yet, so it must never read as fully "live" */
  font-style: italic;
}

.match-board__toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  background: #2a2a2a;
  border: 1px solid #444;
  color: #e8e8e8;
  padding: 8px 16px;
  border-radius: 6px;
  font-size: var(--fs-small);
  z-index: 10;
}

.match-board__toast--error {
  background: #3a1a1a;
  border-color: #742a2a;
  color: #fc8181;
}

@media (max-width: 480px) {
  /* The hand on a phone: big cards, fanned in one row as on a desktop —
     all in view; the one picked to play comes to the front. */
  .match-board, .hand-panel { --hand-h: 128px; }
  .match-board__hand-cards > .hand-card { flex: none; }
  .match-board__zone-header { flex-direction: column; align-items: flex-start; gap: 4px; }
  /* (the mat's labels are background: on a phone's narrow mat, as small as they were, so they don't run into the cards) */
  .mat-area__label { font-size: 0.58rem; }
  .combatant { min-width: 80px; }
  .match-board__combatants { gap: 4px; }
  .match-board__combatants > .combatant { min-width: 0; }
}

/* ── Replay scrubber (T11) ────────────────────────────────────────────────── */

.replay-scrubber {
  display: flex;
  align-items: center;
  gap: 8px 10px;
  flex-wrap: wrap;
  background: #141414;
  border: 1px solid #2a2a2a;
  border-radius: 8px;
  padding: 8px 10px;
}

.replay-scrubber input[type="range"] {
  flex: 1;
  min-width: 120px;
  accent-color: #f0c040;
}

.replay-scrubber__label {
  font-size: var(--fs-small);
  color: #aaa;
}

/* ── Landing page ─────────────────────────────────────────────────────────── */
.home-hero {
  max-width: 480px;
  margin: 96px auto;
  padding: 0 16px;
  text-align: center;
}

.home-hero__tagline {
  color: #aaa;
  margin-bottom: 24px;
}

.home-hero__actions {
  display: flex;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* ── Card hover preview ───────────────────────────────────────────────────────
 * Deliberately no interactive chrome (no close button, no dimmed backdrop) —
 * this is a transient hover glance, not a deliberate look-closer click.
 * `pointer-events: none` is load-bearing: without it, this full-viewport
 * overlay would sit on top of the card being hovered and immediately steal
 * the mouseleave event that's supposed to make it disappear. */
.card-preview-overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  pointer-events: none;
  z-index: 25;
}

.card-preview {
  max-width: 460px;
  width: 100%;
  background: #141414;
  border: 1px solid #2a2a2a;
  border-radius: 8px;
  padding: 10px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
}

.card-preview__image {
  width: 100%;
  border-radius: 6px;
  display: block;
}

/* Held on purpose (a finger on a touch screen): a lightbox — dimmed,
   tappable anywhere to close, with a close button to say so. */
.card-preview-overlay--lightbox { pointer-events: auto; background: rgba(0, 0, 0, 0.7); z-index: 1000; } /* (over the trash sheet, under the messages) */
.card-preview-overlay--lightbox .card-preview { position: relative; max-height: 100%; width: auto; max-width: min(460px, 100%); }
.card-preview-overlay--lightbox .card-preview__image { max-height: calc(100vh - 140px); width: auto; max-width: 100%; margin: 0 auto; }
.card-preview__close {
  position: absolute; top: -14px; right: -14px;
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid #444; background: #222; color: #eee;
  font-size: 1.6rem; line-height: 1; cursor: pointer;
}
/* The trash on a phone (no column beside the board — TrashPanel): a sheet
   over the bottom of the screen, its cards in a grid (a trash can hold 30:
   in one row they'd be slivers), scrolling past 60% of the screen. */
.trash-sheet { position: fixed; inset: 0; z-index: 950; background: rgba(0, 0, 0, 0.5); display: flex; align-items: flex-end; }
.trash-sheet__panel {
  width: 100%; max-height: 60vh; overflow-y: auto; box-sizing: border-box;
  background: #161616; border-top: 1px solid #333; border-radius: 12px 12px 0 0;
  padding: 8px 12px 16px; box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.6);
}
.trash-sheet__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; font-size: var(--fs-small); }
.trash-sheet__close { width: 40px; height: 40px; border-radius: 50%; border: 1px solid #444; background: #222; color: #eee; font-size: 1.5rem; line-height: 1; cursor: pointer; }
.trash-sheet .trash-panel__cards { grid-template-columns: repeat(auto-fill, minmax(60px, 1fr)); }

/* (holding a card mustn't open the phone's own image menu or select text) */
@media (hover: none) {
  .card-face, .card-face img, .combatant, .hand-card, .deck-stack, .card-grid img { -webkit-touch-callout: none; user-select: none; -webkit-user-select: none; }
}

/* ── Right-click "Copy image" (card_copy_controller.js) — above the hover
 * preview (z-index 25), which can still be showing when the menu opens. ── */
.card-copy-menu {
  position: fixed;
  z-index: 30;
  min-width: 140px;
  padding: 4px;
  background: #141414;
  border: 1px solid #2a2a2a;
  border-radius: 6px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
}

.card-copy-menu__item {
  display: block;
  width: 100%;
  padding: 8px 12px;
  background: none;
  border: none;
  border-radius: 4px;
  color: #e8e8e8;
  font-size: var(--fs-small);
  text-align: left;
  cursor: pointer;
}
.card-copy-menu__item:hover,
.card-copy-menu__item:focus-visible { background: #2a2a2a; outline: none; }

.card-copy-toast {
  position: fixed;
  z-index: 30;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  padding: 10px 16px;
  border-radius: 6px;
  background: #1a3a1a;
  color: #68d391;
  font-size: var(--fs-small);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
  pointer-events: none;
}
.card-copy-toast--error { background: #3a1a1a; color: #fc8181; }


/* ── Report a bug (bug_report_controller.js) ──────────────────────────────── */
.bug-report {
  width: min(480px, calc(100vw - 32px));
  padding: 0;
  background: #1a1a1a;
  color: #e8e8e8;
  border: 1px solid #444;
  border-radius: 8px;
}
.bug-report::backdrop { background: rgba(0, 0, 0, 0.6); }
.bug-report__form { display: flex; flex-direction: column; gap: 10px; padding: 18px; }
.bug-report__title { margin: 0; font-size: var(--fs-large); }
.bug-report__hint { margin: 0; font-size: var(--fs-small); color: #999; }
.bug-report__text {
  width: 100%;
  resize: vertical;
  padding: 8px 10px;
  font: inherit;
  font-size: var(--fs-body);
  color: #e8e8e8;
  background: #111;
  border: 1px solid #444;
  border-radius: 4px;
}
.bug-report__text:focus { outline: 2px solid #f0c040; outline-offset: -1px; }
.bug-report__status { margin: 0; min-height: 1.2em; font-size: var(--fs-small); color: #f0c040; }
.bug-report__actions { display: flex; justify-content: flex-end; gap: 8px; }

/* ── Game log (game_log_view.js): a drawer over the right of the board ───── */
.match-board { position: relative; }
.game-log {
  position: absolute;
  top: 6px;
  right: 0;
  bottom: 48px; /* (above the status bar) */
  z-index: 30;
  width: min(340px, 90%);
  display: flex;
  flex-direction: column;
  background: rgba(20, 20, 20, 0.96);
  border: 1px solid #333;
  border-radius: 6px 0 0 6px;
  box-shadow: -4px 0 16px rgba(0, 0, 0, 0.5);
}
.game-log[hidden] { display: none; }
.game-log__header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  font-size: var(--fs-small);
  font-weight: 600;
  color: #ccc;
  border-bottom: 1px solid #2a2a2a;
}
.game-log__close { background: none; border: none; color: #999; font-size: var(--fs-large); line-height: 1; cursor: pointer; }
.game-log__close:hover { color: #fff; }
.game-log__list { flex: 1; overflow-y: auto; margin: 0; padding: 6px 12px 10px; list-style: none; font-size: var(--fs-small); line-height: 1.35; }
.game-log__entry { padding: 4px 0; color: #ddd; }
.game-log__entry--turn { margin-top: 6px; padding-top: 8px; border-top: 1px solid #2a2a2a; color: #f0c040; font-weight: 600; }
.game-log__moves { margin: 2px 0 0; padding-left: 14px; list-style: "· "; color: #aaa; font-weight: normal; }
.game-log__card { color: #fff; text-decoration: underline dotted #777; text-underline-offset: 2px; cursor: default; }
.game-log__empty { color: #777; font-size: var(--fs-small); padding: 8px 0; }
.match-board__status-actions [aria-pressed="true"] { color: #f0c040; }

/* ── The decision panel (game_board_controller#renderDecision): the bar's
   controls, right above the hand in the column ─────────────────────────── */
.decision-panel { flex: none; }
.decision-panel:empty { display: none; }
.decision-panel .match-board__controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 10px 12px;
  background: #131313;
  border: 1px solid #2a2a2a;
  border-radius: 6px;
  font-size: var(--fs-body);
}
.decision-panel--mine .match-board__controls { border-color: #f0c040; }
.decision-panel .match-board__controls > strong,
.decision-panel .match-board__controls > em,
.decision-panel .match-board__pick-count { flex: 1 0 100%; }
.decision-panel .match-board__controls .btn-primary,
.decision-panel .match-board__controls .btn-secondary { min-height: 40px; padding: 8px 14px; }
.decision-panel .match-board__option { flex: 1 1 100%; justify-content: flex-start; text-align: left; white-space: normal; }

/* ── Devise's pages (log in, sign up, password): a card in the middle ───── */
.auth-page {
  width: min(400px, calc(100vw - 32px));
  margin: 8vh auto 32px;
  padding: 28px 28px 20px;
  background: #161616;
  border: 1px solid #2a2a2a;
  border-radius: 10px;
}
.auth-page h2 { margin: 0 0 20px; font-size: var(--fs-large); }
.auth-page .field { margin-bottom: 14px; }
.auth-page .field p { margin: 0; }
.auth-page .field label { display: block; margin-bottom: 6px; font-size: var(--fs-small); color: #bbb; }
.auth-page .field em { display: block; margin: -2px 0 6px; font-size: var(--fs-small); color: #888; font-style: normal; }
/* "Remember me": the box and its label on one line */
.auth-page .field:has(input[type="checkbox"]) { display: flex; align-items: center; gap: 8px; }
.auth-page .field:has(input[type="checkbox"]) label { margin: 0; color: #e8e8e8; font-size: var(--fs-body); }
.auth-page input[type="checkbox"] { width: 16px; height: 16px; accent-color: #f0c040; }
.auth-page .actions { margin: 20px 0 16px; }
.auth-page .actions input[type="submit"] { width: 100%; padding: 10px; }
.auth-page > p, .auth-page form + p, .auth-page p:has(> a) { margin: 8px 0; text-align: center; font-size: var(--fs-small); }
.auth-page a:not(.btn-primary) { color: #f0c040; }
.auth-page a:not(.btn-primary):hover { text-decoration: underline; }
.auth-page form.button_to { display: block; margin: 16px 0 0; padding-top: 16px; border-top: 1px solid #2a2a2a; }
.auth-page__provider { width: 100%; padding: 10px; font-size: var(--fs-body); }
.auth-page #error_explanation { margin-bottom: 16px; padding: 10px 12px; background: #3a1a1a; color: #fc8181; border-radius: 6px; font-size: var(--fs-small); }
.auth-page #error_explanation h2 { margin: 0 0 6px; font-size: var(--fs-small); }
.auth-page #error_explanation ul { margin: 0; padding-left: 18px; }

/* ── The deck builder on a phone: one column that scrolls as a page — the
   top bar (stuck at the top: Save always at hand), the deck, the filters,
   then the cards (a tap adds one). No hover there: no preview panel, and
   no sidebar to resize. ───────────────────────────────────────────────── */
@media (max-width: 760px) {
  .deck-builder { display: flex; flex-direction: column; height: auto; min-height: 100vh; overflow: visible; }
  .db-workspace { display: contents; }
  .db-resize-handle, .db-preview { display: none; }

  .db-topbar { order: 1; position: sticky; top: 0; z-index: 20; flex-wrap: wrap; height: auto; gap: 8px 12px; padding: 10px 12px; }
  .db-name-input { flex: 1 1 60%; }
  .db-count { margin-left: auto; }
  .db-topbar__actions { flex: 1 1 100%; flex-wrap: wrap; gap: 6px; }
  .db-topbar__actions > * { flex: 1 1 auto; }
  .db-topbar__actions .btn-primary,
  .db-topbar__actions .btn-secondary { min-height: 36px; padding: 0 10px; }

  .db-errors { top: 12px; }
  .db-invite { order: 2; }
  .db-deckstrip { order: 3; padding: 10px 12px; }
  .db-sidebar { order: 4; overflow: visible; padding: 12px; border-bottom: 1px solid #2a2a2a; }
  .db-main { order: 5; overflow: visible; padding: 8px 12px 24px; }
}

/* Watching a match (MatchesController#watch): said in the bar. */
.match-board__watching { color: #f0c040; font-size: var(--fs-small); font-weight: 600; }

/* An invite opened signed out (matches/join_guest): who challenged, and the way in. */
.invite-page h2 { margin-bottom: 6px; }
.invite-page__what { margin: 0 0 16px; color: #ccc; }
.invite-page__steps { margin: 0 0 12px; padding-left: 20px; color: #ccc; line-height: 1.7; }
.invite-page__note { margin: 0 0 18px; color: #888; font-size: var(--fs-small); text-align: left; }
.invite-page__main { width: 100%; }
.decks-index__invite { margin: 0 0 16px; border-radius: 6px; }
.decks-index__invite a { text-decoration: underline; }

/* My Matches (matches/index): a list per group — your turn first. */
.matches-index__group { margin-bottom: 28px; }
.matches-index__group h2 { font-size: var(--fs-h3, 1.1rem); margin: 0 0 10px; display: flex; align-items: center; gap: 8px; }
.matches-index__count { background: #f0c040; color: #111; border-radius: 999px; padding: 0 9px; font-size: var(--fs-small); font-weight: 700; }
.matches-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.matches-list__row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: 8px 16px;
  background: #161616; border: 1px solid #2a2a2a; border-radius: 8px; padding: 10px 14px;
}
.matches-list__who { display: flex; flex-direction: column; min-width: 0; }
.matches-list__leaders { color: #aaa; font-size: var(--fs-small); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.matches-list__meta { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; color: #888; font-size: var(--fs-small); }
.matches-list__time-control { color: #ccc; }
.matches-list__time-control--none { color: #90cdf4; }
.matches-list__result--won { color: #68d391; font-weight: 700; }
.matches-list__result--lost { color: #fc8181; font-weight: 700; }
@media (max-width: 560px) {
  .matches-list__row { grid-template-columns: minmax(0, 1fr) auto; }
  .matches-list__meta { grid-column: 1 / -1; grid-row: 2; flex-direction: row; flex-wrap: wrap; justify-content: flex-start; gap: 4px 12px; }
}

/* "Challenge a Friend": with the clock or with none (decks/index). */
.deck-tile__challenge { position: relative; }
.deck-tile__challenge > summary { list-style: none; cursor: pointer; }
.deck-tile__challenge > summary::-webkit-details-marker { display: none; }
.deck-tile__challenge-menu {
  position: absolute; z-index: 20; bottom: calc(100% + 6px); left: 0; min-width: 220px;
  display: grid; gap: 6px; padding: 8px; background: #1c1c1c; border: 1px solid #3a3a3a; border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
}
.deck-tile__challenge-menu form { margin: 0; }
.deck-tile__challenge-option {
  width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 2px; text-align: left;
  padding: 8px 10px; background: #262626; color: #eee; border: 1px solid #333; border-radius: 6px; cursor: pointer; font: inherit;
}
.deck-tile__challenge-option:hover, .deck-tile__challenge-option:focus-visible { border-color: #f0c040; }
.deck-tile__challenge-option span { color: #999; font-size: var(--fs-small); }
.matches-nav-link .matches-index__count { margin-left: 4px; }

/* "Report a bug", in the bottom-left corner of every page (the layout):
   out of the way of each page's own buttons. On a narrow screen just its
   icon; the board's bar, stuck to the bottom there, leaves it room. */
.bug-report-fab {
  position: fixed; left: 12px; bottom: 12px; z-index: 900;
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 36px; padding: 0 12px;
  background: #1c1c1c; color: #bbb; border: 1px solid #3a3a3a; border-radius: 999px;
  font: inherit; font-size: var(--fs-small); cursor: pointer;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5); opacity: 0.85;
}
.bug-report-fab:hover, .bug-report-fab:focus-visible { opacity: 1; color: #f0c040; border-color: #f0c040; }
/* (the left column of the board and of the deck builder ends above it, so it covers no card) */
@media (min-width: 1101px) {
  body:has(.bug-report-fab) .match-preview { padding-bottom: 48px; }
}
@media (min-width: 761px) {
  body:has(.bug-report-fab) .db-sidebar { padding-bottom: 60px; }
}
@media (max-width: 1100px) {
  .bug-report-fab { width: 40px; height: 40px; padding: 0; justify-content: center; }
  .bug-report-fab__label { display: none; }
  body:has(.bug-report-fab) .match-board__status { padding-left: 60px; }
}

/* An effect's cards (searched, revealed, to pick) with no column beside
   the board: first in the decision bar, a row above its buttons — one row,
   never wrapped: each card shrinks from 62px as far as it takes to fit. */
.choice-cards--inline { flex: 1 1 100%; order: -1; padding: 8px 0 2px; }
.choice-cards--inline .trash-panel__cards { display: flex; flex-wrap: nowrap; gap: 6px; }
.choice-cards--inline .trash-panel__card { flex: 0 1 62px; min-width: 0; box-sizing: border-box; height: auto; }

/* ── The board on a phone: all of it on one screen ─────────────────────────
   Both zones, the hand and the decision bar fit the screen's height, so
   nothing needs scrolling — and the bar, stuck to the bottom only when the
   page is taller than the screen, never covers the hand. Each zone's header
   is one line; the attack's banner is laid over it rather than pushing the
   table down (which also made every card on it count as moved). */
@media (max-width: 480px) {
  .match-layout { padding: 0 8px; }
  .match-board { padding-top: 2px; }
  .match-board__zone { padding: 2px 6px 3px; margin-bottom: 3px; }
  .match-board__zone-header {
    flex-direction: row; flex-wrap: nowrap; align-items: center; gap: 6px;
    font-size: var(--fs-micro); min-height: 16px; margin-bottom: 2px;
  }
  .match-board__zone-header > span:first-child { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .match-board__zone-header .match-clock { margin: 0; font-size: var(--fs-micro); padding: 0 6px; }
  .match-board__zone-header .don-track,
  .match-board__zone-header .hand-backs { flex: none; }
  /* (the opponent's hand, face down: a small stack, not a row taking the line) */
  .match-board__zone-header .hand-backs .card-back--hand + .card-back--hand { margin-left: -9px; }
  .match-board__attack-banner {
    position: absolute; top: 2px; left: 6px; right: 6px; z-index: 3;
    background: #141414; font-size: var(--fs-micro); line-height: 16px;
    overflow: hidden; text-overflow: ellipsis;
  }
  /* (the table's cards follow the screen's height: 48px where there's room, down to 40px on a short phone) */
  .match-board, .match-layout .match-board { --card-h: clamp(40px, calc((100svh - 330px) / 6.6), 48px); }
  .match-board, .hand-panel { --hand-h: clamp(80px, calc(100svh - 560px), 104px); }
  .match-board__hand-header { font-size: var(--fs-micro); margin-bottom: 1px; }
  .match-board__status { padding: 3px 8px; gap: 2px 8px; margin-top: 3px; }
  .match-board__status-actions { font-size: var(--fs-micro); gap: 8px; }
  /* [Activate: Main]'s ⚡ on a phone's small cards: up in the corner, so a
     tap on the card itself (to attack with it) isn't taken by it. */
  .card-activate { width: 28px; height: 28px; top: -14px; right: -12px; font-size: 0.85rem; }
  .card-activate::after { inset: -4px; }
}

/* Messages that come and go (signed in, an error): over the page at the
   top, whatever the page — never pushing it down, nor pulling it back up
   when gone. */
.toasts {
  position: fixed; top: 12px; left: 50%; transform: translateX(-50%); z-index: 1200;
  width: min(560px, calc(100vw - 24px));
  display: grid; gap: 8px; pointer-events: none;
}
.toasts:empty { display: none; }
.toasts .flash { pointer-events: auto; border-radius: 8px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6); }

/* A decision in a phone's bar (turn order, mulligan, block, Play / Cancel,
   Confirm / None): its question on a line of its own, its buttons side by
   side under it, the same width — not one beside the question and the
   next wrapped under it. (An ability's or an option's long text keeps its
   own full line.) */
@media (max-width: 480px) {
  .match-board__status > .match-board__controls { flex: 1 1 100%; gap: 8px; }
  .match-board__status > .match-board__controls > strong,
  .match-board__status > .match-board__controls > em,
  .match-board__status > .match-board__controls > .match-board__pick-count { flex: 1 1 100%; }
  /* (two to a row at most, the same width — three, like two Blockers and "Don't block": two, then one the whole width; a long name wraps inside its button) */
  .match-board__status > .match-board__controls > .btn-primary:not(.match-board__activate):not(.match-board__option),
  .match-board__status > .match-board__controls > .btn-secondary:not(.match-board__option) { flex: 1 1 calc(50% - 4px); min-width: 0; white-space: normal; height: auto; }
}

/* An effect's question on a phone (no column beside the board — the
   board's renderQuestion): first in the decision bar — whose card, what it
   asks, the card's text (three lines, scrolling past that) — compact, so
   the table and the hand (where a card is often picked) stay in view; the
   status line, which would repeat the question, gives way to it. */
.match-board__status > .question-inline { flex: 1 1 100%; order: -2; font-size: var(--fs-micro); line-height: 1.3; }
.match-board__status > .question-inline .question-panel__body { padding: 0; border: 0; gap: 0; }
.match-board__status > .question-inline .question-panel__body > p { margin: 0 0 2px; padding: 0; border: 0; font-size: var(--fs-micro); line-height: 1.3; }
.match-board__status > .question-inline .question-panel__source { color: #aaa; text-transform: uppercase; letter-spacing: 0.04em; }
.match-board__status > .question-inline .question-panel__prompt { font-size: var(--fs-small); font-weight: 700; color: #e8e8e8; }
.match-board__status > .question-inline .question-panel__text { color: #ccc; max-height: calc(2 * 1.3em); overflow-y: auto; }
.match-board__status:has(.question-inline) > .match-board__status-text,
.match-board__status:has(.question-inline) > .match-board__back { display: none; }
@media (max-width: 480px) {
  /* (while a question is open: the table's cards and the hand a little smaller, so all of it — the hand to pick from too — stays on screen) */
  .match-layout:has(.question-inline) .match-board { --card-h: 38px; --hand-h: 80px; }
}

/* Sorting the hand / an opened trash (board_view's sortSelectHTML): a
   small select beside the hand's title, at the top of the trash. */
.match-board__hand-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.card-sort {
  font: inherit; font-size: var(--fs-micro); color: #ccc; background: #1e1e1e;
  border: 1px solid #333; border-radius: 4px; padding: 1px 4px; cursor: pointer;
}
.trash-panel__tools { display: flex; justify-content: flex-end; margin-bottom: 6px; }
.trash-sheet__header { gap: 8px; }
.trash-sheet__header > strong { margin-right: auto; }
