/* Theme tokens. Light is the default; dark is opt-in via
   `<html data-theme="dark">` (set by public/theme.js and the inline init
   script in views/index.ejs). Every color used in the app should be
   expressed through one of these variables so both themes stay consistent. */
:root {
  --bg: #f2f4f7;
  --panel: #ffffff;
  --panel-inset: #eef1f5;
  --line: #d5d8de;
  --ink: #1a1d24;
  --ink-dim: #5a6270;
  --accent: #3562d6;
  --accent-ink: #ffffff;
  --backdrop: rgba(20, 24, 34, 0.35);
  --danger-fg: #b3261e;
  --danger-fg-strong: #7a1810;
  --danger-line: #d6a4a0;
  --danger-tint: color-mix(in srgb, #b3261e 8%, transparent);
  --radius: 10px;
}

[data-theme="dark"] {
  --bg: #14161a;
  --panel: #1c1f26;
  --panel-inset: #0e1013;
  --line: #2a2f3a;
  --ink: #e7e9ee;
  --ink-dim: #9aa2b1;
  --accent: #5b8def;
  --accent-ink: #0b0f18;
  --backdrop: rgba(0, 0, 0, 0.65);
  --danger-fg: #f47272;
  --danger-fg-strong: #ffb0b0;
  --danger-line: #6a2b2b;
  --danger-tint: color-mix(in srgb, #f47272 12%, transparent);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.4 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

/* ── Top bar ──────────────────────────────────────────────── */
.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.9rem 1.25rem;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}
.topbar h1 {
  margin: 0;
  font-size: 1.15rem;
  letter-spacing: 0.02em;
}
/* Reserve enough width for the count line — even when it grows to
   "N cards (M total)" with 5-digit values — so the search input to its right
   stays at a fixed x-position instead of shifting with the count text. */
.count {
  color: var(--ink-dim);
  font-size: 0.85rem;
  min-width: 16rem;
  display: inline-block;
}
.count-total { opacity: 0.75; }

/* Search — placeholder vanishes on focus per the spec. */
.search-form {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}
.search-wrap {
  position: relative;
  display: inline-block;
  width: 16rem;
  max-width: 40vw;
}
.search {
  font: inherit;
  color: var(--ink);
  background: var(--panel-inset);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.35rem 1.75rem 0.35rem 0.6rem;
  width: 100%;
}
.search::placeholder { color: var(--ink-dim); }
.search:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.search:focus::placeholder { color: transparent; }

.search-clear {
  position: absolute;
  top: 50%;
  right: 0.35rem;
  transform: translateY(-50%);
  width: 1.35rem;
  height: 1.35rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: 50%;
  color: var(--ink-dim);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}
.search-clear:hover { color: var(--ink); background: var(--line); }
.search-clear[hidden] { display: none; }

/* Filter checkboxes — compact chip-like toggles beside the search input. */
.filter-flags {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}
.filter-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.8rem;
  color: var(--ink-dim);
  padding: 0.2rem 0.55rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel-inset);
  cursor: pointer;
  user-select: none;
}
.filter-toggle:hover { border-color: var(--accent); color: var(--ink); }
.filter-toggle input { margin: 0; cursor: pointer; }
.filter-toggle:has(input:checked) {
  border-color: var(--accent);
  color: var(--ink);
  background: color-mix(in srgb, var(--accent) 15%, var(--panel-inset));
}

/* Right-side action cluster (theme toggle + import). Held together in a
   flex row and pushed to the far right of the topbar — this replaces the
   `margin-left: auto` that used to sit on `.import-trigger` directly. */
.topbar-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.theme-toggle {
  padding: 0.35rem 0.5rem;
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
  font: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
.theme-toggle:hover { border-color: var(--accent); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Both icons ship inside the button; CSS picks which one to show based on
   the active theme so JS never has to touch the DOM contents. The icon
   shown at any time represents the *action* the click will perform:
   moon in light mode (click → dark), sun in dark mode (click → light). */
.theme-toggle svg {
  width: 1.05rem;
  height: 1.05rem;
  display: block;
}
.theme-toggle .icon-sun { display: none; }
[data-theme="dark"] .theme-toggle .icon-moon { display: none; }
[data-theme="dark"] .theme-toggle .icon-sun { display: block; }

/* Sort button + dropdown. Visually a sibling of the theme toggle; the dropdown
   is absolutely positioned so it hangs below the button without shifting the
   topbar layout when open. */
.sort-menu-wrap {
  position: relative;
  display: inline-block;
}
.sort-toggle {
  padding: 0.35rem 0.5rem;
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
  font: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
.sort-toggle:hover { border-color: var(--accent); }
.sort-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.sort-toggle svg { width: 1.05rem; height: 1.05rem; display: block; }

.sort-menu {
  position: absolute;
  top: calc(100% + 0.35rem);
  right: 0;
  z-index: 20;
  margin: 0;
  padding: 0.3rem;
  list-style: none;
  min-width: 13rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}
.sort-menu[hidden] { display: none; }
.sort-menu li { margin: 0; }
.sort-menu button {
  width: 100%;
  text-align: left;
  padding: 0.4rem 0.55rem;
  background: transparent;
  color: var(--ink);
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font: inherit;
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.sort-menu button:hover { background: var(--panel-inset); }
.sort-menu button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.sort-check {
  width: 0.9rem;
  display: inline-flex;
  justify-content: center;
  color: var(--accent);
  font-weight: 700;
  visibility: hidden;
}
.sort-menu button[aria-checked="true"] .sort-check { visibility: visible; }

/* "+" scan trigger. Same visual weight as the theme + sort buttons so the
   trio reads as one action cluster. Rendered as an <a> because it navigates
   to a full page (/scan), not a modal. */
.scan-trigger {
  padding: 0.35rem 0.5rem;
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
  font: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  text-decoration: none;
}
.scan-trigger:hover { border-color: var(--accent); }
.scan-trigger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.scan-trigger svg { width: 1.05rem; height: 1.05rem; display: block; }

/* Scan works via the device camera, which only makes sense on a touch-primary
   client (phone, tablet). Desktops with hover-capable pointers can't feed a
   card to the camera meaningfully, so the entry point is hidden there. */
@media (hover: hover) and (pointer: fine) {
  .scan-trigger { display: none; }
}

/* ── Grid ─────────────────────────────────────────────────── */
/* The grid sits inside a centered column so it doesn't hug the left edge on
   wide monitors. 1400px is enough headroom for 5 cards + gaps + padding. */
main {
  padding: 1.25rem;
  max-width: 1400px;
  margin: 0 auto;
}

.grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 1rem;
}
@media (max-width: 900px) { .grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 600px) { .grid { grid-template-columns: repeat(2, 1fr); } }

/* IntersectionObserver target for lazy-loading the next batch. */
.scroll-sentinel { height: 1px; margin-top: 1rem; }

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color 0.12s ease, transform 0.12s ease;
  cursor: pointer;
}
.card:hover { border-color: var(--accent); transform: translateY(-2px); }
.card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.thumb {
  aspect-ratio: 5 / 7;              /* trading-card proportions */
  background: var(--panel-inset);
  display: flex;
  align-items: center;
  justify-content: center;
}
.thumb img { width: 100%; height: 100%; object-fit: contain; display: block; }
.noimg { color: var(--ink-dim); font-size: 0.75rem; }

.meta { padding: 0.55rem 0.65rem; }
.name { font-weight: 600; font-size: 0.9rem; }
.sub  { color: var(--ink-dim); font-size: 0.78rem; margin-top: 0.15rem; }
.team { color: var(--ink-dim); font-size: 0.72rem; margin-top: 0.1rem; }

.empty { color: var(--ink-dim); }
.empty code { background: var(--panel); padding: 0.1rem 0.35rem; border-radius: 4px; }

@media (prefers-reduced-motion: reduce) {
  .card { transition: none; }
}

/* ── Details modal ────────────────────────────────────────── */
body.modal-open { overflow: hidden; }

.details {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
.details[hidden] { display: none; }

.details-backdrop {
  position: absolute;
  inset: 0;
  background: var(--backdrop);
}

.details-panel {
  position: relative;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  width: min(1200px, 100%);
  max-height: calc(100vh - 3rem);
  overflow: auto;
  padding: 1.5rem 1.75rem 1.75rem;
}

.details-close {
  position: absolute;
  top: 0.5rem;
  right: 0.75rem;
  background: transparent;
  border: none;
  color: var(--ink-dim);
  font-size: 1.75rem;
  line-height: 1;
  padding: 0.25rem 0.5rem;
  cursor: pointer;
  border-radius: var(--radius);
}
.details-close:hover { color: var(--ink); background: var(--line); }

.details-grid {
  display: grid;
  grid-template-columns: minmax(240px, 320px) 1fr;
  gap: 1.75rem;
  align-items: start;
}

.col { display: flex; flex-direction: column; gap: 0.6rem; min-width: 0; }
.col-title {
  margin: 0.35rem 0 0.15rem;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-dim);
}
.col-title:first-child { margin-top: 0; }

.details-col { gap: 0.75rem; }

.field-row {
  display: grid;
  gap: 0.75rem;
  align-items: end;
}
.field-row.cols-1 { grid-template-columns: 1fr; }
.field-row.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.field-row.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

.image-col { align-items: stretch; }
.image-flags {
  margin-top: 0.75rem;
  justify-content: flex-start;
}
.detail-image {
  aspect-ratio: 5 / 7;
  background: var(--panel-inset);
  border-radius: var(--radius);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.detail-image img { width: 100%; height: 100%; object-fit: contain; display: block; }

.side-toggle {
  margin-top: 0.75rem;
  padding: 0.55rem 1rem;
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
  font: inherit;
}
.side-toggle:hover:not(:disabled) { border-color: var(--accent); }
.side-toggle:disabled { opacity: 0.5; cursor: not-allowed; }

.col label {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: 0.75rem;
  color: var(--ink-dim);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.col label input[type="text"],
.col label textarea {
  font: 0.9rem/1.35 inherit;
  color: var(--ink);
  background: var(--panel-inset);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.45rem 0.6rem;
  text-transform: none;
  letter-spacing: normal;
  width: 100%;
  resize: vertical;
}
.col label input[readonly],
.col label textarea[readonly] {
  cursor: not-allowed;
  opacity: 0.55;
}
.col label input:focus,
.col label textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.flags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 0.35rem;
}
.flag {
  flex-direction: row !important;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.8rem !important;
  text-transform: none !important;
  letter-spacing: normal !important;
  color: var(--ink) !important;
}

.details-footer {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
  display: flex;
  justify-content: flex-end;
}

.details-delete {
  font: inherit;
  padding: 0.5rem 1rem;
  background: transparent;
  color: var(--danger-fg);
  border: 1px solid var(--danger-line);
  border-radius: var(--radius);
  cursor: pointer;
}
.details-delete:hover {
  background: var(--danger-tint);
  border-color: var(--danger-fg);
  color: var(--danger-fg-strong);
}
.details-delete:focus-visible {
  outline: 2px solid var(--danger-fg);
  outline-offset: 2px;
}

@media (max-width: 900px) {
  .details-grid { grid-template-columns: 1fr; }
}

/* ── Mobile details modal ────────────────────────────────────
   The desktop layout stacks image-on-top / fields-below at ≤900px, which
   works on tablets. On phones the 5:7 image still eats the whole viewport
   before you see a single form field. Cap the image to ~35vh so the top
   of the form (name/team/etc.) is visible on load. The image stays
   tap-scrollable if the user wants to see it larger. */
@media (max-width: 600px) {
  .details { padding: 0.5rem; }
  .details-panel {
    max-height: calc(100vh - 1rem);
    padding: 1rem 0.9rem 1.25rem;
  }
  .details-grid { gap: 0.9rem; }
  .detail-image { max-height: 35vh; }
  .detail-image img { object-position: center top; }
  .image-col { gap: 0.4rem; }
  .side-toggle {
    margin-top: 0.4rem;
    padding: 0.4rem 0.75rem;
    font-size: 0.85rem;
  }
  .image-flags { margin-top: 0.4rem; gap: 0.5rem 0.85rem; }
  .details-col { gap: 0.5rem; }
  .col-title { font-size: 0.75rem; margin: 0.25rem 0 0.1rem; }
  .field-row { gap: 0.5rem; }
  /* Three inputs across at 380px is too cramped; drop to two so the
     labels and values stay readable. */
  .field-row.cols-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ── Mobile topbar ───────────────────────────────────────────
   Below 600px the topbar stacks: title row, then a full-width search,
   then the filter chips wrap under it. The import button is hidden —
   picking a JSON export on a phone isn't a real workflow. The theme
   toggle stays visible so the user can still switch themes. */
@media (max-width: 600px) {
  .topbar {
    flex-wrap: wrap;
    gap: 0.5rem 0.75rem;
    padding: 0.7rem 1rem;
  }
  .topbar h1 { font-size: 1rem; }
  .count { min-width: 0; flex: 1; text-align: right; }
  .search-form {
    order: 2;
    flex-basis: 100%;
    gap: 0.5rem;
  }
  .search-wrap { width: 100%; max-width: none; }
  .filter-flags { width: 100%; }
  .import-trigger { display: none; }
}
