/* cards.praetoria.live
 *
 * The palette is the map viewer's, deliberately: this is a second window onto
 * one world, and a deckbuilder that looks like a different product makes the
 * seam between them visible in the one place it should not be.
 */
:root {
  --bg: #0e1116; --panel: #161b22; --panel-2: #1c232c; --line: #2a323d;
  --text: #d7dee8; --dim: #8b97a8; --gold: #d9a441; --mine: #62d0a8;
  --warn: #f0b445; --err: #ff5a3a; --ok: #4ec97b;

  /* The six splinters, at the saturation the cards themselves use. */
  --c-Red:   #e0563c; --c-Blue:  #4ea8d8; --c-Green: #63b552;
  --c-White: #e8dfc4; --c-Black: #9a7ec4; --c-Gold:  #d9a441; --c-Gray: #93a0b0;

  --r: 7px;
  --shadow: 0 4px 14px rgba(0,0,0,.45);
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font: 14px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  overflow: hidden;
}
button, input, select { font: inherit; color: inherit; }
a { color: var(--mine); }

/* ------------------------------------------------------------- top bar --- */
#topbar {
  display: flex; align-items: center; gap: 14px;
  height: 52px; padding: 0 14px;
  background: linear-gradient(180deg, #1a212a, #141a22);
  border-bottom: 1px solid var(--line);
}
.brand { display: flex; align-items: center; gap: 8px; text-decoration: none; color: var(--text); }
.brand .mark { color: var(--gold); font-size: 17px; }
.brandtext { font-weight: 600; letter-spacing: .3px; white-space: nowrap; }
.brandtext em { font-style: normal; color: var(--dim); font-weight: 400; }
.spacer { flex: 1; }

.formatbar { display: flex; gap: 7px; align-items: center; overflow: visible; }
.formatgroup { position: relative; }
.formatgroup > summary {
  list-style:none; cursor:pointer; padding:5px 10px; border:1px solid var(--line);
  border-radius:999px; background:var(--panel); color:var(--text);
  font-size:12.5px; white-space:nowrap;
}
.formatgroup > summary::-webkit-details-marker { display:none; }
.formatgroup > summary::after { content:" ▾"; color:var(--gold); }
.formatgroup[open] > summary { border-color:#536171; }
.formatchoices {
  position:absolute; top:calc(100% + 6px); left:0; z-index:60;
  min-width:220px; display:grid; gap:4px; padding:7px;
  background:#11171e; border:1px solid #3b4653; border-radius:9px;
  box-shadow:0 10px 32px rgba(0,0,0,.68);
}
.formatgroup[open]::after {
  content:""; position:absolute; z-index:59; left:0; right:0;
  top:100%; height:8px;
}
.formatbar button {
  background: var(--panel); border: 1px solid var(--line); color: var(--dim);
  padding: 7px 10px; border-radius: 6px; cursor: pointer; white-space: nowrap;
  font-size: 12.5px;
  text-align:left;
}
.formatbar button:hover { color: var(--text); border-color: #3a4553; }
.formatbar button[aria-pressed="true"] {
  color: #10141a; background: var(--gold); border-color: var(--gold); font-weight: 600;
}

.catalogstat { font-size: 11.5px; color: var(--dim); white-space: nowrap; }
.account { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.account .who { color: var(--gold); font-weight: 600; }
.keychainuser {
  width: 138px; min-width: 0; background: #10151c; border: 1px solid var(--line);
  border-radius: 6px; padding: 5px 8px; font-size: 12px; outline: none;
}
.keychainuser:focus { border-color: var(--gold); }

/* ---------------------------------------------------------------- app ---- */
/* 480px is measured, not chosen: the warband is five cards in ONE ROW, because
 * position one is the front line and re-ordering is a real decision you make by
 * looking at them. Five 86px cards plus four gaps plus the pane padding is
 * exactly this wide. Narrower and the row wraps, which breaks the reading of
 * front-to-back; wider and the catalogue starts losing a column. */
#app {
  display: grid; grid-template-columns: 480px 1fr;
  height: calc(100vh - 52px);
}
.pane { min-height: 0; display: flex; flex-direction: column; }
.deckpane {
  position: relative; border-right: 1px solid var(--line); background: var(--panel);
  padding-bottom: 39px;
}

/* --------------------------------------------------------------- deck ---- */
.deckhead { padding: 12px 14px 8px; border-bottom: 1px solid var(--line); }
.deckname {
  width: 100%; background: transparent; border: none; border-bottom: 1px dashed transparent;
  font-size: 17px; font-weight: 600; padding: 2px 0; outline: none;
}
.deckname:hover, .deckname:focus { border-bottom-color: var(--line); }
.deckname::placeholder { color: #4d5867; }
.deckmeta { display: flex; gap: 12px; font-size: 11.5px; color: var(--dim); margin-top: 4px; flex-wrap: wrap; }
.deckmeta .mana strong { color: var(--gold); }
.deckmeta .badge {
  padding: 1px 7px; border-radius: 999px; border: 1px solid var(--line);
}
.deckmeta .badge.active { color: var(--mine); border-color: #2c5c4c; background: rgba(98,208,168,.09); }

/* ------------------------------------------------------- format note ---- */
/* What this format is for. Its text comes from the format document, so a
 * third party's format explains itself in the same box. */
.deckguidance { border-bottom: 1px solid var(--line); }
.deckguidance > summary {
  cursor: pointer; padding: 6px 14px; color: var(--dim); font-size: 11px;
  text-transform: uppercase; letter-spacing: .09em; font-weight: 600;
  list-style: none; user-select: none;
}
.deckguidance > summary::-webkit-details-marker { display: none; }
.deckguidance > summary::before { content: "▸ "; font-size: 9px; }
.deckguidance[open] > summary::before { content: "▾ "; }
.deckguidance > summary:hover { color: var(--text); background: rgba(255,255,255,.02); }
.formatnote {
  padding: 9px 14px; border-top: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(217,164,65,.05), transparent);
}
.formatnote:empty { display: none; }
.notetitle {
  font-size: 11px; text-transform: uppercase; letter-spacing: .09em;
  color: var(--gold); font-weight: 700; margin-bottom: 3px;
}
.notebody { margin: 0 0 5px; font-size: 12.5px; line-height: 1.45; color: #b9c4d2; }
.noteshape { font-size: 11px; color: var(--dim); }
.notewhat {
  margin-top: 6px; font-size: 11.5px; line-height: 1.4; color: #8fa8bf;
  border-left: 2px solid var(--line); padding-left: 7px;
}

.board { padding: 10px 14px; overflow-y: auto; flex: 1; min-height: 0; }
.slotgroup { margin-bottom: 14px; }
.slotgroup > h3 {
  margin: 0 0 6px; font-size: 11px; text-transform: uppercase; letter-spacing: .09em;
  color: var(--dim); font-weight: 600; display: flex; align-items: baseline; gap: 7px;
}
.slotgroup > h3 .hint { text-transform: none; letter-spacing: 0; font-weight: 400; font-size: 11px; opacity: .8; }
.slotrow { display: flex; gap: 7px; flex-wrap: wrap; }
/* A fifty-card deck is a list, not a board. Smaller cells, and the row wraps
 * into a grid rather than pretending to be a front-to-back line — because in a
 * format with no positions, it is not one. */
.slotrow.dense { gap: 5px; }
.slotrow.dense .slot { width: 58px; height: 87px; font-size: 9px; }

/* A slot is a fixed frame so the board never reflows as cards come and go. */
.slot {
  position: relative; width: 68px; height: 96px; border-radius: var(--r);
  border: 1px dashed var(--line); background: #10151c;
  display: flex; align-items: center; justify-content: center;
  color: #46505e; font-size: 10px; cursor: pointer; overflow: hidden;
  text-align: center; white-space: pre-line; line-height: 1.25;
  transition: border-color .12s, transform .12s;
}
.slot.wide { width: 104px; height: 156px; }
.slot:hover { border-color: #3d4855; }
.slot.filled { border-style: solid; cursor: grab; }
.slot.filled.illegal { border-color: var(--err); box-shadow: 0 0 0 1px rgba(255,90,58,.35); }
.slot.filled.capped { border-color: var(--warn); }
.slot.dragover { border-color: var(--gold); transform: translateY(-2px); }
.slot .pos {
  position: absolute; top: 2px; left: 3px; z-index: 3; font-size: 9px;
  color: var(--dim); background: rgba(0,0,0,.6); padding: 0 4px; border-radius: 3px;
}

/* ------------------------------------------------------------ legality --- */
.legality { padding: 0 14px 8px; max-height: 30vh; overflow-y: auto; }
.issue {
  display: flex; gap: 7px; align-items: flex-start;
  font-size: 12px; line-height: 1.4; padding: 6px 8px; margin-bottom: 4px;
  border-radius: 5px; border-left: 3px solid; background: var(--panel-2);
}
.issue.error { border-color: var(--err); color: #ffd0c6; }
.issue.warn  { border-color: var(--warn); color: #f4e0bb; }
.issue .glyph { flex: none; opacity: .85; }
.legality .allgood {
  font-size: 12px; color: var(--ok); padding: 6px 8px;
  border-left: 3px solid var(--ok); background: rgba(78,201,123,.07); border-radius: 5px;
}

.deckactions { display: flex; gap: 7px; padding: 10px 14px; border-top: 1px solid var(--line); }
.btn {
  background: var(--panel-2); border: 1px solid var(--line); color: var(--text);
  padding: 7px 13px; border-radius: 6px; cursor: pointer; font-size: 13px;
}
.btn:hover:not(:disabled) { border-color: #3f4b5a; background: #232c37; }
.btn:disabled { opacity: .42; cursor: not-allowed; }
.btn.primary { background: var(--gold); border-color: var(--gold); color: #10141a; font-weight: 600; }
.btn.primary:hover:not(:disabled) { background: #e8b855; }
.btn.ghost { background: transparent; color: var(--dim); }
.btn.tiny { padding: 3px 8px; font-size: 11px; }

.deckdrawer {
  position: absolute; inset: auto 0 0; z-index: 30;
  background: var(--panel-2); border-top: 1px solid var(--line);
  box-shadow: 0 -10px 24px rgba(0,0,0,.28);
}
.deckdrawer > summary {
  height: 38px; box-sizing: border-box; display: flex; align-items: center; gap: 7px;
  cursor: pointer; padding: 0 14px; color: var(--text); font-size: 12px;
  text-transform: uppercase; letter-spacing: .09em; font-weight: 600;
  list-style: none; user-select: none;
}
.deckdrawer > summary::-webkit-details-marker { display: none; }
.deckdrawer > summary::before { content: "▴"; color: var(--gold); font-size: 10px; }
.deckdrawer[open] > summary::before { content: "▾"; }
.deckdrawer > summary:hover { background: rgba(255,255,255,.035); }
.drawercount { color: var(--dim); font-weight: 400; }
.mydecks {
  border-top: 1px solid var(--line); padding: 8px 14px 14px;
  max-height: min(42vh, 430px); overflow-y: auto; background: var(--panel);
}
.deckrow {
  display: flex; align-items: center; gap: 8px; padding: 5px 7px; border-radius: 5px;
  cursor: pointer; font-size: 12.5px;
}
.deckrow:hover { background: var(--panel-2); }
.deckrow.current { background: var(--panel-2); outline: 1px solid var(--line); }
.deckrow .nm { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.deckrow .tag { font-size: 10px; color: var(--dim); }
.deckrow .tag.on { color: var(--mine); }
.deckrow .del { opacity: 0; color: var(--dim); background: none; border: none; cursor: pointer; }
.deckrow:hover .del { opacity: 1; }
.deckrow .del:hover { color: var(--err); }

/* ------------------------------------------------------------ browser ---- */
.browserpane { background: var(--bg); }
.filters { padding: 10px 14px 8px; border-bottom: 1px solid var(--line); background: var(--panel); }
.filterrow { display: flex; gap: 7px; align-items: center; margin-bottom: 7px; flex-wrap: wrap; }
.filterrow:last-child { margin-bottom: 0; }
.search {
  flex: 1; min-width: 180px; background: #10151c; border: 1px solid var(--line);
  border-radius: 6px; padding: 7px 11px; outline: none;
}
.search:focus { border-color: var(--gold); }

.poolswitch { display: flex; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; }
.poolswitch button {
  background: #10151c; border: none; color: var(--dim); padding: 7px 12px;
  cursor: pointer; font-size: 12.5px; white-space: nowrap;
}
.poolswitch button[aria-pressed="true"] { background: var(--panel-2); color: var(--text); font-weight: 600; }

.chips { gap: 5px; }
.colorrow > .chips { display: flex; gap: 5px; flex-wrap: wrap; }
.colorrow > #dualfilter { padding-left: 7px; border-left: 1px solid var(--line); }
.chip {
  border: 1px solid var(--line); background: #10151c; color: var(--dim);
  padding: 3px 10px; border-radius: 999px; cursor: pointer; font-size: 12px;
  display: inline-flex; align-items: center; gap: 5px;
}
.chip:hover { color: var(--text); }
.chip[aria-pressed="true"] { color: #10141a; font-weight: 600; }
.chip .dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.chip .elementicon { width: 15px; height: 15px; display: block; }

/* Toggle chips that lead with official symbols. */
.chip.iconchip { padding: 3px 9px 3px 5px; gap: 6px; }
.chip.iconchip .seticon { width: 20px; height: 20px; display: block; flex: none; }
.chip.iconchip .racemark { display: block; flex: none; }
.chip.iconchip .chiplabel { white-space: nowrap; }
.chip.iconchip .chipcount {
  font-size: 10px; opacity: .65; font-variant-numeric: tabular-nums;
}
.chip.iconchip[aria-pressed="true"] {
  background: var(--gold); border-color: var(--gold); color: #10141a;
}
.chip.iconchip[aria-pressed="true"] .chipcount { opacity: .8; }
.chip.iconchip.compact { padding: 2px 7px 2px 4px; gap: 4px; font-size: 11.5px; }
.filterline { display:flex; align-items:flex-start; gap:8px; flex-wrap:wrap; }
.filterlabel {
  min-width:48px; padding-top:4px; color:var(--dim); font-size:10px;
  font-weight:700; letter-spacing:.08em; text-transform:uppercase;
}
.foilmark {
  min-width:22px; height:20px; padding:0 4px; border-radius:4px;
  display:inline-grid; place-items:center; background:#28313c; color:#f2d37a;
  border:1px solid #596675; font-size:10px; font-weight:800;
}
.chip.iconchip:disabled {
  opacity: .38; filter: grayscale(1); cursor: not-allowed;
  border-color: #47505b; color: #b1b7bf;
}

#deckconfig .chip {
  color:#eef3f8; background:#27313d; border-color:#536171;
  font-weight:650; padding:6px 11px;
}
#deckconfig .chip:hover { background:#354250; border-color:#7b8b9d; }
#deckconfig .chip[aria-pressed="true"] {
  color:#111820; background:#f0c45b; border-color:#f0c45b;
}

/* Sets and races are long rows, so they collapse. Sets open by default — most
 * people filter by set; races are a specialist tool. */
.facetbox { margin-bottom: 7px; }
.facetbox > summary {
  cursor: pointer; font-size: 11px; text-transform: uppercase;
  letter-spacing: .09em; color: var(--dim); font-weight: 600;
  padding: 2px 0; user-select: none; list-style: none;
}
.facetbox > summary::-webkit-details-marker { display: none; }
.facetbox > summary::before { content: "▸ "; font-size: 9px; }
.facetbox[open] > summary::before { content: "▾ "; }
.facetbox > summary:hover { color: var(--text); }
.facetbox .chips { max-height: 168px; overflow-y: auto; padding: 4px 0 2px; }

.selects select {
  background: #10151c; border: 1px solid var(--line); border-radius: 6px;
  padding: 5px 8px; max-width: 165px; cursor: pointer;
}
.manarow { font-size: 12px; color: var(--dim); }
.check { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; }
.resultcount { font-size: 11.5px; color: var(--dim); }

/* The grid is the only thing on the page that can be enormous, so it scrolls
 * alone and everything else stays put. */
/* grid-auto-rows is an explicit number rather than `auto` on purpose. A grid
 * item that sizes itself with `aspect-ratio` and sits in an auto-sized row is
 * circular — the row wants the item's height, the item derives its height from
 * a width the row has not resolved — and browsers break the tie by falling back
 * to the item's min-content height. That collapsed every row to 27px while the
 * cards themselves measured a correct 165px, so a hundred cards overlapped into
 * ten columns of mush. A fixed row height cuts the circularity: the column
 * width still flexes, `object-fit: cover` absorbs the few pixels of ratio drift. */
.grid {
  flex: 1; min-height: 0; overflow-y: auto; padding: 12px 14px 40px;
  display: grid; gap: 10px; align-content: start;
  grid-template-columns: repeat(auto-fill, minmax(108px, 1fr));
  grid-auto-rows: 172px;
  outline: none;
}
.grid .empty { grid-column: 1/-1; color: var(--dim); padding: 30px 0; text-align: center; }

/* ---------------------------------------------------------------- card --- */
.card {
  position: relative; border-radius: var(--r); overflow: hidden; cursor: pointer;
  background: #0b0e13; border: 1px solid var(--line); height: 100%;
  transition: transform .1s, border-color .1s, box-shadow .1s;
}
.card:hover { transform: translateY(-3px); box-shadow: var(--shadow); border-color: #46525f; }
.card.picked {
  opacity:.34; filter:grayscale(1); cursor:not-allowed;
  border-color:#65707d; box-shadow:none;
}
.card.picked:hover { transform:none; box-shadow:none; border-color:#65707d; }
.card.picked .patronall { pointer-events:none; }
.card.unowned { opacity: .45; }
.card.illegalpick { border-color: #5b2a22; }
/* The image must paint OVER the fallback name, not under it. Both are in the
 * same stacking context and the fallback comes later in the DOM, so without
 * these z-indexes the placeholder text shows through every loaded card. */
.card img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  background: #0b0e13; position: relative; z-index: 1;
}
.card.arcane::after {
  content:""; position:absolute; inset:-18%; z-index:4; pointer-events:none;
  background-image:url("https://d36mxiodymuqjm.cloudfront.net/card_effects/arcane_glimmer_full.webp");
  background-size:cover; background-position:center;
  mix-blend-mode:screen; opacity:.52;
  animation:arcane-shimmer 3.4s ease-in-out infinite alternate;
}
@keyframes arcane-shimmer {
  0%   { transform:translate3d(-4%,-2%,0) scale(1.03); opacity:.30; }
  45%  { opacity:.62; }
  100% { transform:translate3d(4%,2%,0) scale(1.10); opacity:.46; }
}
@media (prefers-reduced-motion: reduce) {
  .card.arcane::after { animation:none; opacity:.42; }
}
.card .fallbackname {
  position: absolute; inset: 0; z-index: 0; display: flex; align-items: center; justify-content: center;
  padding: 8px; text-align: center; font-size: 11px; color: var(--dim);
}

/* The composite overlay: when the art we land on is stat-less, these are the
 * numbers. Always drawn — on a by-level render they agree with the baked-in
 * art, and agreeing twice is cheaper than deciding which render we got. */
.card .lv {
  position: absolute; bottom: 3px; right: 4px; z-index: 2;
  font-size: 10px; font-weight: 700; color: #ffeec2;
  background: rgba(0,0,0,.72); padding: 0 5px; border-radius: 4px;
  border: 1px solid rgba(217,164,65,.5);
}
.card .lv.capped { color: #10141a; background: var(--warn); border-color: var(--warn); }
.card .mana {
  position: absolute; top: 4px; left: 4px; z-index: 2;
  width: 19px; height: 19px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #2f6fd0, #123a78);
  border: 1px solid #6ea8ee; color: #eaf3ff;
  font-size: 11px; font-weight: 700; display: flex; align-items: center; justify-content: center;
}
.card .foil {
  position: absolute; top: 4px; right: 4px; z-index: 2; font-size: 9px;
  padding: 0 4px; border-radius: 3px; font-weight: 700;
}
.card .foil.gold { background: #d9a441; color: #241a06; }
.card .foil.blk  { background: #241f2e; color: #cbb8e8; border: 1px solid #6f5c93; }
/* Resting: benched by a PvE death, still in the deck. Dimmed and stamped with
   a timer rather than removed — a deck that silently shrank would read as the
   game taking your cards away. */
.card.resting { opacity: .5; filter: grayscale(.8); }
/* Hurt, not benched: still fieldable, just carrying damage. Dimmed far less
   than a resting card, because the difference between "cannot fight" and
   "fights at 3 of 6" is the whole decision the player is making. */
.card.hurt { box-shadow: inset 0 0 0 1px rgba(240,180,69,.55); }
.card .rest.wound { background: #b4622e; color: #ffe6d2; }
.card .rest {
  position: absolute; bottom: 3px; left: 4px; right: 4px; z-index: 3;
  text-align: center; font-size: 9.5px; font-weight: 700;
  color: #10141a; background: var(--warn); border-radius: 3px; padding: 0 3px;
}

.card .copies {
  position: absolute; bottom: 3px; left: 4px; z-index: 2; font-size: 9.5px;
  color: var(--dim); background: rgba(0,0,0,.65); padding: 0 4px; border-radius: 3px;
}
.card .selectedcopies {
  position: absolute; right: 4px; top: 27px; z-index: 5;
  min-width: 28px; padding: 2px 5px; border-radius: 9px;
  background: #285b43; border: 1px solid #6fb98f; color: #e4f8eb;
  font-size: 9px; font-weight: 800; text-align: center;
  box-shadow: 0 1px 4px rgba(0,0,0,.55);
}
.card .patronall {
  position:absolute; right:4px; bottom:20px; z-index:6;
  padding:3px 6px; border:1px solid #6fb98f; border-radius:5px;
  background:rgba(13,45,31,.94); color:#dff5e7;
  font-size:9px; font-weight:800; cursor:pointer;
}
.card .patronall:hover { background:#285b43; }
.copypicker {
  position:fixed; inset:0; z-index:100; display:flex; align-items:center;
  justify-content:center; padding:20px; background:rgba(3,6,9,.76);
}
.copypanel {
  position:relative; width:min(560px, 96vw); max-height:82vh; overflow:auto;
  padding:18px; border:1px solid #416f57; border-radius:12px;
  background:var(--panel); box-shadow:0 18px 60px rgba(0,0,0,.72);
}
.copypanel h3 { margin:0 36px 4px 0; color:#dff5e7; }
.copypanel > p { margin:0 36px 14px 0; color:var(--dim); font-size:12px; }
.copyclose {
  position:absolute; right:10px; top:8px; width:34px; height:34px;
  border:1px solid #728195; border-radius:7px; background:#293542;
  color:#fff; font-size:24px; line-height:28px; cursor:pointer;
}
.copyclose:hover { background:#435264; border-color:#a7b5c5; }
.copylist { display:flex; flex-direction:column; gap:6px; }
.copyrow {
  display:flex; align-items:center; gap:12px; padding:9px 10px;
  border:1px solid var(--line); border-radius:8px; background:var(--panel-2);
}
.copyrow.selected { border-color:#6fb98f; background:rgba(52,100,75,.22); }
.copydetail { min-width:0; flex:1; display:grid; gap:2px; }
.copydetail span, .copydetail small { color:var(--dim); }
.copydetail small { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.copyrow button, .copyall {
  border:1px solid #6fb98f; border-radius:6px; background:#173b2b;
  color:#e1f6e9; padding:7px 9px; cursor:pointer;
}
.copyall { margin-top:12px; width:100%; }
.card .splinter {
  position: absolute; left: 0; top: 0; bottom: 0; width: 3px; z-index: 2;
}
.card .nameplate {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 1;
  padding: 12px 5px 3px; font-size: 10px; line-height: 1.2;
  background: linear-gradient(180deg, transparent, rgba(6,9,13,.93) 55%);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* --------------------------------------------------------- hover card ---- */
.hovercard {
  position: fixed; z-index: 60; pointer-events: none; opacity: 0;
  transition: opacity .1s; width: 232px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  box-shadow: var(--shadow); padding: 10px 12px; font-size: 12px;
}
.hovercard.on { opacity: 1; }
.hovercard h4 { margin: 0 0 2px; font-size: 13.5px; }
.hovercard .sub { color: var(--dim); font-size: 11px; margin-bottom: 7px; }
.hovercard .stats { display: flex; gap: 9px; flex-wrap: wrap; margin-bottom: 6px; }
.hovercard .stat { display: flex; align-items: center; gap: 3px; }
.hovercard .stat b { font-weight: 700; }
.hovercard .abil { color: var(--gold); font-size: 11px; line-height: 1.45; }
.hovercard .note { margin-top: 6px; font-size: 11px; color: var(--warn); }
.hovercard .note.bad { color: var(--err); }

/* -------------------------------------------------------------- toast ---- */
.toast {
  position: fixed; left: 50%; bottom: 22px; transform: translate(-50%, 14px);
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
  padding: 9px 16px; font-size: 13px; box-shadow: var(--shadow);
  opacity: 0; pointer-events: none; transition: opacity .15s, transform .15s; z-index: 80;
  max-width: min(560px, 90vw);
}
.toast.on { opacity: 1; transform: translate(-50%, 0); }
.toast.bad { border-color: #6b2a2a; color: #ffd0c6; }
.toast.good { border-color: #2c5c4c; color: #c6f0dd; }

/* ------------------------------------------------------------- public ---- */
.deckpage { padding: 26px; overflow-y: auto; height: calc(100vh - 52px); }
.deckpage h1 { margin: 0 0 4px; font-size: 26px; }
.deckpage .by { color: var(--dim); margin-bottom: 18px; }
.deckpage .lineup { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 20px; }
.deckpage .lineup .card { width: 132px; height: 198px; }

/* ------------------------------------------------------------ responsive - */
@media (max-width: 1100px) {
  #app { grid-template-columns: 1fr; grid-template-rows: auto 1fr; height: auto; }
  body { overflow: auto; }
  .deckpane { border-right: none; border-bottom: 1px solid var(--line); }
  .board { max-height: none; }
  .catalogstat { display: none; }
}

/* Phones. The warband MUST stay on one line here too — position one is the
 * front line and takes the melee, so a row that wraps to two stops reading
 * front-to-back and the ordering silently stops meaning anything. At 390px the
 * pane is the full width, so: 362px of content, four 5px gaps, five 66px cards.
 * Measured against a 390x844 viewport, which is the narrow end of what anyone
 * actually holds. */
@media (max-width: 560px) {
  /* The format bar gets its own line rather than competing with the account for
   * the last 60px of a 390px header, where it was clipped mid-word. */
  #topbar { height: auto; flex-wrap: wrap; padding: 8px 12px; row-gap: 6px; }
  #topbar .formatbar { order: 3; flex-basis: 100%; padding-bottom: 2px; }
  .account { font-size: 12px; }
  .account .btn.tiny { white-space: nowrap; }
  .account.signedout { order: 2; flex-basis: 100%; justify-content: flex-end; }
  .account.signedout .keychainuser { flex: 1; width: auto; }
  #app { height: auto; }
  .slotrow { gap: 5px; }
  .slot { width: 66px; height: 99px; }
  .slot.wide { width: 84px; height: 126px; }
  .board { padding: 10px 14px; }
  .slotgroup > h3 { flex-wrap: wrap; }
  .slotgroup > h3 .hint { flex-basis: 100%; }
  .deckactions { flex-wrap: wrap; }
  .filterrow .search { min-width: 0; }
}
