/*
 * cards.css — shared card tile and card modal styles
 * Sourced from game.html; used by game.html, lobby.html, and any future pages.
 */

/* ── Card type accent colors (extend :root) ── */
:root {
  --c-bioform:  #52E87A;
  --c-protocol: #38C8D4;
  --c-catalyst: #C8943A;
  --c-mutation: #D858A8;

  /* The plate a card sits on. Art bleeds over it; cards with no art yet (most
     of the catalog, for now) read as this black. */
  --card-plate: #06090A;
  /* Height of the FER/VIT numerals. The stat band is sized off this, so every
     card's band is the same height whatever it happens to carry. */
  --stat-size:  0.88rem;
  /* The small caps in the bands (FER / VIT / DURATION). Ability rows use it too,
     for both their text and their height. */
  --label-size: 0.57rem;
}

/* ══════════════════════════════════════════════════════════════════════════
   CARD TILE
   One treatment, two modes. The art block is a perfect square, so 1024² source
   art drops in 1:1 with no crop and no reframing; the name is scrimmed over its
   top, and the ability rows and stat band ride on its bottom edge rather than
   sitting under it. In hand the card is square + footer. In play the cost pips
   and the footer are dropped, so the tile is exactly the square — shorter, and
   otherwise identical.
   ══════════════════════════════════════════════════════════════════════════ */
.card {
  --card-w: 160px;
  width: var(--card-w);
  background: var(--card-plate);
  border: 1px solid var(--plating);
  border-radius: 5px;
  cursor: pointer;
  user-select: none;
  flex-shrink: 0;
  touch-action: none;
  transition: transform 0.15s ease;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.card:hover { border-color: var(--cold-steel); }

.card-art {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.card-art > .art {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
  display: block;
}
/* Top scrim — carries the name and cost. There is deliberately no bottom scrim:
   the ability rows and the stat band carry their own backing, so nothing needs
   a wash over the art, and nothing draws a visible edge across it. */
.card-art::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 34%; z-index: 1;
  background: linear-gradient(to bottom, rgba(4,8,7,0.85), rgba(4,8,7,0));
}
.card-art > *:not(.art) { position: relative; z-index: 2; }

.card-header {
  padding: 0.28rem 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  flex-shrink: 0;
}
.hname {
  font-weight: bold;
  font-size: 0.76rem;
  color: var(--bone-moss);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.2;
  text-shadow: 0 1px 3px rgba(0,0,0,0.9);
}
.hpips {
  font-size: 0.62rem;
  color: var(--toxic-flash);
  letter-spacing: 0.12em;
  white-space: nowrap;
  overflow: hidden;
  line-height: 1.2;
  text-shadow: 0 1px 3px rgba(0,0,0,0.9);
}

.card-content {
  flex: 1;
  padding: 0 0.5rem 0.34rem;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
}
.card-content.effect-centered { justify-content: center; text-align: center; }
/* Bioform ability rows are full-bleed bands, so they carry their own inset and
   stack flush onto the stat band below. */
.bioform .card-content { padding: 0; }

/* Ability rows: the stat band's treatment, halved. One row per ability, tint
   and top rule running from the left edge on the same stops as the band —
   50 · 50 · 25 · 0 — and clear from the middle out. No bottom rule: the next
   row's top rule (or the stat band's) closes each one. Row height is the label
   size plus the band's own 0.24rem inset, so the rows sit on the same vertical
   rhythm as the band they stack onto. */
.ability-line,
.card-toxin {
  --accent: var(--c-bioform);
  --tint: color-mix(in srgb, var(--accent) 16%, #050907);
  position: relative;
  padding: 0.24rem 0.5rem;
  font-size: var(--label-size);
  line-height: 1;
  letter-spacing: 0.03em;
  color: color-mix(in srgb, var(--accent) 55%, var(--cold-steel));
  text-shadow: 0 1px 3px rgba(0,0,0,0.95);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  background: linear-gradient(to right,
    color-mix(in srgb, var(--tint) 50%, transparent) 0%,
    color-mix(in srgb, var(--tint) 50%, transparent) 14.29%,
    color-mix(in srgb, var(--tint) 25%, transparent) 28.57%,
    transparent 42.86%);
}
.ability-line::before,
.card-toxin::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(to right,
    color-mix(in srgb, var(--accent) 50%, transparent) 0%,
    color-mix(in srgb, var(--accent) 50%, transparent) 14.29%,
    color-mix(in srgb, var(--accent) 25%, transparent) 28.57%,
    transparent 42.86%);
}
/* Toxin is the same band on its own accent — it stacks with the ability rows
   rather than sitting apart from them. */
.card-toxin { --accent: #E04848; margin: 0; }

.effect-text {
  font-size: 0.7rem;
  color: #E4EEE4;
  line-height: 1.45;
  text-shadow: 0 1px 4px rgba(0,0,0,0.95);
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.catalyst .effect-text { font-size: 0.66rem; -webkit-line-clamp: 3; }

/* Stat band: floats on the art, tinted to the card type. The tint runs
   horizontally on evenly spaced stops — 50 · 50 · 25 · 0 · 0 · 25 · 50 · 50 —
   so it holds under FER on the left and VIT on the right and clears through the
   middle. Rules in the accent color cap it top and bottom on the same stops, so
   the whole band fades as one; only the backing fades, the numbers stay opaque.
   Height is pinned to the numerals, so a catalyst showing ∞ is exactly as tall
   as a bioform showing FER/VIT. */
.bottom-bar {
  --accent: var(--c-bioform);
  --tint: color-mix(in srgb, var(--accent) 16%, #050907);
  position: relative;
  border: none;
  padding: 0.24rem 0.5rem;
  height: calc(var(--stat-size) + 0.48rem);
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-shrink: 0;
  background: linear-gradient(to right,
    color-mix(in srgb, var(--tint) 50%, transparent) 0%,
    color-mix(in srgb, var(--tint) 50%, transparent) 14.29%,
    color-mix(in srgb, var(--tint) 25%, transparent) 28.57%,
    transparent 42.86%,
    transparent 57.14%,
    color-mix(in srgb, var(--tint) 25%, transparent) 71.43%,
    color-mix(in srgb, var(--tint) 50%, transparent) 85.71%,
    color-mix(in srgb, var(--tint) 50%, transparent) 100%);
}
.bottom-bar::before,
.bottom-bar::after {
  content: ''; position: absolute; left: 0; right: 0; height: 1px;
  background: linear-gradient(to right,
    color-mix(in srgb, var(--accent) 50%, transparent) 0%,
    color-mix(in srgb, var(--accent) 50%, transparent) 14.29%,
    color-mix(in srgb, var(--accent) 25%, transparent) 28.57%,
    transparent 42.86%,
    transparent 57.14%,
    color-mix(in srgb, var(--accent) 25%, transparent) 71.43%,
    color-mix(in srgb, var(--accent) 50%, transparent) 85.71%,
    color-mix(in srgb, var(--accent) 50%, transparent) 100%);
}
.bottom-bar::before { top: 0; }
.bottom-bar::after  { bottom: 0; }
.catalyst .bottom-bar { --accent: var(--c-catalyst); }
/* In hand the band's lower rule separates it from the footer; in play there's
   nothing below it but the card's own edge, so it just doubles that edge up. */
.card.ip .bottom-bar::after { display: none; }

.stat-grp      { display: flex; align-items: baseline; gap: 0.2rem; }
.stat-val-pair { display: flex; align-items: baseline; }
.stat-lbl  { font-size: var(--label-size); letter-spacing: 0.05em; text-transform: uppercase; }
.stat-val  { font-size: var(--stat-size); font-weight: bold; line-height: 1; }
.bioform .stat-lbl { color: color-mix(in srgb, var(--c-bioform) 55%, var(--cold-steel)); }
.bioform .stat-val { color: var(--c-bioform); }
.vit-full { color: var(--c-bioform) !important; }
.sb-pos { color: var(--splice-green); font-size: 0.68rem; font-weight: bold; line-height: 1; }
.sb-neg { color: var(--mutagen);      font-size: 0.68rem; font-weight: bold; line-height: 1; }
.bottom-bar .stat-val, .bottom-bar .dur-lbl, .bottom-bar .dur-inf,
.bottom-bar .sb-pos, .bottom-bar .sb-neg { text-shadow: 0 1px 3px rgba(0,0,0,0.95); }

.dur-lbl  { font-size: var(--label-size); letter-spacing: 0.05em; text-transform: uppercase; color: color-mix(in srgb, var(--c-catalyst) 55%, var(--cold-steel)); }
.dur-pips { display: flex; gap: 4px; align-items: center; }
.dur-pip  { width: 9px; height: 9px; border-radius: 50%; background: var(--c-catalyst); flex-shrink: 0; }
.dur-pip.spent { background: color-mix(in srgb, var(--c-catalyst) 18%, var(--plating)); }
.dur-inf  { font-size: 1rem; color: var(--c-catalyst); line-height: 1; }
/* ∞ needs to read at roughly twice the numerals' size, but its box stays one
   numeral tall so the band doesn't grow — the glyph just overhangs it evenly. */
.bottom-bar .dur-inf {
  font-size: calc(var(--stat-size) * 2);
  height: var(--stat-size);
  display: flex; align-items: center; justify-content: flex-end;
}

/* Affinity icons — Noto Emoji font */
.affinity-icon {
  font-family: "Noto Emoji", sans-serif;
  font-optical-sizing: auto;
  font-weight: 400;
  font-variant-emoji: text;
  line-height: 1;
}

/* Single-affinity inner border via inset box-shadow */
.card.has-affinity { border: 2px solid var(--aff-color-1); }

/* Dual-affinity gradient border — left/right split, gradient only near center */
.card.dual-affinity {
  border: 2px solid transparent;
  background:
    linear-gradient(var(--card-plate), var(--card-plate)) padding-box,
    linear-gradient(to right, var(--aff-color-1) 43%, var(--aff-color-2) 57%) border-box;
}

/* Footer: three items on one optical baseline. The rarity pip and the emoji
   affinity icons sit on different natural baselines than the type label, so
   every cell centers its own contents instead of relying on text baselines. */
.card-footer {
  border-top: 1px solid rgba(180,210,190,0.12);
  padding: 0.2rem 0.5rem;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  min-height: 1.35rem;
  flex-shrink: 0;
}
/* Bioforms and catalysts close their square with the stat band's lower rule, so
   the footer would only double it up. */
.bioform .card-footer, .catalyst .card-footer { border-top: none; }
.footer-type  { font-size: var(--label-size); color: #3F5550; line-height: 1; display: flex; align-items: center; }
.footer-rarity { display: flex; align-items: center; justify-content: center; }
.footer-aff   { font-size: 0.72rem; display: flex; align-items: center; justify-content: flex-end; gap: 2px; line-height: 1; }
.footer-aff .affinity-icon { display: block; transform: translateY(0.5px); }  /* optical nudge: emoji sit high in their box */
.rp { width: 6px; height: 6px; border-radius: 50%; display: block; }
.rp-c { background: #3A5048; }
.rp-u { background: #4A7060; }
.rp-r { background: #3858A0; }
.rp-e { background: #6A3880; }
.rp-l { background: #907030; }

/* ── Card modal ── */
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.78); display: flex; justify-content: center; align-items: center; z-index: 200; }

.modal-box {
  background: var(--undergrowth);
  border: 1px solid var(--plating);
  border-radius: 8px;
  max-width: 360px;
  width: 90%;
  max-height: 85vh;
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 0 1px 1px rgba(0,0,0,0.4), 0 10px 30px rgba(0,0,0,0.5), 0 20px 60px rgba(0,0,0,0.35);
  animation: box-pop 0.22s cubic-bezier(0.2,0,0,1);
}
@keyframes box-pop {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0)   scale(1);    }
}

/* Hero bleed: the full square runs edge to edge, uncropped, with the name and
   cost scrimmed over its bottom edge — the tile's treatment, flipped
   bottom-aligned. Everything else stacks below it. */
.modal-hero {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  flex-shrink: 0;
  background: var(--card-plate);
}
.modal-art {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
  display: block;
}
.modal-hero::after {
  content: ''; position: absolute; inset: auto 0 0 0; height: 34%;
  background: linear-gradient(to top, rgba(4,8,7,0.95) 10%, rgba(4,8,7,0.5) 55%, rgba(4,8,7,0));
}
.modal-hero-text { position: absolute; inset: auto 0 0 0; z-index: 2; padding: 0 0.9rem 0.5rem; }
.modal-hero-text .modal-name,
.modal-hero-text .modal-cost-pips,
.modal-hero-text .modal-cost-label { text-shadow: 0 1px 5px rgba(0,0,0,0.95); }
/* The close button rides the top of the hero, so the name has the full width. */
.modal-hero-text .modal-name { padding-right: 0; }

.modal-close { position: absolute; top: 0; right: 0; z-index: 5; background: none; border: none; color: var(--bone-moss); font-size: 1rem; cursor: pointer; line-height: 1; display: flex; align-items: flex-start; justify-content: flex-end; min-width: 40px; min-height: 40px; padding: 0.5rem 0.6rem; text-shadow: 0 1px 4px rgba(0,0,0,0.95); transition: scale 0.1s ease; }
.modal-close:hover { color: var(--splice-green); }
.modal-close:active { scale: 0.9; }
.modal-name { font-size: 1.05rem; font-weight: bold; color: var(--bone-moss); padding-right: 1.8rem; line-height: 1.2; text-wrap: balance; }
.modal-cost-row { display: flex; align-items: baseline; gap: 0.4rem; }
.modal-cost-pips { font-size: 0.68rem; color: var(--toxic-flash); letter-spacing: 0.1em; }
.modal-cost-label { font-size: 0.75rem; color: var(--amber-spore); }

/* Scrollable body */
.modal-body { padding: 0.65rem 0.9rem 0.5rem; display: flex; flex-direction: column; overflow-y: auto; flex: 1; min-height: 0; }

/* Stat bar (bioform) */
.modal-stat-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.3rem 0;
  margin-bottom: 0.55rem;
  border-bottom: 1px solid var(--plating);
}
.modal-stat-bar.bioform .stat-lbl { color: color-mix(in srgb, var(--c-bioform) 55%, var(--cold-steel)); }
.modal-stat-bar.bioform .stat-val { color: var(--c-bioform); font-size: 1.1rem; }
.modal-stat-bar .stat-lbl { font-size: 0.65rem; }
.modal-stat-bar .stat-val-pair { display: flex; align-items: baseline; }

/* Duration bar (catalyst) */
.modal-dur-bar { display: flex; align-items: center; gap: 0.5rem; padding: 0.3rem 0; margin-bottom: 0.55rem; border-bottom: 1px solid var(--plating); }
.modal-dur-bar .dur-lbl  { font-size: 0.65rem; }
.modal-dur-bar .dur-pip  { width: 11px; height: 11px; }
.modal-dur-bar .dur-inf  { font-size: 1.15rem; }

.modal-section { font-size: 0.68rem; color: var(--cold-steel); letter-spacing: 0.09em; text-transform: uppercase; margin: 0.55rem 0 0.25rem; }
.modal-section:first-child { margin-top: 0; }
.modal-ability { font-size: 0.83rem; margin-bottom: 0.3rem; line-height: 1.4; }
.modal-ability-name { color: var(--splice-green); font-weight: bold; }
.modal-ability-desc { color: var(--bone-moss); }
.modal-desc { font-size: 0.83rem; color: var(--bone-moss); line-height: 1.5; word-break: break-word; margin-bottom: 0.35rem; text-wrap: pretty; }
.modal-buff { font-size: 0.83rem; color: var(--splice-green); margin-bottom: 0.2rem; }
.modal-mutation-name { color: var(--toxic-flash); }
.modal-perm-gain { font-size: 0.83rem; color: var(--amber-spore); margin-bottom: 0.2rem; }
.modal-perm-source { font-weight: bold; color: var(--bone-moss); }
.modal-play-hint { font-size: 0.78rem; color: var(--cold-steel); margin-top: 0.6rem; }
.btn-play-modal { background: var(--splice-green); color: var(--void-green); font-weight: bold; padding: 0.4rem 1.2rem; margin-top: 0.65rem; border-radius: 4px; font-family: monospace; font-size: 0.93rem; cursor: pointer; border: none; transition: filter 0.12s, scale 0.1s ease; }
.btn-play-modal:hover { filter: brightness(1.1); }
.btn-play-modal:active:not(:disabled) { scale: 0.96; }
.btn-play-modal:disabled { opacity: 0.4; cursor: not-allowed; filter: none; }

/* Modal affinity border (consistent with card tile) */
.modal-box.has-affinity { border: 2px solid var(--aff-color-1); }
.modal-box.dual-affinity {
  border: 2px solid transparent;
  background:
    linear-gradient(var(--undergrowth), var(--undergrowth)) padding-box,
    linear-gradient(to right, var(--aff-color-1) 43%, var(--aff-color-2) 57%) border-box;
}

.modal-affinity-row { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.modal-affinity-tag { display: flex; align-items: center; gap: 0.25rem; font-size: 0.83rem; color: var(--bone-moss); text-transform: capitalize; }
.modal-affinity-tag .affinity-icon { font-size: 0.95rem; }

/* Modal footer — 3-column, labeled */
.modal-footer {
  border-top: 1px solid var(--plating);
  padding: 0.4rem 0.9rem;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  flex-shrink: 0;
}
.modal-footer-col { display: flex; flex-direction: column; gap: 0.15rem; }
.modal-footer-col--center { align-items: center; }
.modal-footer-col--right  { align-items: flex-end; }
.modal-footer-label { font-size: 0.60rem; color: var(--cold-steel); letter-spacing: 0.08em; text-transform: uppercase; }
.modal-footer-value { font-size: 0.82rem; color: var(--bone-moss); text-transform: capitalize; }

/* Inline modal (generator) — no overlay, no close button */
.inline-modal { max-width: 360px; }

/* ── Filter multiselect (dropdown popover + checkbox list) ─────────────────
   Shared by the lobby filter rows and the admin Card list view. */
.filter-ms { position: relative; display: inline-flex; }
.filter-ms-btn {
  background: var(--void-green);
  border: 1px solid var(--plating);
  color: var(--bone-moss);
  border-radius: 4px;
  padding: 0.35rem 0.6rem;
  font-family: monospace;
  font-size: 0.82rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  transition: border-color 0.12s ease, color 0.12s ease;
}
.filter-ms-btn:hover { border-color: var(--cold-steel); }
.filter-ms-btn.active { border-color: var(--splice-green); color: var(--splice-green); }
.filter-ms-caret { font-size: 0.6rem; opacity: 0.7; }
.filter-ms.open .filter-ms-caret { transform: rotate(180deg); }

.filter-ms-pop {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 60;
  min-width: 170px;
  max-height: 320px;
  overflow-y: auto;
  background: var(--undergrowth);
  border: 1px solid var(--plating);
  border-radius: 5px;
  padding: 0.3rem;
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.45);
}
.filter-ms-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.45rem;
  border-radius: 4px;
  cursor: pointer;
  font-size: 0.8rem;
  color: var(--bone-moss);
  white-space: nowrap;
  user-select: none;
}
.filter-ms-row:hover { background: var(--void-green); }
.filter-ms-all { font-weight: bold; color: var(--cold-steel); text-transform: uppercase; letter-spacing: 0.05em; font-size: 0.72rem; }
.filter-ms-sep { height: 1px; background: var(--plating); margin: 0.25rem 0.2rem; }
.filter-ms-opt-label { display: inline-flex; align-items: center; gap: 0.3rem; text-transform: capitalize; }

.filter-ms-check {
  width: 14px;
  height: 14px;
  border-radius: 3px;
  flex-shrink: 0;
  border: 1px solid var(--cold-steel);
  background: transparent;
  position: relative;
}
.filter-ms-check.on { background: var(--splice-green); border-color: var(--splice-green); }
.filter-ms-check.on::after {
  content: '✓';
  position: absolute;
  inset: 0;
  color: var(--undergrowth);
  font-size: 0.7rem;
  line-height: 14px;
  text-align: center;
  font-weight: bold;
}
.filter-ms-check.some { background: var(--cold-steel); border-color: var(--cold-steel); }
.filter-ms-check.some::after {
  content: '–';
  position: absolute;
  inset: 0;
  color: var(--undergrowth);
  font-size: 0.8rem;
  line-height: 12px;
  text-align: center;
  font-weight: bold;
}
