/*
 * Collected — design system.
 *
 * A single hand-rolled stylesheet (no framework, no build step) implementing the
 * app's dark, minimal, gaming-adjacent visual language:
 *
 *   - near-black warm charcoal surfaces with hairline borders
 *   - one electric-lime accent, used sparingly for emphasis and primary actions
 *   - Chakra Petch (vendored woff2) for display type, humanist system stack for body
 *   - mono uppercase micro-labels ("eyebrows") for table headers / stat captions
 *
 * Everything the old Pico.css layer provided (element defaults, buttons, forms,
 * tables) is defined here instead, scoped through design tokens below.
 */

/* ---------------------------------------------------------------------------
 * Fonts (vendored — no CDN)
 * ------------------------------------------------------------------------- */

@font-face {
  font-family: "Chakra Petch";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/chakra-petch-500.e7f85bd6a6c1.woff2") format("woff2");
}

@font-face {
  font-family: "Chakra Petch";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/chakra-petch-600.91ed2001bdf1.woff2") format("woff2");
}

@font-face {
  font-family: "Chakra Petch";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/chakra-petch-700.a99260bc4f27.woff2") format("woff2");
}

/* ---------------------------------------------------------------------------
 * Design tokens
 * ------------------------------------------------------------------------- */

:root {
  --bg: #0d0f13;
  --surface: #14171e;
  --surface-2: #1a1e27;
  --surface-3: #20252f;
  --border: rgba(255, 255, 255, 0.08);
  --border-strong: rgba(255, 255, 255, 0.16);

  --text: #e9ecf1;
  --text-muted: #9aa2b1;
  --text-faint: #667084;

  /* The accent has two roles. Fill (--accent/--accent-strong): lime surfaces
     such as primary buttons, the brand mark, selection. Text
     (--accent-text/--accent-text-strong): accent-colored text, links, focus
     rings and hairline indicators. In dark they are the same lime; the light
     theme darkens only the text role so accent text keeps AA contrast while
     lime fills stay on brand. */
  --accent: #b8f04f;
  --accent-strong: #ccf876;
  --accent-ink: #141907;
  --accent-dim: rgba(184, 240, 79, 0.12);
  --accent-text: var(--accent);
  --accent-text-strong: var(--accent-strong);

  --danger: #ff8080;
  --danger-dim: rgba(255, 128, 128, 0.1);
  --success: #9fe87a;

  /* Theme-dependent atmosphere: body backdrop glow + grid, the sticky
     header's translucent tint, floating-panel shadows, table row hover. */
  --backdrop-glow: rgba(184, 240, 79, 0.07);
  --backdrop-grid: rgba(255, 255, 255, 0.018);
  --header-tint: rgba(13, 15, 19, 0.82);
  --shadow-panel: 0 16px 40px rgba(0, 0, 0, 0.5);
  --row-hover: rgba(255, 255, 255, 0.025);

  --font-display: "Chakra Petch", "Avenir Next", system-ui, sans-serif;
  --font-body: "Avenir Next", "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace;

  --radius: 10px;
  --radius-sm: 7px;
  --container: 72rem;
  --speed: 160ms;

  color-scheme: dark;
}

/* Light theme (issue #189): same design language on warm near-white surfaces.
   Selected by the bootstrap script in base.html, which sets data-theme from
   the stored preference or prefers-color-scheme before first paint. Values
   were checked against WCAG AA (see spec 189 validation contrast table). */
html[data-theme="light"] {
  --bg: #f3f4f0;
  --surface: #fbfcf9;
  --surface-2: #edefe7;
  --surface-3: #e2e6da;
  --border: rgba(28, 32, 38, 0.12);
  --border-strong: rgba(28, 32, 38, 0.24);

  --text: #1c2026;
  --text-muted: #4d5560;
  --text-faint: #5f6975;

  --accent: #689218;
  --accent-strong: #6e9a1b;
  --accent-ink: #141907;
  --accent-dim: rgba(63, 98, 18, 0.12);
  --accent-text: #3f6212;
  --accent-text-strong: #335010;

  --danger: #b3261e;
  --danger-dim: rgba(179, 38, 30, 0.08);
  --success: #2e7d32;

  --backdrop-glow: rgba(110, 160, 30, 0.1);
  --backdrop-grid: rgba(28, 32, 38, 0.028);
  --header-tint: rgba(243, 244, 240, 0.85);
  --shadow-panel: 0 16px 40px rgba(25, 30, 15, 0.18);
  --row-hover: rgba(28, 32, 38, 0.03);

  color-scheme: light;
}

/* ---------------------------------------------------------------------------
 * Reset + base
 * ------------------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* Fixed atmospheric backdrop: a faint accent glow bleeding down from the top
   plus an ultra-low-alpha grid, so pages have depth without visual noise. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(60rem 28rem at 50% -8rem, var(--backdrop-glow), transparent 70%),
    linear-gradient(var(--backdrop-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--backdrop-grid) 1px, transparent 1px);
  background-size: auto, 44px 44px, 44px 44px;
  mask-image: linear-gradient(to bottom, black 0%, black 30%, transparent 90%);
  -webkit-mask-image: linear-gradient(to bottom, black 0%, black 30%, transparent 90%);
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: 0.01em;
  margin: 0 0 0.6em;
  text-wrap: balance;
}

h1 {
  font-size: clamp(1.7rem, 1.2rem + 2vw, 2.4rem);
  font-weight: 700;
}

h2 {
  font-size: 1.35rem;
}

h3 {
  font-size: 1.05rem;
}

p {
  margin: 0 0 1rem;
}

a {
  color: var(--accent-text);
  text-decoration: none;
  transition: color var(--speed) ease;
}

a:hover {
  color: var(--accent-text-strong);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

small {
  font-size: 0.85em;
  color: var(--text-muted);
}

strong {
  color: var(--text);
}

hr {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 2rem 0;
}

::selection {
  background: var(--accent);
  color: var(--accent-ink);
}

:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Mono uppercase micro-label used for eyebrows, stat captions, table headers. */
.eyebrow {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--accent-text);
}

/* ---------------------------------------------------------------------------
 * Layout shell
 * ------------------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: clamp(1rem, 4vw, 2rem);
}

main.container {
  flex: 1;
  padding-block: clamp(1.5rem, 4vw, 2.75rem) 4rem;
}

.site-footer {
  border-top: 1px solid var(--border);
  padding-block: 1.25rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--text-faint);
}

.site-footer .container {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  justify-content: space-between;
}

.footer-legal {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
}

.footer-legal a {
  color: var(--text-faint);
}

.footer-legal a:hover {
  color: var(--accent-text);
}

/* ---------------------------------------------------------------------------
 * Header + navigation
 * ------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--header-tint);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}

.site-header .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 3.6rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.98rem;
  letter-spacing: 0.04em;
  color: var(--text);
  white-space: nowrap;
}

.brand:hover {
  color: var(--text);
  text-decoration: none;
}

.brand-mark {
  display: inline-grid;
  grid-template-columns: repeat(2, 7px);
  gap: 2px;
  flex: none;
}

.brand-mark i {
  width: 7px;
  height: 7px;
  border-radius: 1.5px;
  background: var(--accent);
}

.brand-mark i:nth-child(3) {
  background: var(--surface-3);
}

/* Right side of the header: inline nav, theme toggle, mobile menu. */
.header-tools {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Icon-only header button: square ghost treatment matching the mobile menu
   summary. The icon reflects the current theme *mode* (data-theme-mode, set by
   the bootstrap script): half-circle for auto, sun for light, moon for dark. */
.theme-toggle {
  width: 2.4rem;
  height: 2.4rem;
  padding: 0;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
}

.theme-toggle:hover {
  background: var(--accent-dim);
  border-color: var(--accent-text);
  color: var(--accent-text);
}

.theme-toggle svg {
  display: none;
}

html[data-theme-mode="auto"] .theme-toggle .icon-auto,
html[data-theme-mode="light"] .theme-toggle .icon-sun,
html[data-theme-mode="dark"] .theme-toggle .icon-moon {
  display: block;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Flex-center each item so the square account icon button doesn't sit on a
   shifted baseline next to the text links. */
.nav-links li {
  display: flex;
  align-items: center;
}

.nav-links a {
  display: inline-block;
  padding: 0.4rem 0.75rem;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: 0.92rem;
}

.nav-links a:hover {
  color: var(--text);
  background: var(--surface-2);
  text-decoration: none;
}

.nav-links a[aria-current="page"] {
  color: var(--text);
}

.nav-links form {
  margin: 0;
}

/* Account dropdown, desktop (issue #150): one avatar button gathers the
   signed-in user's session controls — email, account settings, log out —
   behind a CSS-only <details>, replacing the loose icon + text-pill + icon
   cluster that read as three mismatched controls. Mirrors the mobile .nav-menu
   disclosure; hidden below the mobile breakpoint, where the hamburger carries
   the same rows. */
.account-menu {
  position: relative;
}

/* Avatar trigger: a ghost pill sized to match the theme toggle's height, with
   a chevron that signals the menu and flips when open. */
.account-menu > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  height: 2.4rem;
  padding: 0 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
}

.account-menu > summary::-webkit-details-marker {
  display: none;
}

.account-menu > summary:hover,
.account-menu[open] > summary {
  background: var(--accent-dim);
  border-color: var(--accent-text);
  color: var(--accent-text);
}

.account-menu .account-caret {
  transition: transform var(--speed) ease;
}

.account-menu[open] .account-caret {
  transform: rotate(180deg);
}

.account-menu .account-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 0.6rem);
  min-width: 14rem;
  padding: 0.5rem;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-panel);
  list-style: none;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.account-menu .account-panel a {
  padding: 0.55rem 0.75rem;
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 0.95rem;
}

.account-menu .account-panel a:hover {
  background: var(--surface-3);
  text-decoration: none;
}

.account-menu .account-panel form {
  margin: 0;
}

/* The log-out control reads as a full-width menu row, sized to match the link
   rows above it rather than the compact .btn-sm pill it ships elsewhere. */
.account-menu .account-panel .btn-ghost {
  width: 100%;
  justify-content: flex-start;
  padding: 0.55rem 0.75rem;
  font-size: 0.95rem;
  border-radius: var(--radius-sm);
}

/* Account-settings row (icon + text), shared by the desktop dropdown and the
   mobile hamburger panel. */
.account-link {
  display: flex;
  align-items: center;
  gap: 0.55rem;
}

/* Signed-in email: a non-interactive caption heading the account rows. */
.account-email {
  padding: 0.35rem 0.75rem 0.5rem;
  font-size: 0.8rem;
  color: var(--text-faint);
  word-break: break-all;
}

/* Hairline separating the account rows from the nav links in the mobile panel. */
.nav-divider {
  height: 1px;
  margin: 0.35rem 0.25rem;
  background: var(--border);
}

/* Mobile menu: a CSS-only <details> disclosure that drops a panel below the
   header. Hidden on desktop, where the inline .nav-links list shows instead. */
.nav-menu {
  position: relative;
  display: none;
}

.nav-menu > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.4rem;
  height: 2.4rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
}

.nav-menu > summary::-webkit-details-marker {
  display: none;
}

.nav-menu[open] > summary {
  background: var(--surface-2);
}

.nav-menu .nav-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 0.6rem);
  min-width: 13rem;
  padding: 0.5rem;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-panel);
  list-style: none;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.nav-menu .nav-panel a {
  display: block;
  padding: 0.55rem 0.75rem;
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 0.95rem;
}

.nav-menu .nav-panel a:hover {
  background: var(--surface-3);
  text-decoration: none;
}

/* In the mobile panel the account-settings link reads as a normal row: icon +
   text. Scoped here so it wins over the .nav-panel a { display: block } above. */
.nav-menu .nav-panel .account-link {
  display: flex;
  align-items: center;
  gap: 0.55rem;
}

.nav-menu .nav-panel form {
  margin: 0;
}

.nav-menu .nav-panel button {
  width: 100%;
  text-align: left;
}

@media (max-width: 720px) {
  .site-header .nav-links {
    display: none;
  }

  .nav-menu {
    display: block;
  }
}

/* ---------------------------------------------------------------------------
 * Buttons
 * ------------------------------------------------------------------------- */

button,
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  padding: 0.5rem 1.05rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 0.9rem;
  letter-spacing: 0.02em;
  line-height: 1.3;
  cursor: pointer;
  text-decoration: none;
  transition:
    background var(--speed) ease,
    border-color var(--speed) ease,
    color var(--speed) ease,
    transform var(--speed) ease;
}

button:hover,
.btn:hover {
  background: var(--surface-3);
  border-color: var(--border-strong);
  color: var(--text);
  text-decoration: none;
}

button:active,
.btn:active {
  transform: translateY(1px);
}

button[type="submit"],
.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
}

button[type="submit"]:hover,
.btn-primary:hover {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
  color: var(--accent-ink);
}

/* Quiet button: hairline outline, no fill. Wins over the submit styling above
   so secondary submit-buttons (e.g. "Log out", "Remove") stay quiet. */
.btn-ghost,
button.btn-ghost {
  background: transparent;
  border-color: var(--border-strong);
  color: var(--text-muted);
  font-weight: 500;
}

.btn-ghost:hover,
button.btn-ghost:hover {
  border-color: var(--accent-text);
  color: var(--accent-text);
  background: var(--accent-dim);
}

/* Destructive button: danger-tinted outline. Wins over the submit styling so
   destructive submit-buttons (e.g. "Delete account") read as warnings. */
.btn-danger,
button.btn-danger {
  background: transparent;
  border-color: var(--danger);
  color: var(--danger);
  font-weight: 600;
}

.btn-danger:hover,
button.btn-danger:hover {
  background: var(--danger-dim);
  border-color: var(--danger);
  color: var(--danger);
}

.btn-sm,
button.btn-sm {
  padding: 0.22rem 0.6rem;
  font-size: 0.78rem;
  border-radius: 6px;
}

/* ---------------------------------------------------------------------------
 * Forms
 * ------------------------------------------------------------------------- */

label {
  display: block;
  margin-bottom: 1rem;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--text-muted);
}

input,
select,
textarea {
  font-family: var(--font-body);
  font-size: 0.95rem;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 0.5rem 0.75rem;
  width: 100%;
  margin-top: 0.35rem;
  transition: border-color var(--speed) ease, background var(--speed) ease;
}

input::placeholder {
  color: var(--text-faint);
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--accent-text);
  background: var(--surface);
}

select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%239aa2b1' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.7rem center;
  padding-right: 2rem;
}

input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  margin: 0;
  accent-color: var(--accent);
}

/* Inline checkbox label (e.g. "Show unreleased games"). */
label.check {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  font-size: 0.85rem;
  cursor: pointer;
}

.field-error {
  display: block;
  margin: -0.5rem 0 1rem;
  color: var(--danger);
  font-size: 0.85rem;
}

.help-text {
  display: block;
  margin: -0.5rem 0 1rem;
  color: var(--text-faint);
  font-size: 0.82rem;
}

/* ---------------------------------------------------------------------------
 * Cards
 * ------------------------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: clamp(1.25rem, 3vw, 1.75rem);
  margin-bottom: 1.5rem;
}

.card > header {
  margin-bottom: 1rem;
}

.card > footer {
  margin-top: 1.25rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

/* Narrow centered card for auth and other single-purpose forms. */
.auth-card {
  max-width: 26rem;
  margin: clamp(1rem, 6vh, 4rem) auto 0;
}

.auth-card h1 {
  font-size: 1.45rem;
}

/* Social login (issue #198): provider buttons under the auth forms. */
.social-login {
  margin: 1rem 0;
}

.social-login form {
  margin: 0 0 0.5rem;
}

.social-login button {
  width: 100%;
}

/* "── or ──" rule between the password form and the provider buttons. */
.social-login-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0 0 1rem;
}

.social-login-divider::before,
.social-login-divider::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--border);
}

/* Connected third-party accounts on the connections page. */
.connections-list {
  list-style: none;
  padding: 0;
}

.connections-list li {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
}

.connections-list li form {
  margin: 0 0 0 auto;
}

/* ---------------------------------------------------------------------------
 * Page furniture
 * ------------------------------------------------------------------------- */

.page-head {
  margin-bottom: 1.75rem;
}

.page-head h1 {
  margin-bottom: 0.25rem;
}

.page-head p {
  color: var(--text-muted);
  margin: 0;
}

.back-link {
  display: inline-block;
  margin-bottom: 1.25rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}

.back-link:hover {
  color: var(--accent-text);
}

/* Long-form legal/prose pages (Terms of Service #153, Privacy Policy #154).
 * Constrains the measure for readability and gives headings/lists comfortable
 * rhythm. */
.legal {
  max-width: 70ch;
  color: var(--text);
  line-height: 1.7;
}

.legal h2 {
  margin-top: 2rem;
  margin-bottom: 0.5rem;
  font-size: 1.05rem;
}

.legal p,
.legal ul {
  margin-bottom: 1rem;
  color: var(--text-muted);
}

.legal ul {
  padding-left: 1.25rem;
}

.legal li {
  margin-bottom: 0.4rem;
}

.legal a {
  color: var(--accent-text);
}

/* Bold inline labels (e.g. the Privacy Policy's "What we collect" list) lift
 * back to full-strength text against the muted body copy. */
.legal strong {
  color: var(--text);
}

/* Flash messages. */
.alert {
  display: block;
  padding: 0.7rem 1rem;
  margin-bottom: 1.25rem;
  border: 1px solid var(--border-strong);
  border-left: 3px solid var(--accent-text);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: 0.92rem;
}

.alert.message-success {
  border-left-color: var(--success);
}

.alert.message-error,
.alert.alert-danger {
  border-left-color: var(--danger);
  background: var(--danger-dim);
}

.text-danger {
  color: var(--danger);
}

/* Definition list for game / profile metadata. */
.meta-list {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.45rem 1.5rem;
  margin: 1.25rem 0;
}

.meta-list dt {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-faint);
  padding-top: 0.2rem;
}

.meta-list dd {
  margin: 0;
}

@media (max-width: 540px) {
  .meta-list {
    grid-template-columns: 1fr;
    gap: 0.1rem;
  }

  .meta-list dd {
    margin-bottom: 0.7rem;
  }
}

/* ---------------------------------------------------------------------------
 * Filter bars (catalog + collection)
 * ------------------------------------------------------------------------- */

.filter-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem;
  margin-bottom: 1.5rem;
}

/* The row of search input + selects + submit. Wraps gracefully; the text input
   takes the leftover space. Both the catalog's <div role="search"> and the
   collection's <fieldset role="group"> render as this row. */
.filter-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  border: 0;
  padding: 0;
  margin: 0;
}

.filter-row input[type="search"] {
  flex: 1 1 14rem;
  margin: 0;
}

.filter-row select {
  flex: 0 1 auto;
  width: auto;
  margin: 0;
}

.filter-row button {
  flex: none;
}

@media (max-width: 576px) {
  .filter-row > * {
    flex: 1 1 100%;
    width: 100%;
  }
}

/* Secondary row under the main filter row: toggle, column picker, reset. */
.filter-extras {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.25rem;
  margin-top: 0.85rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--border);
}

.filter-extras .spacer {
  flex: 1;
}

/* Column picker: <details> disclosure as a popover of checkboxes. */
.column-picker {
  position: relative;
}

.column-picker > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  font-size: 0.82rem;
  color: var(--text-muted);
}

.column-picker > summary::-webkit-details-marker {
  display: none;
}

.column-picker > summary::after {
  content: "";
  width: 8px;
  height: 5px;
  background: currentColor;
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  transition: transform var(--speed) ease;
}

.column-picker[open] > summary {
  border-color: var(--accent-text);
  color: var(--accent-text);
}

.column-picker[open] > summary::after {
  transform: rotate(180deg);
}

.column-picker .picker-panel {
  position: absolute;
  left: 0;
  top: calc(100% + 0.5rem);
  z-index: 30;
  min-width: 13rem;
  padding: 0.75rem 0.9rem;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-panel);
}

.column-picker .picker-panel label.check {
  display: flex;
  margin-bottom: 0.45rem;
}

.column-picker .picker-panel label.check:last-child {
  margin-bottom: 0;
}

/* "Reset columns to default" link at the bottom of the picker (issue #174). */
.column-picker .picker-panel .picker-reset {
  display: block;
  margin-top: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--border);
  text-align: center;
  white-space: nowrap;
}

/* The column picker configures the list table's columns, so it is meaningless in
   grid mode — hide it whenever the grid radio is checked (the mirror image of the
   grid-only Sort menu, which the swapped results partial omits in list mode). The
   picker sits in the static filter form OUTSIDE the HTMX swap region, so a template
   conditional can't re-evaluate it on a live toggle; keying off the radio's
   :checked state covers first paint, live swaps, and the no-JS path alike. Scoped
   to .filter-extras so the toolbar's Sort menu (also a .column-picker) is
   unaffected, and display:none (not removal) keeps the column checkboxes
   serializing so the selection survives a round-trip through grid mode. */
.filter-extras:has(.view-toggle input[name="view"][value="grid"]:checked) > .column-picker {
  display: none;
}

/* List/grid view toggle (issue #240): radios styled as a segmented control. The
   inputs stay in the document (visually hidden, not display:none) so they remain
   focusable and the form still serializes the checked mode. */
.view-toggle {
  display: inline-flex;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.view-toggle .seg {
  position: relative;
  margin: 0; /* cancel the global label margin-bottom */
}

.view-toggle .seg input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}

.view-toggle .seg span {
  display: block;
  padding: 0.3rem 0.8rem;
  font-size: 0.82rem;
  color: var(--text-muted);
  transition:
    background var(--speed) ease,
    color var(--speed) ease;
}

.view-toggle .seg + .seg span {
  border-left: 1px solid var(--border);
}

.view-toggle .seg input:checked + span {
  background: var(--surface-2);
  color: var(--accent-text);
}

.view-toggle .seg input:focus-visible + span {
  outline: 2px solid var(--accent-text);
  outline-offset: -2px;
}

/* ---------------------------------------------------------------------------
 * Results toolbar + tables + pagination
 * ------------------------------------------------------------------------- */

.results-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}

.results-toolbar > p {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

.results-toolbar select {
  width: auto;
  margin: 0;
  padding-block: 0.3rem;
  font-size: 0.82rem;
}

/* Right-hand toolbar cluster: the grid-mode Sort menu + the page-size selector. */
.toolbar-controls {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

/* Grid-mode "Sort" menu (issue #240): the column-picker <details> popover
   restyled as a list of sort links. */
.sort-picker .picker-panel {
  left: auto;
  right: 0;
  min-width: 10.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}

.sort-picker .picker-panel a {
  font-size: 0.85rem;
  color: var(--text-muted);
  white-space: nowrap;
}

.sort-picker .picker-panel a:hover {
  color: var(--accent-text);
  text-decoration: none;
}

.sort-picker .picker-panel a[aria-current="true"] {
  color: var(--accent-text);
  font-weight: 600;
}

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.93rem;
}

thead th {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  text-align: left;
  color: var(--text-faint);
  padding: 0.7rem 0.9rem;
  border-bottom: 1px solid var(--border-strong);
  white-space: nowrap;
}

thead th a {
  color: inherit;
}

thead th a:hover {
  color: var(--accent-text);
  text-decoration: none;
}

thead th[aria-sort="ascending"] a,
thead th[aria-sort="descending"] a {
  color: var(--accent-text);
}

tbody td {
  padding: 0.62rem 0.9rem;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

tbody tr:last-child td {
  border-bottom: 0;
}

tbody tr {
  transition: background var(--speed) ease;
}

tbody tr:hover {
  background: var(--row-hover);
}

tbody td a {
  color: var(--text);
  font-weight: 500;
}

tbody td a:hover {
  color: var(--accent-text);
}

/* Physical/digital availability badge in the catalog's Availability column. */
.availability-badge {
  display: inline-block;
  padding: 0.1rem 0.55rem;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-size: 0.78rem;
  color: var(--text-muted);
  white-space: nowrap;
}

/* No distribution-format evidence (issue #222): visually de-emphasized so an
   honest "we don't know" reads differently from an evidence-backed format. */
.availability-badge--unknown {
  border-style: dashed;
  font-style: italic;
}

/* Inline action cluster inside table cells (Edit / Remove …). */
.row-actions {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  white-space: nowrap;
}

.row-actions form {
  display: inline;
  margin: 0;
}

.pagination ul {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--text-muted);
}

.pagination a {
  display: inline-block;
  padding: 0.35rem 0.85rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
}

.pagination a:hover {
  border-color: var(--accent-text);
  color: var(--accent-text);
  text-decoration: none;
}

.empty-state {
  padding: 2.5rem 1rem;
  text-align: center;
  color: var(--text-muted);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
}

/* BYO-LLM guidance panel (#234): the empty-state shell with readable,
 * left-aligned steps for the agent workflow. */
.byo-guidance {
  text-align: left;
  max-width: 46rem;
}

.byo-guidance h2 {
  margin-top: 0;
}

.byo-steps {
  margin: 0.75rem 0;
  padding-left: 1.4rem;
  display: grid;
  gap: 0.5rem;
}

/* ---------------------------------------------------------------------------
 * Quick-add control (catalog rows + game detail)
 * ------------------------------------------------------------------------- */

.quick-add {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.82rem;
  white-space: nowrap;
}

.quick-add-form {
  display: inline;
  margin: 0;
}

.quick-add-done {
  color: var(--success);
}

.quick-add-done a {
  font-size: 0.9em;
}

/* The shared control rendered above the add-to-collection form on the game
   detail page needs block spacing it doesn't get inside a table cell. */
.card .quick-add {
  margin-bottom: 1.1rem;
}

/* ---------------------------------------------------------------------------
 * Home / landing page
 * ------------------------------------------------------------------------- */

.hero {
  padding-block: clamp(2.5rem, 8vw, 5.5rem) clamp(2rem, 6vw, 4rem);
  max-width: 46rem;
}

.hero .eyebrow {
  margin-bottom: 1.1rem;
}

.hero h1 {
  font-size: clamp(2.1rem, 1.2rem + 4.5vw, 3.6rem);
  margin-bottom: 1rem;
}

.hero h1 .accent {
  color: var(--accent-text);
}

.hero .lede {
  font-size: 1.08rem;
  color: var(--text-muted);
  max-width: 36rem;
  margin-bottom: 1.75rem;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

/* Staggered load-in for the hero (motion-safe only). */
@media (prefers-reduced-motion: no-preference) {
  .hero > * {
    animation: rise 0.55s cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }

  .hero > *:nth-child(2) {
    animation-delay: 70ms;
  }

  .hero > *:nth-child(3) {
    animation-delay: 140ms;
  }

  .hero > *:nth-child(4) {
    animation-delay: 210ms;
  }
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

.stat-strip {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: clamp(2.5rem, 6vw, 4rem);
}

@media (max-width: 640px) {
  .stat-strip {
    grid-template-columns: 1fr;
  }
}

.stat {
  background: var(--surface);
  padding: 1.4rem 1.5rem;
}

.stat .stat-value {
  display: block;
  font-family: var(--font-display);
  font-size: 2.1rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--text);
}

.stat .stat-label {
  display: block;
  margin-top: 0.3rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--text-faint);
}

/* Collection stats dashboard: muted card sub-heading + distribution bars. */

.card-note {
  margin: 0.35rem 0 0;
  color: var(--text-muted);
  font-size: 0.88rem;
}

.dist-cell {
  width: 45%;
  min-width: 10rem;
}

.dist-bar {
  display: inline-block;
  vertical-align: middle;
  width: calc(100% - 4rem);
  height: 0.45rem;
  margin-right: 0.6rem;
  background: var(--surface-3);
  border-radius: 999px;
  overflow: hidden;
}

.dist-bar span {
  display: block;
  height: 100%;
  background: var(--accent);
  border-radius: inherit;
}

.home-section {
  margin-bottom: clamp(2.5rem, 6vw, 4rem);
}

.home-section > .section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.25rem;
}

.home-section > .section-head h2 {
  margin: 0;
}

.home-section > .section-head a {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.05em;
}

.game-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13.5rem, 1fr));
  gap: 0.9rem;
}

.game-card {
  display: block;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.1rem 1.2rem;
  color: var(--text);
  transition:
    border-color var(--speed) ease,
    transform var(--speed) ease,
    background var(--speed) ease;
}

.game-card:hover {
  border-color: var(--accent-text);
  background: var(--surface-2);
  transform: translateY(-2px);
  text-decoration: none;
  color: var(--text);
}

.game-card .game-title {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.98rem;
  margin-bottom: 0.35rem;
}

.game-card .game-meta {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--text-faint);
}

.feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 0.9rem;
}

.feature-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.4rem 1.5rem;
}

.feature-card .feature-index {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  color: var(--accent-text);
  margin-bottom: 0.8rem;
}

.feature-card h3 {
  margin-bottom: 0.4rem;
}

.feature-card p {
  margin: 0;
  font-size: 0.92rem;
  color: var(--text-muted);
}

/* ---------------------------------------------------------------------------
 * HTMX swap polish + motion preferences
 * ------------------------------------------------------------------------- */

#catalog-results.htmx-swapping,
#collection-results.htmx-swapping {
  opacity: 0.4;
  transition: opacity 120ms ease;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/*
 * Game cover art on detail pages (spec 180).
 *
 * A fixed aspect ratio + object-fit keeps the footprint identical whether a real
 * cover or the neutral placeholder is shown, so the layout never shifts between
 * games with and without art. The image is capped so a large source image cannot
 * dominate the page, and aspect ratio is preserved (never stretched/cropped).
 */
.game-cover {
  display: block;
  width: 100%;
  max-width: 12rem;
  aspect-ratio: 3 / 4;
  height: auto;
  object-fit: contain;
  margin: 0 0 1rem;
  border-radius: var(--radius-sm);
}

/* ---------------------------------------------------------------------------
 * Cover-art browse grid (issue #240) — the catalog/collection "Grid" view
 * ------------------------------------------------------------------------- */

/* Fixed column counts at breakpoints (issue #264), not auto-fill: every count
   (2/3/4/6) divides the grid page sizes (24/48/96), so each page renders only
   complete rows at any viewport width — no orphan one-card last row. Keep the
   counts and the page sizes in apps/catalog/pagination.py in sync. */
.browse-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.9rem;
}

@media (min-width: 40rem) {
  .browse-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 56rem) {
  .browse-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

@media (min-width: 75rem) {
  .browse-grid {
    grid-template-columns: repeat(6, 1fr);
  }
}

.browse-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  transition:
    border-color var(--speed) ease,
    transform var(--speed) ease;
}

.browse-card:hover {
  border-color: var(--accent-text);
  transform: translateY(-2px);
}

.browse-card .browse-card-cover {
  display: block;
  background: var(--surface-3);
}

/* The shared cover partial is sized for the detail page (capped width, bottom
   margin, contain). Inside a card it fills the full card width edge to edge;
   object-fit: cover keeps the 3:4 tiles uniform across covers whose source
   ratios vary slightly (IGDB art is 3:4 already, Commons art is close). */
.browse-card .game-cover {
  max-width: none;
  margin: 0;
  border-radius: 0;
  object-fit: cover;
}

.browse-card .browse-card-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 0.35rem;
  padding: 0.7rem 0.8rem 0.8rem;
}

.browse-card .browse-card-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  line-height: 1.25;
  color: var(--text);
}

.browse-card .browse-card-title:hover {
  color: var(--accent-text);
  text-decoration: none;
}

.browse-card .browse-card-meta {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--text-faint);
}

/* Pin the quick-add / Edit-Remove cluster to the card's bottom edge so action
   rows align across a row of cards with different title lengths. */
.browse-card .browse-card-actions {
  margin-top: auto;
  padding-top: 0.45rem;
}

/* The shared quick-add control is laid out for a table cell (nowrap); let it
   wrap inside a narrow card instead of overflowing. */
.browse-card .quick-add {
  flex-wrap: wrap;
  white-space: normal;
}

/* ---------------------------------------------------------------------------
 * Recommendations page (issues #21 + #22)
 * ------------------------------------------------------------------------- */

.recs-trigger {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-bottom: 1.5rem;
}

/* htmx ships the .htmx-indicator visibility toggling; this just styles the note. */
.recs-loading {
  color: var(--text-muted);
  font-size: 0.9rem;
}

.recs-meta {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
  color: var(--text-muted);
  font-size: 0.85rem;
}

.recs-badge {
  padding: 0.1rem 0.55rem;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-size: 0.78rem;
}

.recs-badge-fallback {
  color: var(--accent-text);
  border-color: var(--accent-text);
}

.recs-badge-agent {
  color: var(--accent-text);
}

.recs-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.9rem;
}

.recs-card {
  display: flex;
  gap: 1rem;
  padding: 1rem 1.2rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.recs-rank {
  font-family: var(--font-display);
  font-size: 1.4rem;
  color: var(--text-muted);
  min-width: 2rem;
  text-align: center;
}

.recs-body {
  flex: 1;
  min-width: 0;
}

.recs-title-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
}

.recs-title {
  font-family: var(--font-display);
  font-size: 1.05rem;
}

.recs-score {
  font-family: var(--font-mono);
  font-weight: 700;
  color: var(--accent-text);
}

.recs-genres {
  margin: 0.15rem 0 0;
  color: var(--text-muted);
  font-size: 0.82rem;
}

.recs-rationale {
  margin: 0.5rem 0 0.75rem;
}

.recs-actions {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}

.recs-feedback {
  display: inline-flex;
  gap: 0.25rem;
}

.recs-feedback form {
  display: inline;
  margin: 0;
}

.recs-thumb {
  filter: grayscale(1);
  opacity: 0.65;
}

.recs-thumb:hover {
  opacity: 1;
}

.recs-thumb-active {
  filter: none;
  opacity: 1;
  border-color: var(--accent-text);
}

.recs-error {
  padding: 1rem 1.2rem;
  border: 1px solid var(--danger);
  border-radius: var(--radius);
  color: var(--danger);
}

.recs-error p {
  margin: 0.35rem 0 0;
  color: var(--text);
}
