/* Design system — SSR price-guide pages. shadcn-style semantic token pairs
   (background/foreground); dark mode swaps :root values via .dark /
   prefers-color-scheme. */

/* Preflight reset loads before this file (static/preflight.css,
   base.html.j2); tokens assume that baseline. */

:root {
  /* Page shell */
  --background: #ffffff;
  --foreground: #111827;

  /* Elevated surfaces (cards, panels) */
  --card: #ffffff;
  --card-foreground: #111827;

  /* Floating surfaces (popovers, dropdowns) */
  --popover: #ffffff;
  --popover-foreground: #111827;

  /* High-emphasis actions & brand */
  --primary: var(--color-primary-600);
  --primary-hover: var(--color-primary-500);
  --primary-foreground: #ffffff;
  --primary-light: var(--color-primary-100);
  --primary-text: var(--color-primary-900, #4c1d95);
  --primary-dark: var(--color-primary-950);

  /* Lower-emphasis actions */
  --secondary: #f3f4f6;
  --secondary-foreground: #374151;

  /* Subtle / muted content */
  --muted: #f9fafb;
  --muted-foreground: #374151;

  /* Interactive hover/focus states */
  --accent: #f3f4f6;
  --accent-foreground: #111827;

  /* Destructive actions */
  --destructive: #dc2626;
  --destructive-foreground: #ffffff;

  /* Borders & separators */
  --border: #e5e7eb;
  --input: #d1d5db;

  /* Focus rings */
  --ring: var(--color-primary-300);

  /* Feedback */
  --gain-up: #2563eb;
  --gain-down: #dc2626;
  --gain-flat: #9ca3af;
  --error: #f87171;
  --success: #34d399;

  /* Typography scale */
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5rem;
  --text-3xl: 1.875rem;
  --text-4xl: 3rem;

  /* Layout */
  --nav-height-sm: 3rem;
  --nav-height: 4rem;
  /* --nav-height is the nav's CONTENT box; .site-nav adds a 1px
     border-bottom, so anything docking below the nav must clear 65px. Dock
     off --nav-dock, never --nav-height — otherwise a 1px seam of page
     background shows above every sub-nav. */
  --nav-border: 1px;
  --nav-dock: calc(var(--nav-height) + var(--nav-border));
  --nav-dock-sm: calc(var(--nav-height-sm) + var(--nav-border));
  --content-max: 80rem;
  --radius: 0.5rem;
  --radius-thumb: 0.25rem;
  --radius-lg: 0.75rem;
  --radius-full: 9999px;

  /* Unified field tokens (inputs, buttons, selects, toggles) */
  --field-height: 2.25rem;
  --field-px: 0.75rem;
  --field-py: 0.375rem;
  --field-font: 13px;
  --field-radius: var(--radius);
  --field-border: var(--input);
  --field-focus-ring: 0 0 0 3px color-mix(in srgb, var(--ring) 25%, transparent);

  /* Numeric display — Inter with tabular figures for aligned columns */
  --font-numeric: "Inter", ui-sans-serif, system-ui, sans-serif;

  /* Admin stat-tile line-boxes: skeleton and loaded element read the same
     vars so their heights can never drift. Values match measured renders:
     .admin-stat-value 1.375rem × 1.15 ≈ 1.58rem, labels 0.75rem × 1.5 ≈
     1.125rem. */
  --stat-value-line: 1.58rem;
  --stat-label-line: 1.125rem;

  /* Logo */
  --logo-fill: #f7f3fd;
  --logo-color: var(--color-primary-900, #4c1d95);
  /* Eye/cutout fill must contrast with --logo-color in BOTH modes — the AFG
     eyes sit on a band filled with --logo-color. */
  --logo-eye-fill: #f7f3fd;

  /* Subtle surface tokens — the same color-mix expressions repeat 10–20×
     each; one var = one palette tweak and a single dark-mode override point. */
  --bg-muted-subtle:        color-mix(in srgb, var(--muted-foreground) 14%, transparent);
  --bg-muted-hover:         color-mix(in srgb, var(--muted-foreground) 10%, transparent);
  --bg-primary-subtle:      color-mix(in srgb, var(--primary) 12%, transparent);
  --bg-destructive-subtle:  color-mix(in srgb, var(--destructive) 12%, transparent);
  --bg-success-subtle:      color-mix(in srgb, var(--success) 12%, transparent);
  --border-muted-subtle:    color-mix(in srgb, var(--muted-foreground) 22%, transparent);
}

/* Near-black surfaces with a subtle cool tint (linear.app-style), not flat
   gray. */
.dark,
[data-theme="dark"] {
  --background: lch(1.8% 0 272);
  --foreground: lch(97% 0.5 272);
  --card: lch(4.5% 0.75 272);
  --card-foreground: lch(97% 0.5 272);
  --popover: lch(6% 0.75 272);
  --popover-foreground: lch(97% 0.5 272);
  --secondary: lch(10% 1 272);
  --secondary-foreground: lch(80% 1 272);
  --muted: lch(4.5% 0.75 272);
  --muted-foreground: lch(55% 1 272);
  --accent: lch(10% 1 272);
  --accent-foreground: lch(97% 0.5 272);
  --destructive: #dc2626;
  --destructive-foreground: #fafafa;
  --border: lch(11% 2.91 272);
  --input: lch(16% 2 272);
  --ring: var(--color-primary-400);
  --primary-text: var(--color-primary-300);
  --primary-light: lch(10% 3 272);

  /* Dark logo: outline-only, no fill */
  --logo-fill: transparent;
  --logo-color: var(--muted-foreground);
  /* Eye fill stays bright — see the :root definition. */
  --logo-eye-fill: var(--foreground);
}

.sm-up {
  display: none;
}
@media (min-width: 640px) {
  .sm-up {
    display: inline;
  }
}
.md-up {
  display: none;
}
@media (min-width: 768px) {
  .md-up {
    display: inline;
  }
}
@media (min-width: 768px) {
  th.md-up,
  td.md-up {
    display: table-cell;
  }
}

[data-hidden] {
  display: none !important;
}

/* Atomic utilities — compose these instead of minting another one-declaration
   bespoke selector; naming follows the familiar Tailwind subset. */

/* layout */
.flex          { display: flex; }
.inline-flex   { display: inline-flex; }
.flex-col      { display: flex; flex-direction: column; }
.flex-row      { display: flex; flex-direction: row; }
.flex-wrap     { flex-wrap: wrap; }
.grid          { display: grid; }
.items-center  { align-items: center; }
.items-start   { align-items: flex-start; }
.items-end     { align-items: flex-end; }
.justify-center  { justify-content: center; }
.justify-between { justify-content: space-between; }
.justify-end     { justify-content: flex-end; }
.gap-1 { gap: 0.25rem; }
.gap-2 { gap: 0.5rem; }
.gap-3 { gap: 0.75rem; }
.gap-4 { gap: 1rem; }
.gap-6 { gap: 1.5rem; }
.w-full  { width: 100%; }
.h-full  { height: 100%; }
.flex-1  { flex: 1; }
.flex-shrink-0 { flex-shrink: 0; }
.relative { position: relative; }

/* text */
.text-xs   { font-size: 0.75rem; }
.text-sm   { font-size: 0.8125rem; }
.text-base { font-size: 0.875rem; }
.font-medium    { font-weight: 500; }
.font-semibold  { font-weight: 600; }
.font-bold      { font-weight: 700; }
.text-muted      { color: var(--muted-foreground); }
.text-foreground { color: var(--foreground); }
.text-primary    { color: var(--primary); }
.text-center { text-align: center; }
.text-right  { text-align: right; }
.uppercase   { text-transform: uppercase; }
.tabular-nums { font-variant-numeric: tabular-nums; }

/* overflow */
.overflow-hidden { overflow: hidden; }
.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* interaction */
.cursor-pointer { cursor: pointer; }

/* vertical stack with consistent gap */
.stack   { display: flex; flex-direction: column; }
.stack-1 { display: flex; flex-direction: column; gap: 0.25rem; }
.stack-2 { display: flex; flex-direction: column; gap: 0.5rem; }
.stack-3 { display: flex; flex-direction: column; gap: 0.75rem; }
.stack-4 { display: flex; flex-direction: column; gap: 1rem; }

html {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-optical-sizing: auto;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}
a {
  text-decoration: none;
  color: inherit;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  font-family: "Inter", ui-sans-serif, system-ui, sans-serif;
  font-size: var(--text-sm);
  line-height: 1.5;
  background-color: var(--background);
  color: var(--foreground);
}

/* Site-wide scrollbars. Firefox: scrollbar-* cascades from the root; WebKit
   needs ::-webkit rules on every scrollable element — hence the universal
   selector. Colors track --border / --muted-foreground so dark mode follows. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
*::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 4px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover { background: var(--muted-foreground); }
*::-webkit-scrollbar-corner { background: transparent; }

input[type="checkbox"],
input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  width: 1rem;
  height: 1rem;
  border-radius: 0.25rem;
  border: 1.5px solid var(--muted-foreground);
  background: transparent;
  cursor: pointer;
  flex-shrink: 0;
  transition:
    background-color 100ms,
    border-color 100ms;
}
input[type="radio"] {
  border-radius: 50%;
}
input[type="checkbox"]:checked,
input[type="radio"]:checked {
  background-color: var(--primary);
  border-color: var(--primary-hover);
  background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
  background-size: 100%;
  background-position: center;
  background-repeat: no-repeat;
}
input[type="checkbox"]:hover:not(:checked),
input[type="radio"]:hover:not(:checked) {
  border-color: var(--muted-foreground);
}

main {
  flex: 1;
}

h1,
h2,
h3,
h4 {
  line-height: 1.2;
}

.mobile-nav-wrap {
  position: fixed;
  bottom: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  z-index: 40;
}
@media (min-width: 768px) {
  .mobile-nav-wrap {
    display: none;
  }
}

.mobile-nav {
  display: flex;
  justify-content: space-around;
  align-items: stretch;
  height: 3.5rem;
  padding: 0 0.25rem;
  background: color-mix(in srgb, var(--muted) 80%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-top: 1px solid var(--border);
}

.mobile-nav-link {
  display: flex;
  flex: 1 1 0;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.125rem;
  min-width: 0;
  min-height: 3rem;
  padding: 0.25rem 0.125rem;
  font-size: 0.6875rem;
  color: var(--muted-foreground);
  text-decoration: none;
  background: transparent;
  border: 0;
  cursor: pointer;
  font-family: inherit;
}
.mobile-nav-link .icon {
  width: 1.25rem;
  height: 1.25rem;
}
.mobile-nav-label {
  line-height: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* Clear the fixed bottom nav. */
@media (max-width: 767px) {
  body {
    padding-bottom: 3.5rem;
  }
}

.toast-container {
  position: fixed;
  bottom: 5rem;
  right: 1.5rem;
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  pointer-events: none;
}
@media (min-width: 768px) {
  .toast-container {
    bottom: 1.5rem;
  }
}

*,
::after,
::before,
::backdrop {
  border-color: var(--border);
}

::selection {
  background-color: var(--primary);
  color: var(--primary-foreground);
}

:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 2px var(--background),
    0 0 0 4px var(--ring);
}

/* Inputs use a softer inner glow instead of double ring */
.input:focus,
.search-input:focus,
.code-input:focus {
  outline: none;
  border-color: var(--ring);
  box-shadow: var(--field-focus-ring);
}

/* Sticky lives on the HEADER, not .site-nav: a sticky box can only travel
   inside its containing block, and header.site-header shrink-wraps to exactly
   the nav's height — sticky on the nav itself never moves. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
}

.site-nav {
  background: var(--background);
  border-bottom: var(--nav-border) solid var(--border);
}

.site-nav-inner {
  display: flex;
  align-items: center;
  height: var(--nav-height-sm);
  max-width: var(--content-max);
  margin: 0 auto;
  gap: 0.5rem;
  padding: 0 0.5rem;
}
@media (min-width: 640px) {
  .site-nav-inner {
    padding: 0 1rem;
  }
}
@media (min-width: 1024px) {
  .site-nav-inner {
    padding: 0 1.25rem;
  }
}
@media (min-width: 768px) {
  .site-nav-inner {
    height: var(--nav-height);
  }
}

.site-logo {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.5rem;
  color: var(--logo-color);
  flex-shrink: 0;
}
.site-logo > svg {
  width: 2rem;
  height: 2rem;
}

.nav-links {
  display: none;
  gap: 1rem;
  font-size: var(--text-sm);
  font-weight: 500;
  padding-top: 0.25rem;
  margin-left: 1.5rem;
}

@media (min-width: 1024px) {
  .nav-links {
    display: flex;
  }
}

.nav-link {
  display: flex;
  align-items: center;
  padding: 0.5rem;
  color: var(--foreground);
  font-weight: 400;
  transition: color 150ms;
  text-decoration: none;
}
.nav-link:hover {
  color: var(--muted-foreground);
}

.nav-search {
  display: flex;
  align-items: center;
  margin-left: auto;
  margin-right: auto;
  /* min-width: 0 — a flex item defaults to min-width:auto and the search
     field refuses to shrink on a narrow phone; it is the one item here that
     should yield first. */
  min-width: 0;
}

.search-field {
  position: relative;
  display: flex;
  align-items: center;
}
.search-kbd {
  display: none;
  position: absolute;
  right: 0.5rem;
  pointer-events: none;
  font-size: 0.6875rem;
  color: var(--muted-foreground);
  background: var(--secondary);
  border: 1px solid var(--border);
  border-radius: 0.25rem;
  padding: 0.0625rem 0.375rem;
  font-family: inherit;
}
.search-field:not(:focus-within) .search-kbd {
  display: block;
}
@media (max-width: 767px) {
  .search-kbd { display: none !important; }
}
.search-icon {
  position: absolute;
  left: 0.625rem;
  width: 1rem;
  height: 1rem;
  color: var(--muted-foreground);
  pointer-events: none;
}
.search-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  margin-top: 0.25rem;
  background: var(--popover);
  color: var(--popover-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.04),
    0 4px 12px rgba(0, 0, 0, 0.06),
    0 12px 24px rgba(0, 0, 0, 0.04);
  z-index: 50;
  max-height: 60vh;
  overflow-y: auto;
}
/* visibility handled by [data-hidden] global rule */

/* Auth-aware visibility — resolved in <head> before first paint via the authd
   cookie. The [data-authed] ancestor beats [data-hidden] on specificity (no
   !important); handleUnauthorized() removes the attribute to flip back to
   guest. */
[data-authed] [data-guest-only] { display: none; }
[data-authed] [data-auth-only] { display: flex; }
[data-authed] [data-auth-link] { display: inline-flex; }
/* Admin-only nav entries — the inline <head> script sets data-admin on <html>
   when the authd cookie carries "admin". Reveal is scoped to .profile-menu:
   links need display:flex and <hr> display:block (display:revert falls back
   to inline and breaks the menu layout). */
[data-admin-only] { display: none; }
[data-admin] .profile-menu a[data-admin-only] { display: flex; }
[data-admin] .profile-menu hr[data-admin-only] { display: block; }

.nav-auth-slot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  position: relative;
}
.nav-actions {
  display: flex;
  align-items: center;
  position: relative;
}

.profile-toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  height: var(--field-height);
  border: 1px solid var(--border);
  border-radius: var(--field-radius);
  padding: 0 var(--field-px);
  font-size: var(--field-font);
  color: var(--secondary-foreground);
  background: none;
  cursor: pointer;
  transition: background 150ms;
}
.profile-toggle:hover {
  background: var(--muted);
}
.profile-initial {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  line-height: 1;
}
.profile-toggle > .icon {
  transition: transform 200ms;
}
.profile-toggle[aria-expanded="true"] > .icon {
  transform: rotate(180deg);
}
.profile-toggle[aria-expanded="true"] {
  background: var(--muted);
}

.profile-menu {
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: 0.25rem;
  width: 14rem;
  background: var(--popover);
  color: var(--popover-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.04),
    0 4px 12px rgba(0, 0, 0, 0.06),
    0 12px 24px rgba(0, 0, 0, 0.04);
  z-index: 50;
  padding: 0.25rem 0;
  font-size: var(--text-sm);
}
.search-dropdown-wrap {
  position: relative;
}

/* Per-user type filter (multi-type tenant nav) — icon-only; the count badge
   appears once a type is hidden; popover anchors to the toggle's right edge. */
.ctid-filter-wrap {
  position: relative;
  display: inline-flex;
}
.ctid-filter-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  margin-right: 0.25rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: none;
  color: var(--muted-foreground);
  cursor: pointer;
  transition: background 150ms, color 150ms;
}
.ctid-filter-toggle:hover,
.ctid-filter-toggle[aria-expanded="true"] {
  background: var(--muted);
  color: var(--foreground);
}
.ctid-filter-badge {
  position: absolute;
  bottom: -0.125rem;
  right: -0.125rem;
  padding: 0 0.25rem;
  border-radius: var(--radius-full);
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 0.5625rem;
  font-weight: 600;
  line-height: 0.875rem;
  min-width: 0.875rem;
  text-align: center;
}
.ctid-filter-badge[data-hidden] { display: none; }
.ctid-filter-menu {
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: 0.25rem;
  min-width: 12rem;
  padding: 0.5rem 0.75rem 0.625rem;
  background: var(--popover);
  color: var(--popover-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 4px 12px rgba(0,0,0,0.06);
  z-index: 50;
  font-size: var(--text-sm);
}
.ctid-filter-menu[data-hidden] { display: none; }
.ctid-filter-title {
  margin: 0 0 0.375rem;
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted-foreground);
}
.ctid-filter-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}
.ctid-filter-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0;
  cursor: pointer;
}
.ctid-filter-row input[type="checkbox"] {
  accent-color: var(--primary);
  flex-shrink: 0;
}
/* Long type names stay on one line — the label absorbs width; the smaller
   size buys room without widening the popover. */
.ctid-filter-row span {
  font-size: 0.8125rem;
  white-space: nowrap;
}
.ctid-filter-reset {
  margin-top: 0.5rem;
  width: 100%;
  padding: 0.25rem;
  border: none;
  background: none;
  color: var(--muted-foreground);
  font-size: 0.6875rem;
  cursor: pointer;
  text-align: center;
  border-radius: var(--radius);
}
.ctid-filter-reset:hover {
  background: var(--muted);
  color: var(--foreground);
}

.profile-menu a,
.profile-menu button {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  margin: 0 0.25rem;
  width: calc(100% - 0.5rem);
  border-radius: var(--radius);
  color: var(--secondary-foreground);
  text-align: left;
  text-decoration: none;
  background: none;
  border: none;
  cursor: pointer;
  font-size: var(--field-font);
  transition:
    background 150ms,
    color 150ms;
}
.profile-menu a:hover,
.profile-menu button:hover {
  background: var(--muted);
  color: var(--foreground);
}
.profile-menu-user {
  padding: 0.5rem 0.75rem;
  margin: 0 0.25rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--muted-foreground);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.profile-menu hr {
  margin: 0.25rem 0;
  border: none;
  border-top: 1px solid var(--border);
}

.content-panel {
  display: flex;
  flex-direction: column;
  max-width: var(--content-max);
  gap: 0.75rem;
  margin: 0 auto;
  padding: 1.25rem 0.75rem 5rem;
  min-height: 100vh;
}
/* Stacked content-panels (multi-type home): only the first absorbs the
   viewport-fill so the shorter follow-up panel doesn't trap empty space. */
.content-panel + .content-panel {
  min-height: 0;
  padding-top: 0;
  padding-bottom: 1.25rem;
}
@media (min-width: 640px) {
  .content-panel {
    padding-left: 1.5rem;
    padding-right: 1.5rem;
  }
}
@media (min-width: 768px) {
  .content-panel {
    padding-bottom: 1.25rem;
  }
}
@media (min-width: 1024px) {
  .content-panel {
    padding-left: 2rem;
    padding-right: 2rem;
  }
}

.card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background-color: var(--card);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1rem;
  background-color: var(--muted);
}

.card-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--border);
  transition: background-color 150ms;
}
.card-row:hover {
  background-color: var(--muted);
}
a.card-row {
  text-decoration: none;
  color: inherit;
}

.badge {
  display: inline-flex;
  align-items: center;
  border-radius: var(--radius-full);
  padding: 0.125rem 0.625rem;
  font-size: 0.75rem;
  font-weight: 500;
}

.badge-primary {
  background-color: var(--primary-light);
  color: var(--primary-text);
}

.badge-default {
  background-color: var(--secondary);
  color: var(--muted-foreground);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  height: var(--field-height);
  padding: 0 1rem;
  font-size: var(--field-font);
  font-weight: 500;
  white-space: nowrap;
  border-radius: var(--field-radius);
  transition:
    background-color 150ms,
    color 150ms;
  cursor: pointer;
  user-select: none;
}
.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* [data-loading] keeps the label in place (transparent) and spins a
   pseudo-element ring — rewriting textContent recomputed the button width and
   flashed layout. */
.btn[data-loading] {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}
.btn[data-loading]::before {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 1rem;
  height: 1rem;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: btn-spin 0.7s linear infinite;
  color: var(--primary-foreground);
}
.btn-default[data-loading]::before,
.btn-outline[data-loading]::before { color: var(--foreground); }

@keyframes btn-spin {
  to { transform: rotate(360deg); }
}

.btn-primary {
  background-color: var(--primary);
  color: var(--primary-foreground);
  border: 1px solid transparent;
}
.btn-primary:hover:not(:disabled) {
  background-color: var(--primary-hover);
}

.btn-outline {
  background-color: transparent;
  color: var(--primary-text);
  border: 1px solid var(--primary);
}
.btn-outline:hover:not(:disabled) {
  background-color: var(--bg-primary-subtle);
}

.nav-actions-guest {
  gap: 0.5rem;
}
.nav-signin,
.nav-register {
  white-space: nowrap;
}
/* ≤767px the bottom bar already carries Sign in, and this duplicate pushed
   the row past the viewport: every item is nowrap with min-width:auto, so the
   row cannot compress — the last child gets pushed out. 768px matches
   .mobile-nav-wrap's breakpoint exactly, so the two controls are never both
   hidden. `Start collecting` stays — it is the conversion CTA. */
@media (max-width: 767.98px) {
  .nav-signin {
    display: none;
  }
}
.nav-divider {
  display: inline-block;
  width: 1px;
  height: 1.5rem;
  background: var(--border);
  margin: 0 0 0 0.75rem;
  flex-shrink: 0;
}

.btn-default {
  background-color: var(--background);
  color: var(--secondary-foreground);
  border: 1px solid var(--border);
}
.btn-default:hover:not(:disabled) {
  background-color: var(--muted);
}

.input {
  display: block;
  width: 100%;
  height: var(--field-height);
  padding: 0 var(--field-px);
  border: 1px solid var(--field-border);
  border-radius: var(--field-radius);
  background-color: var(--background);
  color: var(--foreground);
  font-size: var(--field-font);
  transition:
    border-color 150ms,
    box-shadow 150ms;
}
textarea.input {
  height: auto;
  padding: var(--field-py) var(--field-px);
}
.input::placeholder {
  color: var(--muted-foreground);
}
.input:focus {
  outline: none;
  border-color: var(--ring);
  box-shadow: var(--field-focus-ring);
}

.input-with-icon {
  padding-left: 2.25rem;
}

/* Gain display — state from data-trend="up|down|flat"; Jinja can render the
   attr, no dynamic classList. */

[data-trend="up"]   { color: var(--gain-up); }
[data-trend="down"] { color: var(--gain-down); }
[data-trend="flat"] { color: var(--gain-flat); }

.icon {
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
}
.icon-sm {
  width: 1rem;
  height: 1rem;
}
.icon-lg {
  width: 1.5rem;
  height: 1.5rem;
}
.icon-xl {
  width: 2rem;
  height: 2rem;
}
.icon-huge {
  width: 10rem;
  height: 10rem;
}

.section-divider {
  width: 2.5rem;
  border-top: 2px solid var(--primary);
  margin: 0.75rem 0;
}

.label-uppercase {
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted-foreground);
}

.page-title {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--foreground);
  letter-spacing: -0.025em;
  margin-bottom: 0.5rem;
}
@media (min-width: 768px) {
  .page-title {
    font-size: 1.875rem;
  }
}

.page-subtitle {
  color: var(--muted-foreground);
  margin-bottom: 2rem;
}

.text-subtle {
  color: var(--muted-foreground);
}

/* Screen-reader only. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

.catalog-layout {
  display: flex;
  gap: 2rem;
}

.catalog-sidebar {
  display: none;
  flex-shrink: 0;
  min-width: 200px;
  position: sticky;
  top: var(--nav-dock);
  align-self: flex-start;
  max-height: calc(100vh - var(--nav-height));
  overflow-y: auto;
}
@media (min-width: 1024px) {
  .catalog-sidebar {
    display: block;
  }
}

.catalog-sidebar-list {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  list-style: none;
  padding: 0;
}

.catalog-sidebar-link {
  display: block;
  padding: 0.375rem 0.75rem;
  font-size: 0.875rem;
  color: var(--secondary-foreground);
  border-radius: var(--radius);
  transition:
    background 150ms,
    color 150ms;
  text-decoration: none;
}
.catalog-sidebar-link:hover {
  background: var(--muted);
  color: var(--primary);
}

.catalog-content {
  flex-grow: 1;
  min-width: 0;
}

.catalog-toc-mobile {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 2rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--border);
}
@media (min-width: 1024px) {
  .catalog-toc-mobile {
    display: none;
  }
}

.catalog-group {
  margin-bottom: 3rem;
  scroll-margin-top: 5rem;
}
.catalog-group-header {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
}
.catalog-group-header:has([data-toggle-section]) {
  cursor: pointer;
}
.catalog-group h2 {
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--foreground);
}
.catalog-group-header [data-toggle-section] .icon {
  transition: transform 200ms;
  transform: rotate(180deg);
}
.catalog-group-header [aria-expanded="false"] .icon {
  transform: rotate(0deg);
}

.catalog-cards {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}
@media (min-width: 640px) {
  .catalog-cards {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 768px) {
  .catalog-cards {
    grid-template-columns: repeat(3, 1fr);
  }
}
.catalog-expand {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  margin-top: 1rem;
}

.catalog-card {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 0.75rem 1rem;
  transition:
    border-color 150ms,
    box-shadow 150ms;
  text-decoration: none;
  color: inherit;
}
.catalog-card-thumbs {
  display: flex;
  flex-shrink: 0;
}
.catalog-card-thumb {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--radius-thumb);
  object-fit: cover;
  border: 2px solid var(--card, #fff);
}
.catalog-card-thumb + .catalog-card-thumb {
  margin-left: -0.625rem;
}
.catalog-card:hover {
  border-color: var(--color-primary-300);
}
.catalog-card-name {
  font-weight: 500;
  color: var(--foreground);
}
.catalog-card:hover .catalog-card-name {
  color: var(--primary);
}
/* The unnamed name+meta wrapper was content-sized, so its children's
   width:100% resolved too narrow and space-between collapsed. */
.catalog-card > div:not(.catalog-card-thumbs) {
  flex: 1;
  min-width: 0;
}
.catalog-card-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  margin-top: 0.5rem;
  font-size: 0.75rem;
  color: var(--muted-foreground);
}
.catalog-card-meta > span {
  display: inline-block;
}

.browse-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
  margin-top: 0.5rem;
}
@media (min-width: 900px) {
  .browse-layout {
    grid-template-columns: 15rem 1fr;
  }
}

.browse-filters {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 0.75rem;
}
@media (min-width: 900px) {
  .browse-filters {
    position: sticky;
    top: calc(var(--nav-dock) + 1rem);
    /* Explicit height (not max-height) so flex children can stretch; the form
       uses flex:1. */
    height: calc(100vh - var(--nav-height) - 2rem);
    display: flex;
    flex-direction: column;
  }
}
.browse-filter-form {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  flex: 1;
  min-height: 0;
}
.browse-filter-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.browse-filter-clear {
  font-size: 0.75rem;
}
.browse-filter-search {
  display: flex;
  align-items: center;
  margin: 0.125rem 0;
}
.browse-filter-search .input {
  font-size: 0.8125rem;
  height: 2rem;
}
.browse-filter-groups {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}
@media (max-width: 899px) {
  /* No aside-bound viewport height here — cap the list so the page stays
     usable. */
  .browse-filter-groups { max-height: 26rem; }
}
.browse-filter-group[data-match="0"] {
  display: none;
}
.browse-filter-group-title {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted-foreground);
  margin-bottom: 0.25rem;
}
.browse-filter-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}
.browse-filter-empty {
  font-size: 0.8125rem;
  color: var(--muted-foreground);
  text-align: center;
  padding: 0.75rem 0;
}
.browse-filter-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0.5rem;
  border-radius: var(--radius);
  font-size: 0.8125rem;
  cursor: pointer;
}
.browse-filter-item:hover {
  background: var(--muted);
}
.browse-filter-item input[type="checkbox"] {
  flex-shrink: 0;
}
.browse-filter-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.browse-filter-count {
  flex-shrink: 0;
  font-size: 0.6875rem;
  color: var(--muted-foreground);
  font-variant-numeric: tabular-nums;
}

.btn-block {
  width: 100%;
}

.browse-nav {
  position: sticky;
  top: var(--nav-dock-sm);
  z-index: 5;
  background: var(--background);
}
@media (min-width: 768px) {
  .browse-nav { top: var(--nav-dock); }
}
.browse-toolbar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.25rem;
  margin-bottom: 0.5rem;
  background: var(--background);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.browse-results-summary {
  font-size: 0.875rem;
  color: var(--muted-foreground);
}
.browse-controls {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-left: auto;
}
.browse-sort {
  display: flex;
  align-items: center;
}

/* 2 cols mobile → 4 max, capped so thumbnails stay readable on wide desktops. */
.browse-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
  margin-top: 0.5rem;
}
@media (min-width: 600px) {
  .browse-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 1000px) {
  .browse-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.browse-card {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 0.5rem;
  text-decoration: none;
  color: inherit;
  transition: border-color 150ms, box-shadow 150ms;
}
.browse-card:hover {
  border-color: var(--color-primary-300);
}
.browse-card-thumb {
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--muted);
  border-radius: var(--radius);
  overflow: hidden;
}
.browse-card-thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* While bytes are in flight, paint the img box muted and hide alt-text so
     no broken-image icon or stranded alt label flashes. */
  background: var(--muted);
  color: transparent;
}
.browse-card-thumb .thumb-skeleton {
  width: 100%;
  height: 100%;
  border-radius: 0;
}
.browse-card-name {
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.3;
  /* Clamp to two lines so card heights stay aligned in the grid. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.browse-card-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-top: auto;
}
.browse-card-badge {
  font-size: 0.6875rem;
  padding: 0.125rem 0.5rem;
  border-radius: var(--radius-full);
  background: var(--secondary);
  color: var(--secondary-foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* Type badge — kept a tier quieter than the filled checklist pills (muted
   text, tighter padding); align-self stops the inline-flex badge stretching
   the flex column. */
.browse-card-type {
  align-self: flex-start;
  font-size: 0.6875rem;
  padding: 0.05rem 0.4rem;
}
.browse-card-price {
  font-size: 1rem;
  font-weight: 600;
  color: var(--foreground);
  font-variant-numeric: tabular-nums;
  text-align: center;
  margin: 0.5rem 0 0.25rem;
}

/* Dim the stale grid while the lazy-fetch is in flight; the Apply button
   carries the spinner via [data-loading]. */
.browse-results.is-loading {
  opacity: 0.45;
  transition: opacity 120ms ease-out;
  pointer-events: none;
}
.browse-card-price-empty {
  font-weight: 400;
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

/* Stretch cards so the price row aligns across different-length names. */
.browse-card-grid .browse-card-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

/* List view — bigger thumbs, horizontal card, fewer items per row. */
.browse-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin-top: 0.5rem;
}
.browse-card-list {
  flex-direction: row;
  align-items: center;
  padding: 1rem;
  gap: 1.25rem;
}
.browse-card-list .browse-card-thumb {
  width: 8rem;
  flex-shrink: 0;
}
.browse-card-list .browse-card-body {
  flex: 1;
  min-width: 0;
}
.browse-card-list .browse-card-name {
  font-size: 1rem;
  -webkit-line-clamp: unset;
}
.browse-card-list .browse-card-price {
  font-size: 1rem;
  font-weight: 600;
  color: var(--foreground);
  margin-top: 0.25rem;
}

.pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 2rem;
  flex-wrap: wrap;
}
.pagination-status {
  font-size: 0.875rem;
  color: var(--muted-foreground);
  text-align: center;
  flex: 1;
}

.hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  min-height: calc(100svh - var(--nav-height));
  padding: 1.25rem;
  padding-top: calc(50svh - var(--nav-height) - 8rem);
  margin: 0 auto;
  max-width: var(--content-max);
}

.hero-title {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.1em 0.35em;
  font-size: var(--text-3xl);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.025em;
  margin-bottom: 0.75rem;
}
@media (min-width: 768px) {
  .hero-title {
    font-size: var(--text-4xl);
  }
}

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

.hero-tagline {
  max-width: var(--content-max);
  text-align: center;
  color: var(--muted-foreground);
}

.hero-search {
  display: flex;
  gap: 0.5rem;
  flex-direction: column;
  align-items: stretch;
  width: 100%;
  max-width: 44rem;
  margin: 0 auto;
  padding-top: 2.5rem;
}

.hero-search-row {
  display: flex;
  gap: 0.5rem;
}
.hero-search-row .input {
  flex: 1;
  height: 2.75rem;
  padding: 0.5rem 1rem;
  font-size: var(--text-sm);
  border-radius: var(--radius);
}
.hero-search-row .btn {
  height: 2.75rem;
  padding: 0 1rem;
  font-size: var(--text-sm);
  border-radius: var(--radius);
}
.hero-ghost-text {
  position: absolute;
  left: 1rem;
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
  font-size: var(--text-sm);
  /* 0.4 opacity failed WCAG contrast (≈3.5:1); 0.6 ≈ 5.7:1 keeps the
     placeholder feel. aria-hidden should exempt axe but doesn't with current
     axe rules. */
  color: var(--foreground);
  opacity: 0.6;
  text-shadow: 0 0 16px var(--color-primary-400), 0 0 32px color-mix(in srgb, var(--color-primary-400) 30%, transparent);
  white-space: nowrap;
}
.hero-ghost-text.has-cursor::after {
  content: '';
  display: inline-block;
  width: 2px;
  height: 1.1em;
  margin-left: 1px;
  vertical-align: text-bottom;
  background: var(--foreground);
  opacity: 0.6;
  border-radius: 1px;
  animation: ghost-blink 0.8s ease-in-out infinite;
}
@keyframes ghost-blink {
  0%, 100% { opacity: 0.6; }
  50% { opacity: 0; }
}
.ghost-mode {
  pointer-events: none;
  border: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
  box-shadow: none;
  transition: opacity 1.2s ease;
}
.ghost-mode:not([data-hidden]) {
  opacity: 0.2;
}
.ghost-result-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  color: var(--foreground);
}
.ghost-result-thumb {
  width: 2rem;
  height: 2rem;
  object-fit: cover;
  border-radius: var(--radius-thumb);
  flex-shrink: 0;
}
.ghost-result-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ghost-result-price {
  color: var(--muted-foreground);
  font-size: 0.75rem;
  flex-shrink: 0;
}

.hero-browse {
  text-align: center;
  margin-top: auto;
  padding-top: 1.5rem;
  padding-bottom: 1rem;
  font-size: 0.875rem;
  color: var(--secondary-foreground);
}
.hero-browse a {
  color: var(--primary-text);
  font-weight: 500;
}
.hero-browse a:hover {
  text-decoration: underline;
}

/* "Meet our Guides" — intro left, 2×2 grid right. */
.spg-guides-layout {
  display: grid;
  gap: 2rem;
}
@media (min-width: 1024px) {
  .spg-guides-layout {
    grid-template-columns: 1fr 2fr;
    gap: 3rem;
  }
}
.spg-guides-intro h2 {
  font-size: var(--text-2xl);
  font-weight: 800;
  letter-spacing: -0.025em;
}
.spg-guides-intro p {
  font-size: var(--text-lg);
  color: var(--muted-foreground);
  margin-top: 0.75rem;
}

.spg-guide-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
  list-style: none;
  padding: 0;
  margin: 0;
}
@media (min-width: 640px) {
  .spg-guide-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

.spg-guide-card {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.625rem;
  border-radius: var(--radius);
  transition: background-color 150ms;
}
.spg-guide-card:hover {
  background: var(--accent);
}
.spg-guide-icon {
  width: 4rem;
  height: 4rem;
  flex-shrink: 0;
  border-radius: var(--radius);
  --logo-fill: var(--muted);
  --logo-color: var(--muted-foreground);
}
.spg-guide-icon > svg {
  width: 100%;
  height: 100%;
}
@media (min-width: 1024px) {
  .spg-guide-icon {
    width: 5rem;
    height: 5rem;
  }
}
.spg-guide-card h3 {
  font-size: var(--text-lg);
  font-weight: 600;
}
.spg-guide-host {
  font-size: var(--text-sm);
  color: var(--primary-text);
  font-weight: 500;
}

.section-label {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 500;
  color: var(--muted-foreground);
  margin-bottom: 1.5rem;
}

.popular-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem 1rem;
}
@media (min-width: 768px) {
  .popular-grid {
    grid-template-columns: 1fr 1fr;
    gap: 2rem;
  }
}

.popular-column {
  display: flex;
  flex-direction: column;
}
.popular-checklists {
  margin-top: 2.5rem;
}
/* "Browse by category" tiles — multi-type tenants only; reuses the
   .admin-card border + radius vocabulary. */
.category-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0.75rem;
}
.category-card {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 1rem 1.125rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  color: inherit;
  text-decoration: none;
  transition: border-color 120ms, transform 120ms;
}
.category-card:hover {
  border-color: color-mix(in srgb, var(--primary) 55%, var(--border));
  transform: translateY(-1px);
}
.category-card h3 {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
}
.category-card-cta {
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}
.popular-column h2 {
  font-size: var(--text-xl);
  font-weight: 600;
  line-height: 1.75rem;
  color: var(--foreground);
}

.ranking-table {
  width: 100%;
}
.ranking-row {
  transition: background 150ms;
  cursor: pointer;
}
.ranking-row:hover {
  background: var(--muted);
}
.ranking-row td {
  padding: 0.375rem 0.25rem;
  vertical-align: middle;
}
.ranking-row td:last-child {
  text-align: right;
}
.ranking-thumb {
  width: 4rem;
  height: 4rem;
  object-fit: cover;
  border-radius: var(--radius-thumb);
}
@media (min-width: 768px) {
  .ranking-thumb {
    width: 4.5rem;
    height: 4.5rem;
  }
}
.ranking-thumb-placeholder,
.thumb-skeleton {
  width: 4rem;
  height: 4rem;
  background: var(--secondary);
  border-radius: var(--radius-thumb);
}
@media (min-width: 768px) {
  .ranking-thumb-placeholder {
    width: 4.5rem;
    height: 4.5rem;
  }
}
.ranking-name {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--secondary-foreground);
  /* WCAG 2.5.5: interactive targets ≥24×24px — the <a> read 17px tall;
     padding gives it real touch surface without changing the row visually. */
  display: inline-block;
  padding-block: 0.35rem;
  min-height: 1.5rem;
}
@media (min-width: 768px) {
  .ranking-name {
    font-size: 0.875rem;
  }
}
/* Compact type badge beside the row name (multi-type tenants); inline so it
   wraps under the name without distorting row height. */
.ranking-type-badge {
  font-size: 0.6875rem;
  padding: 0.05rem 0.35rem;
  margin-left: 0.4rem;
  vertical-align: 0.05em;
  font-weight: 500;
}
.num-badge {
  background: var(--primary-light);
  color: var(--primary-text);
  text-align: center;
  padding: 0.25rem 0.5rem;
  min-width: 2.5rem;
  border-radius: var(--radius);
  font-size: 0.75rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.checklist-list {
  columns: 1;
  gap: 1rem;
}
@media (min-width: 768px) {
  .checklist-list {
    columns: 2;
  }
}
@media (min-width: 1024px) {
  .checklist-list {
    columns: 3;
  }
}
.checklist-list li {
  break-inside: avoid-column;
  padding: 0.375rem 0;
}
.checklist-list-link {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: 500;
  gap: 0.75rem;
  padding: 0.5rem;
  border-radius: var(--radius);
  transition: background 150ms;
}
.checklist-list-link:hover {
  background: var(--muted);
}
.checklist-list-link .name {
  font-size: 0.875rem;
  color: var(--secondary-foreground);
}

.checklist-tree {
  border-bottom: 1px solid var(--border);
  padding: 0.375rem 0;
}
.checklist-tree:last-child {
  border-bottom: none;
}
.checklist-tree summary {
  cursor: pointer;
  padding: 0.5rem;
  border-radius: var(--radius);
}
.checklist-tree summary:hover {
  background: var(--muted);
}
.checklist-tree-parent {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  font-weight: 600;
}
.checklist-tree-parent .name {
  font-size: 0.9375rem;
  color: var(--foreground);
}
.checklist-tree-children {
  margin: 0.25rem 0 0.5rem 1.25rem;
}

.features-section {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 6rem 0.75rem;
}
@media (min-width: 640px) {
  .features-section {
    padding-inline: 1.5rem;
  }
}
@media (min-width: 1024px) {
  .features-section {
    padding-inline: 2rem;
  }
}

.features-header {
  text-align: center;
  margin-bottom: 4rem;
}
.features-header .section-label {
  margin-bottom: 1rem;
}
.features-header h2 {
  font-size: var(--text-3xl);
  font-weight: 600;
  letter-spacing: -0.025em;
  color: var(--foreground);
}

.features-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.5rem 1rem;
}
@media (min-width: 768px) {
  .features-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: 3rem 2rem;
  }
}

.feature-card {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  text-align: center;
  align-items: center;
}
.feature-card h3 {
  font-size: 1rem;
  font-weight: 600;
  color: var(--foreground);
  letter-spacing: -0.025em;
}
@media (min-width: 768px) {
  .feature-card h3 {
    font-size: 1.125rem;
  }
}
.feature-card p {
  font-size: 0.8125rem;
  color: var(--muted-foreground);
  line-height: 1.625;
}
@media (min-width: 768px) {
  .feature-card p {
    font-size: 0.875rem;
  }
}

.feature-visual {
  border: 1px solid var(--border);
  background: var(--background);
  overflow: hidden;
  width: 100%;
  border-radius: var(--radius-lg);
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.04);
  height: 200px;
  display: flex;
  flex-direction: column;
}

.feature-vis-header {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--secondary);
  background: var(--muted);
}
.feature-vis-dots {
  width: 1.625rem;
  height: 0.5rem;
  background:
    radial-gradient(circle, var(--border) 50%, transparent 50%) 0 0 / 0.5rem 0.5rem no-repeat,
    radial-gradient(circle, var(--border) 50%, transparent 50%) 50% 0 / 0.5rem 0.5rem no-repeat,
    radial-gradient(circle, var(--border) 50%, transparent 50%) 100% 0 / 0.5rem 0.5rem no-repeat;
}
.feature-vis-bar {
  height: 0.5rem;
  border-radius: 9999px;
  background: var(--secondary);
}
.feature-vis-bar-wide {
  width: 80%;
}
.feature-vis-bar-third {
  width: 33%;
}
.feature-vis-bar-grow {
  flex-grow: 1;
}
.feature-vis-body {
  flex-grow: 1;
  padding: 1rem;
  display: flex;
}
.feature-vis-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  gap: 0.75rem;
}
.feature-vis-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
}
.feature-vis-bottom {
  display: flex;
  align-items: flex-end;
  width: 100%;
}
.feature-vis-chart-svg {
  width: 100%;
  height: 80px;
}
/* Automated-pricing visual: three sale rows → arrow → sparkline, the same
   feature-vis primitives arranged as a pipeline. */
.feature-vis-pipeline {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
}
.feature-vis-rows {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  flex: 1;
}
.feature-vis-row-mini {
  display: flex;
  align-items: center;
  gap: 0.375rem;
}
.feature-vis-row-mini .feature-vis-bar {
  flex: 1;
}
.feature-vis-pipe-arrow {
  flex-shrink: 0;
  color: var(--muted-foreground);
}
.feature-vis-pipe-spark {
  flex: 1.5;
  height: 40px;
}
/* "$0" headline for the Free card — the established primary tint, sized to
   read at a glance. */
.feature-vis-free-zero {
  font-size: 2.25rem;
  font-weight: 700;
  color: var(--color-primary-500);
  line-height: 1;
  letter-spacing: -0.02em;
}
.feature-vis-grid {
  display: grid;
  /* minmax(0,1fr), not 1fr: bare 1fr = minmax(auto,1fr), and that auto floors
     each track at min-content width — the third tile drew 63px outside the
     card on a 390px phone. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.5rem;
  width: 100%;
}
.feature-vis-grid-tile {
  aspect-ratio: 1;
  border-radius: var(--radius-lg);
}
.feature-vis-grid-tile:nth-child(odd) {
  background: var(--color-primary-50);
}
.feature-vis-grid-tile:nth-child(even) {
  background: var(--color-primary-100);
}

.cta-section {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
  padding: 5rem 0.75rem;
  background: var(--muted);
  max-width: var(--content-max);
  margin: 0 auto;
  border-radius: var(--radius-lg);
}
@media (min-width: 640px) {
  .cta-section {
    padding-inline: 1.5rem;
  }
}
@media (min-width: 1024px) {
  .cta-section {
    padding-inline: 2rem;
  }
}
.cta-section h2 {
  font-size: var(--text-2xl);
  font-weight: 600;
  letter-spacing: -0.025em;
  color: var(--foreground);
}
.cta-section p {
  color: var(--muted-foreground);
}
.btn-lg {
  padding: 0.75rem 2rem;
  font-size: 1rem;
}

.faq-section {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 5rem 0.75rem;
}
@media (min-width: 640px) {
  .faq-section {
    padding-inline: 1.5rem;
  }
}
@media (min-width: 1024px) {
  .faq-section {
    padding-inline: 2rem;
  }
}
.faq-section > h2 {
  font-size: var(--text-2xl);
  font-weight: 600;
  letter-spacing: -0.025em;
  color: var(--foreground);
  text-align: center;
  margin-bottom: 3rem;
}

.faq-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 3rem;
}
@media (min-width: 768px) {
  .faq-grid {
    grid-template-columns: 1fr 1fr;
  }
}
.faq-grid h3 {
  font-size: 1rem;
  font-weight: 600;
  color: var(--foreground);
  margin-bottom: 0.75rem;
}
.faq-grid p {
  font-size: 0.875rem;
  color: var(--muted-foreground);
  line-height: 1.625;
}
.faq-grid a {
  color: var(--primary-text);
  text-decoration: underline;
}

.stats-counter {
  text-align: center;
  padding: 3rem 0;
}

.site-footer {
  background: var(--card);
  color: var(--card-foreground);
  border-top: 1px solid var(--border);
}
.site-footer .btn-outline {
  border-color: var(--border);
}

.footer-inner {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 2rem 1rem;
}
@media (min-width: 640px) {
  .footer-inner {
    padding-inline: 1.5rem;
  }
}
@media (min-width: 1024px) {
  .footer-inner {
    padding-top: 4rem;
    padding-inline: 2rem;
  }
}

.footer-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}
@media (min-width: 640px) {
  .footer-grid {
    grid-template-columns: 1fr 1fr;
    gap: 1.5rem;
  }
  .footer-brand {
    grid-column: 1 / -1;
  }
}
@media (min-width: 1280px) {
  .footer-grid {
    grid-template-columns: 1fr 1fr 1fr;
    gap: 2rem;
  }
  .footer-brand {
    grid-column: auto;
  }
}

.footer-brand {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  padding-bottom: 2.5rem;
}
.footer-brand p {
  opacity: 0.85;
}

.footer-logo {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  text-transform: uppercase;
  font-weight: 700;
  font-size: 0.875rem;
  letter-spacing: 0.05em;
}
.footer-logo .icon {
  color: var(--muted-foreground);
  --logo-fill: transparent;
}

.footer-social {
  display: flex;
  gap: 1.5rem;
}
.footer-social a,
.footer-social-btn {
  opacity: 0.6;
  transition: opacity 150ms;
}
.footer-social a:hover,
.footer-social-btn:hover {
  opacity: 1;
}
.footer-social-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: inherit;
  padding: 0;
}
.pwa-glow {
  opacity: 0.85;
  animation: pwa-pulse 3s ease-in-out infinite;
}
@keyframes pwa-pulse {
  0%, 100% { filter: drop-shadow(0 0 0 transparent); }
  50% { filter: drop-shadow(0 0 6px var(--color-primary-400)); }
}

.footer-links strong {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.65;
}
.footer-links ul {
  list-style: none;
  padding: 0;
  margin-top: 0.75rem;
  display: flex;
  flex-direction: column;
  /* Links below carry their own vertical padding — rhythm unchanged, tap
     target isn't. */
  gap: 0.125rem;
}
.footer-links a {
  color: inherit;
  font-size: 0.8125rem;
  opacity: 0.75;
  text-decoration: none;
  transition: opacity 150ms;
  /* WCAG 2.5.8 (AA): 24px minimum target. These are standalone list links
     (the inline exception doesn't apply) and measured 16px at 13px type;
     padding rather than height keeps the text position. */
  display: inline-block;
  padding: 0.25rem 0;
  min-height: 24px;
}
.footer-links a:hover {
  opacity: 1;
}
/* Umbrella credit — same muted tier as .footer-disclaimer; own centered row,
   no underline. */
.footer-umbrella-credit {
  margin-top: 2.5rem;
  text-align: center;
  font-size: 0.75rem;
  font-weight: 300;
  opacity: 0.5;
  letter-spacing: 0.02em;
}
.footer-umbrella-credit a {
  color: inherit;
  text-decoration: none;
  /* Same 24px WCAG 2.5.8 target floor as .footer-links a. */
  display: inline-block;
  padding: 0.3rem 0;
  min-height: 24px;
}
.footer-umbrella-credit a:hover { opacity: 1; }

.footer-disclaimer {
  margin-top: 2.5rem;
  padding-top: 2rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 0.75rem;
  line-height: 1.6;
  opacity: 0.65;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.footer-disclaimer a {
  color: inherit;
  text-decoration: underline;
}

.detail-header {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0 3rem;
}
@media (min-width: 768px) {
  .detail-header {
    grid-template-columns: 1fr 1fr;
    gap: 2rem 3rem;
  }
}

.detail-info {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
.detail-title {
  font-size: var(--text-2xl);
  font-weight: 600;
  color: var(--foreground);
  line-height: 1.2;
  scroll-margin-top: 5rem;
}
@media (min-width: 768px) {
  .detail-title {
    font-size: 1.875rem;
  }
}
.detail-description {
  font-size: 0.875rem;
  color: var(--secondary-foreground);
  line-height: 1.625;
}

.detail-media {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}
.detail-image {
  display: flex;
  justify-content: center;
  align-items: center;
  max-height: 22rem;
}
.detail-image img,
.detail-image .carousel {
  max-height: 22rem;
  object-fit: contain;
}

/* Mosaic: dense auto-flow fills gaps; aspect-ratio keeps cells square;
   object-fit:cover crops. */
.thumb-mosaic {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-flow: dense;
  gap: 0.375rem;
  max-width: 24rem;
  /* max-width cap centers extra column width as whitespace on both sides. */
  margin-inline: auto;
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.thumb-mosaic img {
  width: 100%;
  height: 100%;
  aspect-ratio: 1 / 1;
  display: block;
  border-radius: var(--radius);
  object-fit: cover;
}
/* First image occupies a 2×2 cell for visual hierarchy */
.thumb-mosaic img:first-child {
  grid-column: span 2;
  grid-row: span 2;
}
@media (min-width: 768px) {
  .thumb-mosaic {
    max-width: 20rem;
  }
}

.badge-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
}

.card-value {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--foreground);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.tag-list {
  list-style: none;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin-top: 0.5rem;
}
.tag {
  display: inline-flex;
  align-items: center;
  border-radius: var(--radius-full);
  font-size: 0.75rem;
  padding: 0.25rem 0.625rem;
  /* WCAG 2.5.8: a pill in a wrapped list is a standalone target — 24px floor
     (measured 17px at 12px type; under a thumb that's a coin toss between
     neighbours). */
  min-height: 24px;
  border: 1px solid var(--border);
  background: var(--background);
  color: var(--secondary-foreground);
  font-weight: 500;
  text-decoration: none;
  transition:
    background 150ms,
    border-color 150ms;
}
.tag:hover {
  background: var(--muted);
  border-color: var(--input);
}

.sellers-bar {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.sellers-toggle {
  width: 100%;
  border-radius: 0;
  justify-content: center;
  cursor: pointer;
  list-style: none;
}
.sellers-toggle::-webkit-details-marker { display: none; }
.sellers-toggle::marker { content: ''; }
.affiliate-disclaimer {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  font-size: 0.75rem;
  color: var(--muted-foreground);
  background: var(--muted);
  margin: 0;
  line-height: 1.4;
}
.affiliate-disclaimer .icon {
  color: var(--primary);
  flex-shrink: 0;
}
/* Centered rows so vendor logo + "View listings" align; the fixed icon column
   keeps text starting at the same x. */
.sellers-bar .card-row {
  justify-content: center;
  gap: 1rem;
}
.affiliate-link .affiliate-logo {
  flex-shrink: 0;
  height: 1.25rem;
  /* Same box for every vendor — eBay's wordmark fills it, Amazon's smile
     centers. */
  width: 4rem;
  object-fit: contain;
}

/* Dark mode: grayscale the vendor brands via filter (SVG sprite stays
   intact), matching the site logo's fade to muted; light keeps official
   colors. */
.dark .affiliate-logo,
[data-theme="dark"] .affiliate-logo {
  filter: grayscale(1) brightness(1.4) opacity(0.7);
}

.affiliate-disclaimer {
  justify-content: center;
  text-align: center;
}

.alert-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 0.625rem 1rem;
  font-size: 0.875rem;
  color: var(--secondary-foreground);
  text-decoration: none;
  transition: background 150ms;
}
.alert-cta:hover {
  background: var(--muted);
}

.action-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.btn-icon {
  padding: 0.5rem;
}
.theme-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius);
  border: none;
  background: none;
  color: var(--muted-foreground);
  cursor: pointer;
  transition: color 150ms;
}
.theme-toggle:hover {
  color: var(--foreground);
}
.theme-icon-sun {
  display: none;
}
.dark .theme-icon-sun {
  display: block;
}
.dark .theme-icon-moon {
  display: none;
}

.stats-bar {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  margin-top: 1.5rem;
  text-align: center;
  overflow: hidden;
}
@media (min-width: 768px) {
  .stats-bar {
    grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  }
}
.stat {
  display: flex;
  flex-direction: column;
  padding: 0.75rem 0.5rem;
  align-items: center;
  border-top: 1px solid var(--border);
}
.stat:nth-child(-n + 2) {
  border-top: none;
}
.stat:nth-child(odd) {
  border-right: 1px solid var(--border);
}
@media (min-width: 768px) {
  .stat {
    border-top: none !important;
    border-right: 1px solid var(--border);
  }
  .stat:nth-child(-n + 4) {
    border-top: none;
  }
  .stat:last-child {
    border-right: none;
  }
}
@media (min-width: 768px) {
  .stat {
    border-top: none;
  }
}
.stat-value {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--foreground);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}
.stat-label {
  font-size: 0.75rem;
  color: var(--muted-foreground);
  margin-top: 0.25rem;
}

.chart-section {
  margin: 2.5rem 0;
}
.chart-section h2 {
  font-size: 1.125rem;
  font-weight: 600;
  margin-bottom: 0.5rem;
}

.chart-controls {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin: 1rem 0;
}
.chart-range-buttons {
  display: flex;
  gap: 0.5rem;
}
.chart-range-buttons button {
  padding: 0.5rem 0.75rem;
  min-height: 2.75rem;
  font-size: 0.8125rem;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: none;
  color: var(--muted-foreground);
  cursor: pointer;
  transition: background 150ms;
}
@media (min-width: 768px) {
  .chart-range-buttons button {
    padding: 0.25rem 0.75rem;
    min-height: auto;
    font-size: 0.75rem;
  }
}
.chart-range-buttons button:hover {
  background: var(--muted);
}
.chart-range-buttons button[data-active] {
  background: var(--secondary);
  color: var(--secondary-foreground);
  font-weight: 500;
}

.chart-container {
  padding: 0.5rem;
}
#chart,
#collection-chart {
  width: 100%;
}
/* Plot height comes from the SVG's intrinsic 1200×450 viewBox (≈8:3); a CSS
   aspect-ratio here forced the box shorter and SVG paint overflowed the panel
   border. */

.ts-chart {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  width: 100%;
  color: var(--secondary-foreground);
}
.ts-chart-plot {
  position: relative;
  width: 100%;
  /* No height rules — the SVG's intrinsic 1200×450 viewBox owns the scale
     (see chart.js). */
}
.ts-chart-svg {
  display: block;
  font-family: inherit;
  overflow: visible;
  /* No width/height — SVG's width="100%" attribute + viewBox handle it. */
}

.ts-chart-empty {
  text-align: center;
  color: var(--muted-foreground);
  font-size: 0.875rem;
  padding: 3rem 1rem;
}

.ts-chart-plot {
  position: relative;
}
.ts-chart-empty-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted-foreground);
  font-size: 0.875rem;
  pointer-events: none;
}

.ts-grid-line {
  stroke: var(--border);
  stroke-width: 1;
  stroke-dasharray: 2 4;
  opacity: 0.5;
}

.ts-axis-label {
  fill: var(--muted-foreground);
  font-size: 13px;
  font-family: inherit;
}

.ts-line-stroke {
  stroke: var(--ts-primary);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.ts-scatter-dot {
  fill: var(--ts-primary);
  opacity: 0.3;
}

.ts-avg-line {
  stroke: var(--muted-foreground);
  stroke-width: 1;
  stroke-dasharray: 4 4;
  opacity: 0.4;
}
.ts-avg-label {
  fill: var(--muted-foreground);
  font-size: 10px;
  font-family: inherit;
  opacity: 0.75;
}

.ts-outlier-ring {
  fill: none;
  stroke: var(--ts-primary);
  stroke-width: 1;
  opacity: 0.15;
}
.ts-outlier-dot {
  fill: var(--ts-primary);
  opacity: 0.15;
}

.ts-cursor-line {
  stroke: var(--muted-foreground);
  stroke-width: 1;
  stroke-dasharray: 3 3;
  opacity: 0.6;
}
.ts-cursor-halo {
  fill: var(--ts-primary);
  opacity: 0.2;
}
.ts-cursor-dot {
  fill: var(--ts-primary);
  stroke: var(--background, #fff);
  stroke-width: 2;
}

.ts-hit {
  cursor: crosshair;
}

.ts-tooltip {
  position: absolute;
  pointer-events: none;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.5rem 0.75rem;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  opacity: 0;
  transform: translateY(4px);
  transition:
    opacity 100ms,
    transform 100ms;
  font-size: 0.75rem;
  white-space: nowrap;
  z-index: 10;
}
.ts-tooltip.is-visible {
  opacity: 1;
  transform: translateY(0);
}
.ts-tooltip-date {
  color: var(--muted-foreground);
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin-bottom: 0.125rem;
}
.ts-tooltip-value {
  color: var(--foreground);
  font-size: 0.9375rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  font-variant-numeric: tabular-nums;
}
/* Multi-line variant — legend below the plot, per-series tooltip rows. No
   fixed plot height: the SVG owns its scale (forcing it shorter overflowed
   the .chart-panel border). */
.ts-chart-multi .ts-chart-plot {
  width: 100%;
}
.ts-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  padding: 0.5rem 0.25rem 0;
  font-size: 0.8125rem;
  color: var(--secondary-foreground);
}
.ts-legend-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  cursor: pointer;
  user-select: none;
}
.ts-legend-chip input {
  margin: 0;
}
.ts-legend-dot {
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 9999px;
  flex-shrink: 0;
}
.ts-legend-chip-off {
  opacity: 0.45;
}
.ts-tooltip-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8125rem;
}
.ts-tooltip-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 9999px;
  display: inline-block;
}
.ts-tooltip-label {
  color: var(--muted-foreground);
}

.ts-tooltip-tag {
  margin-top: 0.25rem;
  display: inline-block;
  padding: 0.0625rem 0.375rem;
  background: color-mix(
    in srgb,
    var(--color-warning, #f59e0b) 15%,
    transparent
  );
  color: var(--color-warning, #f59e0b);
  border-radius: 0.25rem;
  font-size: 0.625rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.ts-stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  background: var(--muted);
  border-radius: var(--radius);
  border: 1px solid var(--border);
}
@media (min-width: 640px) {
  .ts-stats {
    grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
    text-align: center;
  }
}
.ts-stat {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}
.ts-stat-label {
  font-size: 0.6875rem;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 500;
}
.ts-stat-value {
  font-variant-numeric: tabular-nums;
  font-size: 0.9375rem;
  color: var(--foreground);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ts-stat-value[data-trend="up"]   { color: #16a34a; }
.ts-stat-value[data-trend="down"] { color: #dc2626; }
.dark .ts-stat-value[data-trend="up"]   { color: #4ade80; }
.dark .ts-stat-value[data-trend="down"] { color: #f87171; }

.sales-section {
  margin: 2.5rem 0;
}
.sales-section h2 {
  font-size: 1.125rem;
  font-weight: 600;
  margin-bottom: 0.5rem;
}

/* Pinned to the `table` element with display:table re-asserted: the admin
   <div>-based .data-table (later in this file) sets display:flex on the bare
   class, which collapsed this SSR table. table.data-table (0,0,1,1) beats
   .data-table (0,0,1,0) regardless of source order. */
table.data-table {
  display: table;
  width: 100%;
  border-collapse: collapse;
}
.data-table thead th {
  font-size: 0.75rem;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 500;
  padding: 0.75rem 0.25rem;
  text-align: left;
  border-bottom: 1px solid var(--border);
}
.data-table thead th:last-child {
  text-align: right;
}
.data-table tbody tr {
  border-bottom: 1px solid var(--secondary);
}
.data-table tbody tr:hover {
  background: var(--muted);
}
.data-table tbody td {
  padding: 0.375rem 0.25rem;
  font-size: 0.875rem;
  vertical-align: middle;
}
@media (min-width: 768px) {
  .data-table tbody td {
    padding: 0.5rem;
  }
}
.data-table tbody td:last-child {
  text-align: right;
}
.data-table a {
  color: var(--secondary-foreground);
  text-decoration: none;
}
.data-table a:hover {
  color: var(--primary);
}

.thumb-cell {
  width: 5rem;
  height: 5rem;
}

.load-more-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1.5rem;
}
.sales-count {
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

.detail-title-row {
  display: flex;
  align-items: start;
  justify-content: space-between;
  gap: 1rem;
}

.card-row-info {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex-grow: 1;
}
.card-row-info strong {
  font-size: 0.875rem;
  color: var(--foreground);
}
.card-row-price {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--primary);
  flex-shrink: 0;
}

.items-section {
  margin-top: 2rem;
}
.items-section h2 {
  font-size: 1.125rem;
  font-weight: 600;
  margin-bottom: 1rem;
}

.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}
.filter-search {
  flex-grow: 1;
  max-width: 20rem;
}
/* Native select styled to match enhanced version (prevents layout shift on JS enhance) */
.filter-select {
  width: auto;
  height: var(--field-height);
  padding: 0 2rem 0 var(--field-px);
  border: 1px solid var(--field-border);
  border-radius: var(--field-radius);
  font-size: var(--field-font);
  color: var(--secondary-foreground);
  background: var(--background)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")
    no-repeat right 0.5rem center;
  background-size: 1rem;
  appearance: none;
  cursor: pointer;
}
.filter-select[data-hidden] {
  display: none;
}

.view-toggle {
  display: flex;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin-left: auto;
}
.view-toggle button {
  padding: 0.375rem 0.625rem;
  background: none;
  border: none;
  color: var(--muted-foreground);
  cursor: pointer;
}
/* State lives in aria-pressed (the announced state IS the styled state —
   a missing/wrong ARIA state is immediately visible). */
.view-toggle button[aria-pressed="true"] {
  background: var(--secondary);
  color: var(--secondary-foreground);
}
.view-toggle-btn {
  /* Match --field-height so the toggle reads as a peer of the sort dropdown. */
  height: var(--field-height);
  padding: 0 0.75rem;
  display: inline-flex;
  align-items: center;
  color: var(--muted-foreground);
  text-decoration: none;
}
.view-toggle-btn + .view-toggle-btn {
  border-left: 1px solid var(--border);
}
.view-toggle-active {
  background: var(--secondary);
  color: var(--secondary-foreground);
}

.clickable-row {
  cursor: pointer;
}
.clickable-row:hover {
  background: var(--muted);
}

.col-expand {
  width: 2rem;
  padding-right: 0;
}
.name-cell {
  display: flex;
  align-items: center;
}
.detail-link {
  display: inline-flex;
  color: var(--muted-foreground);
  margin-left: 0.5rem;
  padding: 0.25rem;
  border-radius: var(--radius);
  vertical-align: middle;
  opacity: 0.4;
  transition: opacity 150ms, background 150ms;
}
.detail-link:hover {
  opacity: 1;
  background: var(--accent);
}
.expand-chevron {
  transition: transform 150ms;
}
.expand-chevron-open {
  transform: rotate(90deg);
}
.qty-badge {
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--primary);
}
.detail-row {
  background: var(--muted);
}
.detail-cell {
  padding: 0.75rem 1rem;
}
/* Grid lives inside the td (display:flex on a colspan td collapses to content
   width). Header row is display:contents; each purchase row is its own
   subgrid — inherits the parent tracks but keeps a real box for hover +
   border-bottom. */
.detail-purchases {
  display: grid;
  grid-template-columns:
    minmax(6rem, max-content)   /* date */
    minmax(5rem, max-content)   /* price */
    minmax(6rem, 1fr)           /* condition (absorbs slack) */
    auto;                       /* actions */
  column-gap: 1.5rem;
  font-size: var(--text-sm);
}
.detail-purchase-header {
  display: contents;
}
.detail-purchase-header > span {
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted-foreground);
  padding: 0 0 0.5rem;
  border-bottom: 1px solid var(--border);
}
.detail-purchase-row {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  align-items: center;
  column-gap: inherit;
  padding: 0.5rem 0.5rem;
  margin: 0 -0.5rem;
  border-radius: var(--radius);
  transition: background-color 150ms;
}
.detail-purchase-row:not(:last-child) {
  border-bottom: 1px solid var(--border);
}
.detail-purchase-row:hover {
  background: var(--background);
}
.detail-date {
  color: var(--muted-foreground);
  font-variant-numeric: tabular-nums;
}
.detail-price {
  font-family: var(--font-numeric);
  font-variant-numeric: tabular-nums;
}
.detail-condition {
  color: var(--muted-foreground);
}
.detail-loading {
  color: var(--muted-foreground);
  font-size: var(--text-sm);
}
.col-date {
  font-variant-numeric: tabular-nums;
  font-size: var(--text-sm);
}
.page-header-actions {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.data-table caption {
  caption-side: bottom;
  font-size: 0.75rem;
  text-transform: uppercase;
  text-align: right;
  color: var(--muted-foreground);
  padding: 0.5rem 0;
}

.prose {
  max-width: 48rem;
}
.prose section {
  margin-bottom: 2.5rem;
}
.prose h2 {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--foreground);
  margin-bottom: 0.5rem;
}
.prose p {
  color: var(--secondary-foreground);
  line-height: 1.75;
  margin-bottom: 0.75rem;
}
.prose p:last-child {
  margin-bottom: 0;
}
.prose ul,
.prose ol {
  color: var(--secondary-foreground);
  line-height: 1.75;
  padding-left: 1.5rem;
  margin-bottom: 0.75rem;
}
.prose li {
  margin-bottom: 0.25rem;
}
.prose a {
  color: var(--primary);
  text-decoration: underline;
}
.dark .prose a {
  color: var(--primary-text);
}

.error-page {
  align-items: center;
  justify-content: center;
}
.error-page-inner {
  display: flex;
  gap: 2rem;
  margin: 5rem 0;
  align-items: center;
}
@media (max-width: 639px) {
  .error-page-inner {
    flex-direction: column;
    text-align: center;
  }
}
.error-icon {
  color: var(--color-primary-300);
}
.error-content {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.error-search {
  max-width: 24rem;
}

.auth-page {
  max-width: 28rem;
  margin: 2rem auto;
  padding: 0 1rem;
}
@media (min-width: 768px) {
  .auth-page {
    margin: 4rem auto;
  }
}

/* Short pages: remove min-height so they don't stretch with empty space */
.content-panel:has(.auth-page),
.content-panel:has(.auth-split),
.content-panel:has(.auth-confirm),
.content-panel:has(.error-page),
.content-panel:has(.settings-form),
.content-panel:has(.content-panel-narrow) {
  min-height: auto;
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.form-field label {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--secondary-foreground);
}

/* Input with leading icon. */
.input-icon-wrap {
  position: relative;
  display: flex;
  align-items: center;
}
.input-icon-wrap > .icon {
  position: absolute;
  left: 0.75rem;
  color: var(--muted-foreground);
  pointer-events: none;
  flex-shrink: 0;
}
.input-icon-wrap .input {
  padding-left: 2.5rem;
}
.input-icon-wrap:has(.input-reveal) .input {
  padding-right: 2.5rem;
}
.input-reveal {
  position: absolute;
  right: 0.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.375rem;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  cursor: pointer;
  border-radius: var(--radius);
}
.input-reveal:hover { color: var(--foreground); }

.form-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 0.25rem 0;
}
.form-row-end {
  justify-content: flex-end;
}
.form-row > label {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  color: var(--secondary-foreground);
  cursor: pointer;
}
.form-row > label input[type="checkbox"] {
  margin: 0;
}

.form-hint {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.75rem;
  background: var(--secondary);
  border-radius: var(--radius);
  font-size: 0.875rem;
  color: var(--secondary-foreground);
}

.form-footer {
  text-align: center;
  font-size: 0.875rem;
  color: var(--muted-foreground);
}
.form-footer a {
  color: var(--primary);
  font-weight: 500;
}
.form-subtext {
  text-align: center;
  font-size: 0.75rem;
  color: var(--muted-foreground);
  margin-top: -0.25rem;
}
.form-subtext a {
  color: var(--primary);
  text-decoration: underline;
}

.welcome-lead {
  color: var(--secondary-foreground);
  font-size: 0.9375rem;
  line-height: 1.5;
}
.welcome-username {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 1rem;
  margin: 0.5rem 0 0.25rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--secondary);
  text-align: center;
}
.welcome-username-label {
  font-size: 0.75rem;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.welcome-username-value {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--foreground);
  font-family: var(--font-numeric);
}
.welcome-actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 1rem;
}
.welcome-actions .btn {
  flex: 1;
}

.oauth-divider {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin: 0;
  color: var(--muted-foreground);
  font-size: 0.8125rem;
}
.oauth-divider::before,
.oauth-divider::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--border);
}
.btn-google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.625rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
  color: var(--foreground);
  font-weight: 500;
  font-size: 0.875rem;
  cursor: pointer;
  text-decoration: none;
  transition: background 150ms, border-color 150ms;
}
/* Auth-page variant gets vertical margin; the settings-row .btn-sm variant
   stays flush (inline in a flex row). */
.btn-google:not(.btn-sm) {
  margin-block: 1.25rem;
}
.btn-google:hover {
  background: var(--secondary);
  border-color: var(--muted-foreground);
}
.btn-google .icon {
  width: 0.875rem;
  height: 0.875rem;
  flex-shrink: 0;
}

/* Auth split layout (signin page) */
.auth-split {
  display: grid;
  grid-template-columns: 1fr;
  gap: 3rem;
  align-items: stretch;
}
@media (min-width: 768px) {
  .auth-split {
    grid-template-columns: 1fr 1fr;
  }
}

.auth-welcome {
  display: none;
}
@media (min-width: 768px) {
  .auth-welcome {
    display: flex;
    flex-direction: column;
    gap: 2rem;
    padding: 2.5rem 0;
  }
  /* Right column mirrors the form's 1rem rhythm; flex-centers vertically,
     padding-top keeps the top edge level with the left headline. */
  .auth-right {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 1rem;
    padding-top: 2.5rem;
  }
  .auth-right .page-title {
    display: none;
  }
}
.auth-welcome h1 {
  font-size: var(--text-3xl);
  font-weight: 600;
  color: var(--foreground);
}
.auth-welcome p {
  color: var(--muted-foreground);
}

.feature-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.feature-list-item {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
}
.feature-list-icon {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius);
  background: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--primary-foreground);
}
.feature-list-item p {
  font-weight: 500;
  color: var(--foreground);
}
.feature-list-item .desc {
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

.link {
  color: var(--primary);
  font-weight: 500;
  font-size: 0.875rem;
}
.link:hover {
  text-decoration: underline;
}

/* Error/success/info — tinted surface + accent text + subtle same-hue border
   (the site's soft-tint pattern); adapts light/dark via color-mix against
   --card. */

.msg-error,
.msg-success,
.msg-info {
  font-size: 0.875rem;
  line-height: 1.4;
  border-radius: var(--radius);
  padding: 0.625rem 0.875rem;
  border: 1px solid transparent;
}
.msg-error a,
.msg-success a,
.msg-info a {
  color: inherit;
  text-decoration: underline;
}
.msg-error {
  background: color-mix(in srgb, var(--destructive) 10%, var(--card));
  color: var(--destructive);
  border-color: color-mix(in srgb, var(--destructive) 25%, transparent);
}
.msg-success {
  background: color-mix(in srgb, var(--success) 12%, var(--card));
  color: color-mix(in srgb, var(--success) 85%, var(--foreground));
  border-color: color-mix(in srgb, var(--success) 30%, transparent);
}
.msg-info {
  background: color-mix(in srgb, var(--primary) 8%, var(--card));
  color: var(--primary-text);
  border-color: color-mix(in srgb, var(--primary) 25%, transparent);
}

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}

.chart-panel {
  border-radius: var(--radius);
  border: 1px solid var(--secondary);
  padding: 1.25rem;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
  background: var(--background);
  margin-bottom: 1.5rem;
}

.collection-table {
  width: 100%;
}
.collection-table thead tr {
  border-bottom: 1px solid var(--border);
}
.collection-table thead th {
  padding: 0.75rem 0.25rem;
  text-align: left;
}
@media (min-width: 768px) {
  .collection-table thead th {
    padding-left: 1rem;
    padding-right: 1rem;
  }
}
.collection-table thead th:last-child,
.collection-table thead th.col-right {
  text-align: right;
}

.collection-table tbody {
  font-size: 0.875rem;
}
.collection-table tbody tr {
  border-bottom: 1px solid var(--secondary);
}
.collection-table tbody tr:hover {
  background: var(--muted);
  cursor: pointer;
}
.collection-table tbody td {
  padding: 0.25rem;
  vertical-align: middle;
}
@media (min-width: 768px) {
  .collection-table tbody td {
    padding: 0.5rem;
  }
}
.collection-table tbody td.col-right {
  text-align: right;
}

.col-thumb {
  height: 5rem;
  width: 4rem;
}
.thumb-img {
  width: 3rem;
  height: 3rem;
  object-fit: cover;
  border-radius: var(--radius-thumb);
}
.item-link {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--secondary-foreground);
  text-decoration: none;
}
.item-link:hover {
  color: var(--primary);
}
.gain-label {
  font-size: 0.75rem;
  font-weight: 500;
}
.price-label {
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}
.price-dash {
  color: var(--input);
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  padding: 4rem 0;
  text-align: center;
}
.empty-state .icon {
  color: var(--input);
}
.empty-state p {
  color: var(--muted-foreground);
}
.empty-state a {
  color: var(--primary);
}
.empty-state a:hover {
  text-decoration: underline;
}

.purchase-list {
  display: flex;
  flex-direction: column;
}
.purchase-list > * + * {
  border-top: 1px solid var(--secondary);
}

.purchase-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 0;
  transition: background 150ms;
}
.purchase-row:hover {
  background: var(--muted);
}
.purchase-thumb {
  width: 3.5rem;
  height: 3.5rem;
  flex-shrink: 0;
}
.purchase-info {
  flex-grow: 1;
  min-width: 0;
}
.purchase-meta {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.75rem;
  color: var(--muted-foreground);
  margin-top: 0.125rem;
}
.purchase-price {
  flex-shrink: 0;
  text-align: right;
}
.purchase-price span {
  font-size: 0.875rem;
  font-weight: 500;
}
.purchase-actions {
  flex-shrink: 0;
}

.empty-state-cell {
  padding: 3rem 1rem;
  text-align: center;
}
.empty-state-text {
  color: var(--muted-foreground);
  font-size: 0.875rem;
  text-align: center;
  padding: 3rem 1rem;
  grid-column: 1 / -1;
}
.empty-state-text.text-error {
  color: var(--error);
}

tbody.is-loading,
[data-items].is-loading {
  opacity: 0.5;
  transition: opacity 150ms;
}

.alert-card-ends {
  font-size: 0.75rem;
  color: var(--muted-foreground);
  margin: 0.25rem 0 0 0;
}

.tip-text {
  font-size: 0.75rem;
  color: var(--muted-foreground);
  margin-top: 1rem;
}
.kbd {
  display: inline-block;
  padding: 0.125rem 0.375rem;
  background: var(--secondary);
  border: 1px solid var(--input);
  border-radius: 0.25rem;
  font-size: 0.75rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.alert-guest-teaser {
  border: 1px solid var(--border);
  background: var(--card);
  border-radius: var(--radius-lg);
  padding: 1.5rem;
  margin-top: 1rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.alert-guest-teaser p {
  font-size: 0.9375rem;
  color: var(--secondary-foreground);
  line-height: 1.5;
}
.alert-guest-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.alert-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}
@media (min-width: 640px) {
  .alert-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 1024px) {
  .alert-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

.alert-card {
  transition: box-shadow 150ms;
  text-decoration: none;
  color: inherit;
}
.alert-card:hover {
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
.alert-thumb-wrap {
  aspect-ratio: 1;
  background: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.alert-thumb {
  object-fit: contain;
  max-height: 100%;
}
.alert-card-body {
  padding: 0.75rem;
}
.alert-card-name {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--foreground);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.alert-card:hover .alert-card-name {
  color: var(--primary);
}
.alert-card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 0.5rem;
}
.alert-card-price {
  font-size: 0.875rem;
  font-weight: 500;
}
.alert-deal {
  font-size: 0.75rem;
  color: var(--gain-down);
}

.checkbox-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  color: var(--secondary-foreground);
  cursor: pointer;
}
.checkbox-label input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  accent-color: var(--primary);
}

.filter-inline {
  display: flex;
  align-items: center;
  gap: 0.375rem;
}
.filter-inline-label {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}
.input-narrow {
  width: 5rem;
  padding-top: 0.25rem;
  padding-bottom: 0.25rem;
}

.settings-form {
  display: flex;
  flex-direction: column;
}
.settings-form > * + * {
  border-top: 1px solid var(--border);
}

.settings-section {
  padding: 1.5rem 0;
}
.settings-section-title {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--foreground);
  margin-bottom: 1rem;
}

.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.setting-row + .setting-row {
  margin-top: 1rem;
}

.setting-label {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--secondary-foreground);
}
.setting-desc {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

.username-form {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.75rem;
}
.username-form .input {
  flex: 1;
}
.username-form .btn {
  white-space: nowrap;
}
.username-status {
  font-size: 0.75rem;
  margin-top: 0.5rem;
  min-height: 1rem;
  color: var(--muted-foreground);
}
.username-status[data-kind="error"] { color: var(--destructive); }
.username-status[data-kind="ok"] { color: var(--success); }
.username-status[data-kind="checking"] { color: var(--muted-foreground); }

.setting-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
}
.setting-toggle + .setting-toggle {
  margin-top: 1rem;
}
.setting-toggle input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  accent-color: var(--primary);
}

.search-bar {
  display: flex;
  gap: 0.5rem;
  max-width: 36rem;
  margin-bottom: 2rem;
}
.search-input {
  flex-grow: 1;
  /* min-width:0 — the default min-width:auto plus a long placeholder pushed
     the Search button past the viewport at 390px and scrolled the page
     sideways (a fixed element's 100% resolves against the widened layout
     viewport, dragging the mobile nav out too). */
  min-width: 0;
  padding: 0.5rem 1rem;
  border: 1px solid var(--input);
  border-radius: var(--radius-lg);
  font-size: 1rem;
  background: var(--background);
  color: var(--foreground);
  transition:
    border-color 150ms,
    box-shadow 150ms;
}
.search-input::placeholder {
  color: var(--muted-foreground);
}
.search-input:focus {
  outline: none;
  border-color: var(--ring);
  box-shadow: var(--field-focus-ring);
}
.search-results {
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.code-input {
  width: 100%;
  padding: 0.75rem;
  border: 1px solid var(--input);
  border-radius: var(--radius);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1.5rem;
  text-align: center;
  letter-spacing: 0.5em;
  background: var(--background);
  color: var(--foreground);
  transition:
    border-color 150ms,
    box-shadow 150ms;
}
.code-input::placeholder {
  color: var(--input);
}
.code-input:focus {
  outline: none;
  border-color: var(--ring);
  box-shadow: var(--field-focus-ring);
}

.auth-confirm {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
  margin: 5rem 0;
  max-width: 20rem;
  margin-left: auto;
  margin-right: auto;
}
.auth-confirm h1 {
  font-size: var(--text-2xl);
  font-weight: 600;
  color: var(--foreground);
}
.auth-confirm p {
  color: var(--muted-foreground);
  text-align: center;
}
.auth-confirm form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  width: 100%;
}

.input-readonly {
  background: var(--muted);
  color: var(--muted-foreground);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

body.modal-open {
  overflow: hidden;
}
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
}
.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
}
.modal-positioner {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 10vh;
}
.modal-panel {
  background: var(--card);
  color: var(--card-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 25px 50px rgba(0, 0, 0, 0.25);
  width: 95vw;
  display: flex;
  flex-direction: column;
}
.modal-panel-md {
  max-width: 28rem;
}
.modal-panel-lg {
  max-width: 32rem;
  max-height: 75vh;
}

.modal-header {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border);
}
.modal-header h3 {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--foreground);
}

.modal-body {
  padding: 0.5rem;
  overflow-y: auto;
  flex-grow: 1;
}
.modal-body-padded {
  padding: 1.5rem;
}

.modal-form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--border);
}
.modal-footer-split {
  justify-content: space-between;
}
.modal-footer-actions {
  display: flex;
  gap: 0.5rem;
}

.modal-hint {
  font-size: 0.875rem;
  color: var(--muted-foreground);
  padding: 0.5rem;
}

.range-full {
  width: 100%;
}
.range-labels {
  display: flex;
  justify-content: space-between;
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

.btn-danger {
  color: var(--gain-down);
  background: none;
  border: none;
}
.btn-danger:hover:not(:disabled) {
  background: rgba(220, 38, 38, 0.05);
}

.carousel {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.carousel-img {
  max-height: 100%;
  width: auto;
  object-fit: contain;
  border-radius: var(--radius-lg);
}
.carousel-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: color-mix(in srgb, var(--background) 80%, transparent);
  border: none;
  border-radius: var(--radius-full);
  padding: 0.375rem;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  cursor: pointer;
  transition: background 150ms;
  display: flex;
  align-items: center;
  justify-content: center;
}
.carousel-btn:hover {
  background: var(--background);
}
.carousel-btn-prev {
  left: 0.5rem;
}
.carousel-btn-next {
  right: 0.5rem;
}
.carousel-dots {
  position: absolute;
  bottom: 0.5rem;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 0.375rem;
}
.carousel-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: var(--radius-full);
  background: var(--input);
  border: none;
  padding: 0;
  cursor: pointer;
  transition: background 150ms;
}

.content-panel-narrow {
  max-width: 42rem;
  min-height: auto !important;
}

.breadcrumb-nav {
  font-size: 0.875rem;
  color: var(--muted-foreground);
  margin-bottom: 0.5rem;
}
.breadcrumb-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  list-style: none;
  padding: 0;
  margin: 0;
}
.breadcrumb-item {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
.breadcrumb-link {
  color: var(--muted-foreground);
  text-decoration: none;
  transition: color 150ms;
  /* WCAG 2.5.5: ≥24px tap target (link measured 21px); inline-flex + padding
     keeps the row's visual height stable. */
  display: inline-flex;
  align-items: center;
  padding-block: 0.2rem;
  min-height: 1.5rem;
}
.breadcrumb-link:hover {
  color: var(--primary);
}

/* Badge base padding reads 22px tall; badges wrapped in <a> get the ≥24px
   WCAG 2.5.8 floor. Plain <span class="badge"> stays compact —
   non-interactive targets don't need it. */
a.badge {
  padding-block: 0.35rem;
  min-height: 1.5rem;
}
.breadcrumb-sep {
  color: var(--input);
  flex-shrink: 0;
}
.breadcrumb-current {
  color: var(--secondary-foreground);
  font-weight: 500;
}

.toast-msg {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  min-width: 16rem;
  max-width: 22rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  color: var(--card-foreground);
  font-size: var(--text-sm);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.04),
    0 4px 12px rgba(0, 0, 0, 0.06),
    0 12px 32px rgba(0, 0, 0, 0.05);
  pointer-events: auto;
  transform: translateY(0.75rem);
  opacity: 0;
  transition:
    transform 300ms cubic-bezier(0.16, 1, 0.3, 1),
    opacity 200ms ease-out;
}
.toast-msg[data-state="visible"] {
  transform: none;
  opacity: 1;
}
.toast-msg[data-state="leaving"] {
  transform: translateY(0.75rem);
  opacity: 0;
}
.toast-msg[data-type="error"] {
  border-color: color-mix(in srgb, var(--destructive) 25%, var(--border));
}
.toast-icon {
  width: 1.125rem;
  height: 1.125rem;
  flex-shrink: 0;
}
.toast-msg[data-type="success"] .toast-icon {
  color: var(--success);
}
.toast-msg[data-type="error"] .toast-icon {
  color: var(--destructive);
}

.search-result-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  color: var(--secondary-foreground);
  text-decoration: none;
  transition:
    background 150ms,
    color 150ms;
}
.search-result-item:hover,
.search-result-item[data-active] {
  background: var(--primary-light);
  color: var(--primary-text);
}
.search-no-results {
  font-size: 0.875rem;
  color: var(--muted-foreground);
  padding: 0.75rem;
}

/* Search results, shared by the nav dropdown + /search page. Classes come
   from #search-result-*-tpl in base.html.j2 (cloned by
   ui.renderSearchResults); context tweaks key off .search-dropdown /
   [data-search-page]. */

.result-section { }
.result-heading {
  padding: 0 0.75rem 0.75rem;
  border-bottom: 1px solid var(--input);
}
.result-heading h3 {
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--muted-foreground);
}
.result-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.result-list li {
  border-bottom: 1px solid var(--border);
  transition: background 150ms;
  cursor: pointer;
}
.result-list li:hover {
  background: var(--muted);
}
.result-list li:last-child {
  border-bottom: none;
}

.result-link {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  font-size: 0.8125rem;
  color: var(--secondary-foreground);
  text-decoration: none;
}
.result-link[data-active] { background: var(--primary-light); }
.result-link-checklist {
  justify-content: space-between;
  font-weight: 500;
}
@media (min-width: 768px) {
  .result-link { font-size: 0.875rem; }
}

.result-thumb {
  width: 2.75rem;
  height: 2.75rem;
  object-fit: cover;
  border-radius: var(--radius-thumb);
  flex-shrink: 0;
}
@media (min-width: 768px) {
  .result-thumb { width: 3rem; height: 3rem; }
}
.result-name {
  font-weight: 500;
  flex-grow: 1;
}
.result-price {
  color: var(--muted-foreground);
  flex-shrink: 0;
}
.result-count {
  background: var(--primary-light);
  color: var(--primary-text);
  text-align: center;
  padding: 0.25rem 0.5rem;
  min-width: 2.5rem;
  border-radius: var(--radius);
  font-size: 0.75rem;
  font-weight: 500;
}

/* Nav dropdown variant — compact header, tighter separators. */
.search-dropdown .result-heading {
  margin-top: 0.75rem;
}
.search-dropdown .result-heading h3 {
  font-size: 0.875rem;
}
.search-dropdown .result-list li {
  border-bottom-color: var(--secondary);
}

/* Search-page variant — taller rows. */
[data-search-page] .result-link-collectible {
  padding: 0.625rem 0.75rem;
}

.grid-view {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem;
}
@media (min-width: 640px) {
  .grid-view {
    grid-template-columns: repeat(3, 1fr);
  }
}
@media (min-width: 768px) {
  .grid-view {
    grid-template-columns: repeat(4, 1fr);
  }
}

.grid-card {
  display: block;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition:
    border-color 150ms,
    box-shadow 150ms;
}
.grid-card:hover {
  border-color: var(--color-primary-300);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.grid-card-media {
  aspect-ratio: 1;
  background: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.grid-card-img {
  object-fit: contain;
  max-height: 100%;
}
.grid-card-info {
  padding: 0.75rem;
}
.grid-card-name {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--foreground);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.grid-card:hover .grid-card-name {
  color: var(--primary);
}
.grid-card-price {
  font-size: 0.75rem;
  color: var(--muted-foreground);
  margin-top: 0.25rem;
}

.owned-badge-wrap {
  position: relative;
}
.owned-badge {
  position: absolute;
  top: -0.25rem;
  right: -0.25rem;
  width: 1.25rem;
  height: 1.25rem;
  background: var(--color-success, #22c55e);
  border-radius: var(--radius-full);
  display: flex;
  align-items: center;
  justify-content: center;
}
.owned-badge-icon {
  width: 0.75rem;
  height: 0.75rem;
  color: white;
}

/* Action-button "on" state comes from the generic button[aria-pressed="true"]
   rule below — no per-button data attributes. */

.custom-select-wrap {
  position: relative;
  display: inline-block;
}
.custom-select-btn {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  height: var(--field-height);
  padding: 0 var(--field-px);
  border: 1px solid var(--field-border);
  border-radius: var(--field-radius);
  font-size: var(--field-font);
  color: var(--secondary-foreground);
  background: var(--background);
  cursor: pointer;
  transition:
    background 150ms,
    border-color 150ms;
}
.custom-select-btn:hover {
  background: var(--muted);
}
.custom-select-btn:focus {
  outline: none;
  border-color: var(--ring);
  box-shadow: var(--field-focus-ring);
}

.custom-select-chevron {
  width: 1rem;
  height: 1rem;
  color: var(--muted-foreground);
  transition: transform 150ms;
}
.custom-select-chevron[data-open] {
  transform: rotate(180deg);
}

.custom-select-menu {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 0.25rem;
  padding: 0.25rem 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--popover);
  color: var(--popover-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.04),
    0 4px 12px rgba(0, 0, 0, 0.06),
    0 12px 24px rgba(0, 0, 0, 0.04);
  z-index: 50;
  min-width: 100%;
  padding: 0.25rem;
}
.custom-select-option {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--field-py) var(--field-px);
  font-size: var(--field-font);
  color: var(--secondary-foreground);
  white-space: nowrap;
  background: none;
  border: none;
  border-radius: var(--radius);
  cursor: pointer;
  transition:
    background 150ms,
    color 150ms;
}
.custom-select-option:hover {
  background: var(--secondary);
  color: var(--foreground);
}
.custom-select-option[data-selected] {
  font-weight: 500;
  color: var(--foreground);
}
.dark .custom-select-option:hover,
[data-theme="dark"] .custom-select-option:hover {
  background: var(--secondary);
  color: var(--foreground);
}
.dark .custom-select-option[data-selected],
[data-theme="dark"] .custom-select-option[data-selected] {
  background: var(--secondary);
  color: var(--foreground);
}

.picker-result-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  text-align: left;
  padding: 0.5rem;
  border-radius: var(--radius);
  font-size: 0.875rem;
  color: var(--secondary-foreground);
  background: none;
  border: none;
  cursor: pointer;
  transition:
    background 150ms,
    color 150ms;
}
.picker-result-item:hover {
  background: var(--primary-light);
  color: var(--primary-text);
}

.carousel-dot[data-active] {
  background: var(--primary);
}

/* Reduced motion — kill transitions, animations and smooth-scroll; instant
   transform/opacity updates keep the UI toggling. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* aria-state is the first-class styling hook — JS sets aria-* and styling
   follows; no parallel data-* to sync. */

/* Collect/wishlist/alert buttons carry state in aria-pressed. */
button[aria-pressed="true"].btn-default,
.action-bar [data-action][aria-pressed="true"] {
  background: var(--primary-light);
  border-color: var(--color-primary-300);
}

/* Disclosure widgets — any [aria-expanded] icon rotates consistently */
[aria-expanded="true"] > .custom-select-chevron,
[aria-expanded="true"] > .icon.chevron {
  transform: rotate(180deg);
}

/* Admin dashboard — scoped to .admin-* so it never leaks into the public
   surface; reuses the primitives above (.btn, .text-subtle, var(--border),
   …). */

.admin-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

/* Admin tab nav — slim underline, URL-driven (?tab=…). */
.admin-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 1.5rem;
  /* No overflow-x:auto here: browsers redirected vertical wheel over the nav
     into horizontal scroll, which bounced (nothing to scroll). flex-wrap
     grows the nav vertically instead — no overflow container at all. */
  overscroll-behavior: contain;
}
.admin-tab {
  padding: 0.625rem 1rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--muted-foreground);
  background: transparent;
  border: none;
  border-bottom: 3px solid transparent;
  /* -1px pulls the active tab's 3px border over the container's 1px bottom
     border (otherwise the tab sits above the line). */
  margin-bottom: -1px;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: color 120ms, border-color 120ms;
}
.admin-tab:hover {
  color: var(--foreground);
  border-bottom-color: color-mix(in srgb, var(--primary) 30%, transparent);
}
.admin-tab-active {
  color: var(--foreground);
  border-bottom-color: var(--primary);
  font-weight: 600;
}

/* Reusable data table (admin-data-table.js). */

.data-table {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.data-table-search {
  max-width: 22rem;
}
.data-table-body {
  display: flex;
  flex-direction: column;
}
.data-table-row {
  display: grid;
  gap: 0.75rem;
  align-items: center;
  padding: 0.5rem 0.25rem;
  border-top: 1px solid var(--border);
  font-size: 0.8125rem;
  /* Rows outside the viewport skip paint/layout (tables run 25–100 rows);
     contain-intrinsic-size reserves the natural ~36px so the scrollbar stays
     accurate and CLS doesn't regress. */
  content-visibility: auto;
  contain-intrinsic-size: 0 36px;
}
.data-table-head {
  border-top: 0;
  border-bottom: 1px solid var(--border);
  font-size: 0.6875rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted-foreground);
  /* The head must always paint — it's the reading reference; override the
     per-row opt-in. */
  content-visibility: visible;
  contain-intrinsic-size: auto;
}
.data-table-cell {
  min-width: 0;
  overflow: hidden;
}
/* Sortable header is a <button> so the whole cell is the click target; the ↑
   ↓ ↕ arrow goes full-color on the active sort key. */
.data-table-sort {
  background: none;
  border: 0;
  padding: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}
.data-table-sort:hover {
  color: var(--foreground);
}
.data-table-sort-active {
  color: var(--foreground);
}
.data-table-sort-indicator {
  font-size: 0.875em;
  opacity: 0.4;
}
.data-table-sort-active .data-table-sort-indicator {
  opacity: 1;
}
.data-table-loading,
.data-table-empty {
  padding: 0.75rem 0.25rem;
  color: var(--muted-foreground);
  font-size: 0.8125rem;
}
.data-table-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border);
}
.data-table-count {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}
.data-table-nav {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.data-table-page {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}
.data-table-btn {
  padding: 0.25rem 0.625rem;
}
.admin-period-switch {
  display: flex;
  gap: 0.125rem;
  border-bottom: 1px solid var(--border);
}
/* Same affordance as the top-level admin tabs; smaller font + tighter padding
   so the row fits card headers. */
.admin-period-switch .btn {
  background: transparent;
  color: var(--muted-foreground);
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  padding: 0.375rem 0.75rem;
  font-size: 0.75rem;
  font-weight: 500;
  margin-bottom: -1px;
  cursor: pointer;
  transition: color 120ms, border-color 120ms;
}
.admin-period-switch .btn:hover {
  color: var(--foreground);
  border-bottom-color: color-mix(in srgb, var(--primary) 30%, transparent);
}
.admin-period-switch .btn-active {
  color: var(--foreground);
  border-bottom-color: var(--primary);
  font-weight: 600;
}

/* Always one row: minmax(0,1fr) lets cards shrink below min-content so long
   numbers wrap; grid-auto-flow:column keeps future tiles side-by-side. */
.admin-stat-grid {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 0.5rem;
  margin-bottom: 1.5rem;
}

.admin-stat {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  min-width: 0;
  /* Container query: the value scales its font against card width so long
     hydrated timestamps shrink instead of blowing out the grid. */
  container-type: inline-size;
  overflow: hidden;
}
.admin-stat-value {
  font-size: clamp(0.75rem, 9cqi, 1.375rem);
  font-weight: 700;
  color: var(--foreground);
  font-variant-numeric: tabular-nums;
  /* --stat-value-line drives line-height AND min-height so skeleton and
     loaded text share one box even when clamp() shrinks the font (CLS
     otherwise). */
  line-height: var(--stat-value-line);
  min-height: var(--stat-value-line);
  /* Hard cap: ellipsis instead of pushing siblings. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.admin-stat-label {
  font-size: 0.75rem;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  /* Mirror of .admin-stat-value — skeleton tracks via --stat-label-line. */
  line-height: var(--stat-label-line);
  min-height: var(--stat-label-line);
}
/* Server-health severity: caution at 75% of a bounded resource, warn at 90% —
   creeping growth caught before it pages. */
.admin-stat-caution {
  border-color: color-mix(in srgb, var(--warning, #c4a107) 50%, var(--border));
  background: color-mix(in srgb, var(--warning, #c4a107) 6%, var(--card));
}
.admin-stat-caution .admin-stat-value { color: var(--warning, #c4a107); }
.admin-stat-warn {
  border-color: color-mix(in srgb, var(--destructive) 50%, var(--border));
  background: color-mix(in srgb, var(--destructive) 8%, var(--card));
}
.admin-stat-warn .admin-stat-value { color: var(--destructive); }
/* Thin progress bar at the tile bottom (disk/db/inodes); fill is
   width:<pct>%; color inherits the tile's severity classes. */
.admin-stat-bar {
  margin-top: auto;
  height: 4px;
  width: 100%;
  background: var(--bg-muted-subtle);
  border-radius: var(--radius-full);
  overflow: hidden;
}
.admin-stat-bar > i {
  display: block;
  height: 100%;
  background: var(--muted-foreground);
  border-radius: inherit;
  transition: width 0.25s ease-out;
}
.admin-stat-caution .admin-stat-bar > i { background: var(--warning, #c4a107); }
.admin-stat-warn    .admin-stat-bar > i { background: var(--destructive); }

.admin-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 1rem;
  margin-bottom: 1.5rem;
  /* overflow:visible so absolutely-positioned popouts (custom selects,
     popovers) escape the card — overflow-x:auto clipped the DQ dropdowns.
     Wide tables get their own scroll context via the :has(.admin-table) rule
     below. */
  overflow: visible;
  /* Cards may set style="--card-min-h:Npx" to reserve their final height
     before JS content arrives (kills the skeleton→JSON CLS); default 0 =
     unchanged. */
  min-height: var(--card-min-h, 0);
}
.admin-card:has(> .admin-table),
.admin-card:has(> .admin-grid-2col .admin-table) {
  overflow-x: auto;
}
/* Opt-in paint/layout skip for below-the-fold cards (pairs with
   --card-min-h). NOT on .admin-card base: content-visibility:auto implies
   contain:paint, which clips absolutely-positioned popout children — only
   cards without popouts get the class in the template. */
.admin-card-cv {
  content-visibility: auto;
  contain-intrinsic-size: 1216px var(--card-min-h, 280px);
}
/* admin-card-header is the one way to head an admin-card: <h2> + optional <p
   class="admin-card-hint">. With a control row on the right, wrap the title
   block in a div, controls as a sibling, and set data-with-controls
   (two-column). */
.admin-card-header {
  margin-bottom: 1.25rem;
}
.admin-card-header h2,
.admin-card > h2:first-child {
  font-size: 1rem;
  font-weight: 600;
  margin: 0 0 0.25rem 0;
}
.admin-card-header .admin-card-hint,
.admin-card > .admin-card-hint {
  font-size: 0.8125rem;
  line-height: 1.55;
  margin: 0.125rem 0 0 0;
  color: var(--muted-foreground);
  /* ~62ch cap — readable line length for multi-sentence hints. */
  max-width: 62ch;
}
/* <code> chips: monospace only, so they don't read as surprise UI. */
.admin-card-hint code {
  background: color-mix(in srgb, var(--muted-foreground) 12%, transparent);
  padding: 0 0.25rem;
  border-radius: 0.25rem;
  font-size: 0.875em;
}
.admin-card-hint strong { color: var(--foreground); font-weight: 600; }
/* Unwrapped headers get the same bottom spacing as the wrapped variant. */
.admin-card > h2:first-child {
  margin-bottom: 0.5rem;
}
.admin-card > .admin-card-hint {
  margin-bottom: 1.25rem;
}
.admin-card-header[data-with-controls] {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 0.75rem;
}
.admin-card-header[data-with-controls] > div:first-child {
  /* Title block keeps h2 + hint stacked at any width. */
  min-width: 0;
}

/* Every admin timestamp is <time class="admin-time" datetime="<UTC
   ISO-8601>"> hydrated into .admin-time-abs (browser-local) + .admin-time-rel
   ("5m ago"); the parens around rel come from pseudo-elements so overrides
   are one line. */
admin-time {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.admin-time-rel {
  color: var(--muted-foreground);
  font-size: 0.85em;
}
.admin-time-rel::before { content: ' ('; }
.admin-time-rel::after  { content: ')'; }

/* In stat tiles the relative time is the prominent value; column-reverse puts
   it on top although it is second in DOM order. */
.admin-stat-value > admin-time {
  display: flex;
  flex-direction: column-reverse;
  align-items: center;
  line-height: 1.05;
  white-space: normal;
}
.admin-stat-value > admin-time .admin-time-rel {
  color: inherit;
  font-size: inherit;
}
.admin-stat-value > admin-time .admin-time-rel::before,
.admin-stat-value > admin-time .admin-time-rel::after { content: ''; }
/* Only the relative reads at a glance in tiles. */
.admin-stat-value > admin-time .admin-time-abs {
  display: none;
}
.admin-kv-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.5rem 1rem;
}
@media (min-width: 640px) { .admin-kv-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1024px) { .admin-kv-grid { grid-template-columns: repeat(6, 1fr); } }
.admin-kv {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}
.admin-kv-label {
  font-size: 0.7rem;
  color: var(--muted-foreground);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  /* Same line metric as .admin-skeleton-label so the swap is pixel-accurate. */
  line-height: var(--stat-label-line);
  min-height: var(--stat-label-line);
}
.admin-kv-value {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--foreground);
  font-variant-numeric: tabular-nums;
  /* Pinned to the same line-box as .admin-skeleton-value so the swap doesn't
     reflow the kv row. */
  line-height: var(--stat-value-line);
  min-height: var(--stat-value-line);
}
.admin-kv-sub {
  color: var(--muted-foreground);
  font-size: 0.75rem;
  font-weight: 400;
  margin-left: 0.25rem;
}
/* Rate next to a kv count — "Accepted 5 (12.3%)"; empty parens suppressed
   when the rate is null. */
.admin-kv-rate {
  color: var(--muted-foreground);
  font-size: 0.75rem;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}
.admin-kv-rate:not(:empty)::before { content: '('; margin-right: 0.125rem; }
.admin-kv-rate:not(:empty)::after  { content: ')'; }
.admin-kv-rate:empty { display: none; }
/* Legacy alias — removable once every admin-card uses the stacked
   .admin-card-header. */
.admin-grid-2col {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  /* Reserve the loaded height: DQ-Stats measured a 59→3px collapse on
     skeleton→loaded swap, pulling everything below up 56px (CLS). Children's
     --card-min-h drives most; this is the floor. */
  min-height: 367px;
}
/* Opt-in smaller reservation when the tallest child resolves under ~184px. */
.admin-grid-2col.is-short { min-height: 184px; }
@media (min-width: 900px) { .admin-grid-2col { grid-template-columns: 1fr 1fr; } }

.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8125rem;
}
.admin-table th,
.admin-table td {
  padding: 0.5rem 0.5rem;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
  text-align: left;
}
.admin-table th {
  font-weight: 600;
  color: var(--muted-foreground);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  text-align: center;
}
/* Numeric columns stay right-aligned — counts read top-down by digit
   position. */
.admin-table th.num {
  text-align: right;
}
.admin-table tbody tr:last-child td { border-bottom: none; }
.admin-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* Long errors + eBay URLs break inside the cell; break-all because URLs have
   no natural break points. */
.admin-table .wrap-anywhere {
  word-break: break-all;
  overflow-wrap: anywhere;
}
/* Three stacked full-width scrape-jobs tables: table-layout:fixed keeps their
   columns aligned with each other and lets Query/Error truncate. */
[data-section="scrape-jobs"] [data-slot] > * + * { margin-top: 1.5rem; }
[data-section="scrape-jobs"] .admin-table { table-layout: fixed; }
[data-section="scrape-jobs"] .admin-table th:nth-child(2) { width: 6rem; }
[data-section="scrape-jobs"] .admin-table th:nth-child(4) { width: 10rem; }
[data-section="scrape-jobs"] .admin-table th:nth-child(5) { width: 6rem; }
/* Relative time is the at-a-glance signal; hiding the abs keeps Finished
   narrow under table-layout:fixed. */
[data-section="scrape-jobs"] .admin-table .admin-time-abs { display: none; }
/* Cell text IS the full URL here (the point of this card); table-layout:fixed
   gives the td a real width so .admin-path-truncate engages. */
[data-section="external-referrer-urls"] .admin-table { table-layout: fixed; }
[data-section="external-referrer-urls"] .admin-table th:nth-child(2) { width: 8rem; }
/* Click-to-expand error blob: truncated summary by default, full string in a
   monospace pre. */
.error-details summary {
  cursor: pointer;
  list-style: none;
}
.error-details summary::-webkit-details-marker { display: none; }
.error-details summary::marker { content: ''; }
.error-details summary::before {
  content: "▸ ";
  color: var(--muted-foreground);
  font-size: 0.75em;
}
.error-details[open] summary::before {
  content: "▾ ";
}
.error-full {
  margin: 0.5rem 0 0;
  padding: 0.5rem 0.75rem;
  background: var(--muted);
  border-radius: var(--radius);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.75rem;
  white-space: pre-wrap;
  word-break: break-all;
}
.admin-path {
  color: var(--foreground);
  text-decoration: none;
}
.admin-path:hover { color: var(--primary); }
.admin-path-truncate {
  display: inline-block;
  max-width: 22rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
}
/* Inside a fixed column the 22rem default overruns into the next cell — clip
   to cell width. */
.admin-table td .admin-path-truncate {
  max-width: 100%;
}
.admin-badge {
  display: inline-block;
  padding: 0.125rem 0.5rem;
  border-radius: var(--radius-full);
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.admin-badge-ok {
  background: color-mix(in srgb, var(--success) 15%, transparent);
  color: var(--success);
}
.admin-badge-warn {
  background: color-mix(in srgb, var(--destructive) 15%, transparent);
  color: var(--destructive);
}
.admin-badge-source-google {
  background: color-mix(in srgb, hsl(210 90% 55%) 15%, transparent);
  color: hsl(210 80% 45%);
}
.admin-badge-source-handcrafted {
  background: color-mix(in srgb, var(--muted-foreground) 15%, transparent);
  color: var(--muted-foreground);
}
/* Same hue pair as the revenue chart's vendor series (CHART_PALETTE[0]/[1] in
   admin.js) so badge and chart segment read as one entity. */
.admin-badge-vendor-ebay {
  background: color-mix(in srgb, hsl(210 80% 55%) 15%, transparent);
  color: hsl(210 80% 45%);
}
.admin-badge-vendor-amazon {
  background: color-mix(in srgb, hsl(28 90% 55%) 18%, transparent);
  color: hsl(28 85% 38%);
}
.admin-badge-confirmed-yes {
  background: color-mix(in srgb, var(--success) 15%, transparent);
  color: color-mix(in srgb, var(--success) 90%, var(--foreground));
}
/* Unconfirmed = gentler yellow caution, not destructive red. */
.admin-badge-confirmed-no {
  background: color-mix(in srgb, hsl(40 95% 55%) 18%, transparent);
  color: hsl(35 80% 35%);
}
/* Active reads neutral muted (not ok-green); deleted is a clear red that
   stands out in the All filter. */
.admin-badge-active {
  background: var(--bg-muted-subtle);
  color: var(--muted-foreground);
}
.admin-badge-deleted {
  background: color-mix(in srgb, var(--destructive) 18%, transparent);
  color: var(--destructive);
}
/* Center pill-only cells (the th is already centered — a left-aligned pill
   reads as a typo); :has-scoped so cells mixing pill + text keep natural
   alignment. */
.admin-table td:has(> .admin-badge),
.admin-table td:has(> .mb-label-badge) {
  text-align: center;
}
/* Catch-all bin badge — muted yellow warning; replaced the loud "CATCH ALL"
   name suffix. */
.catch-all-badge {
  display: inline-block;
  margin-left: 0.375rem;
  padding: 0 0.4rem;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-radius: 0.5rem;
  background: color-mix(in srgb, hsl(40 95% 55%) 22%, transparent);
  color: hsl(35 80% 35%);
  vertical-align: middle;
  white-space: nowrap;
}
/* Name followed by a badge: inline-flex aligns the badge with the link
   baseline and keeps ellipsis truncation on the link. */
.admin-cell-with-badge {
  display: inline-flex;
  align-items: center;
  min-width: 0;
  max-width: 100%;
}
.admin-cell-with-badge .admin-path-truncate {
  flex: 1 1 auto;
  min-width: 0;
}
/* abs + rel spans concatenate with no whitespace ("11:30:358h ago") and abs
   rarely fits a 9–14rem column — hide abs in every admin-table td; the <time>
   datetime attribute keeps the full stamp (native hover tooltip). Reader-view
   callsites sit outside <td> and keep both. */
.admin-table td .admin-time .admin-time-abs { display: none; }
.admin-table td .admin-time .admin-time-rel {
  font-size: inherit;
  color: inherit;
}

/* Row-actions kebab + popover — same shape as mailbox .mb-row-actions-*,
   promoted so any entity table can reuse it. */
.admin-row-actions-btn {
  background: transparent;
  border: 1px solid transparent;
  color: var(--muted-foreground);
  border-radius: 0.375rem;
  padding: 0.125rem 0.5rem;
  cursor: pointer;
  /* Serves both an SVG icon and a text "…" glyph — font-size/letter-spacing
     target the text path; the .icon rule sizes the SVG. */
  font-size: 1.125rem;
  letter-spacing: 0.05em;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.admin-row-actions-btn:hover,
.admin-row-actions-btn[aria-expanded="true"] {
  background: var(--bg-muted-subtle);
  border-color: var(--border-muted-subtle);
  color: var(--foreground);
}
.admin-row-actions-btn .icon { width: 1.125rem; height: 1.125rem; }
.admin-row-actions-menu {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  box-shadow: 0 8px 24px -8px color-mix(in srgb, black 30%, transparent);
  padding: 0.25rem;
  min-width: 10rem;
}
.admin-row-actions-item {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  padding: 0.375rem 0.75rem;
  font-size: 0.8125rem;
  color: var(--foreground);
  cursor: pointer;
  border-radius: 0.375rem;
}
.admin-row-actions-item:hover {
  background: var(--bg-muted-hover);
}
.admin-row-actions-item.is-danger { color: var(--destructive); }
.admin-row-actions-item.is-danger:hover {
  background: var(--bg-destructive-subtle);
}

/* Edit-user modal — readonly basic fields + role checklist. */
.admin-crud-readonly {
  font-size: 0.9375rem;
  color: var(--foreground);
  padding: 0.375rem 0;
}

/* Sales Manager modal — near-fullscreen with a thin click-away margin; edit
   form left, sales datatable right; backdrop click + Escape close. */
/* <admin-modal> custom element = the backdrop (components/admin-modal.js). */
admin-modal {
  position: fixed;
  inset: 0;
  z-index: 9000;
  background: color-mix(in srgb, black 55%, transparent);
  display: flex;
  padding: 2rem;
  overflow: auto;
}
body.admin-modal-open { overflow: hidden; }
.admin-modal {
  background: var(--card);
  color: var(--card-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 20px 60px -10px color-mix(in srgb, black 50%, transparent);
  display: flex;
  flex-direction: column;
  width: 92vw;
  max-width: 1400px;
  /* max-height (not height) + margin:auto centres when it fits and — unlike
     align-items:center — keeps the header reachable when content overflows;
     the body scrolls, not the dialog. The sales modal's inline 90vh stays
     under this cap. */
  max-height: calc(100vh - 4rem);
  margin: auto;
  overflow: hidden;
}
.admin-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.875rem 1rem;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.admin-modal-title {
  font-size: 1rem;
  font-weight: 600;
  margin: 0;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.admin-modal-close {
  background: transparent;
  border: 0;
  color: var(--muted-foreground);
  font-size: 1.5rem;
  line-height: 1;
  padding: 0.25rem 0.5rem;
  cursor: pointer;
  border-radius: var(--radius);
}
.admin-modal-close:hover {
  background: color-mix(in srgb, var(--muted-foreground) 12%, transparent);
  color: var(--foreground);
}
.admin-modal-body {
  flex: 1;
  min-height: 0;
  /* The body is the scroll container (header stays pinned). overflow:hidden +
     flex clipped single-column content taller than the dialog; .admin-sm
     self-manages at 100%, block flow is fine for it too. */
  overflow: auto;
}

.admin-sm {
  display: grid;
  grid-template-columns: minmax(18rem, 24rem) 1fr;
  gap: 1px;
  background: var(--border);
  width: 100%;
  height: 100%;
  min-height: 0;
}
@media (max-width: 899px) { .admin-sm { grid-template-columns: 1fr; } }
.admin-sm-col {
  background: var(--card);
  padding: 1rem;
  overflow: auto;
  min-height: 0;
}
.admin-sm-edit { display: flex; flex-direction: column; gap: 1rem; }

.admin-sm-thumb {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: center;
  text-align: center;
}
.admin-sm-thumb img {
  max-width: 12rem;
  max-height: 12rem;
  object-fit: contain;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--background);
}
.admin-sm-thumb-empty {
  width: 12rem;
  height: 12rem;
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted-foreground);
  font-size: 0.75rem;
}
.admin-sm-public-link {
  font-size: 0.75rem;
  color: var(--muted-foreground);
  text-decoration: none;
}
.admin-sm-public-link:hover { color: var(--foreground); text-decoration: underline; }

.admin-clickable-row { cursor: pointer; }
.admin-clickable-row:hover {
  background: color-mix(in srgb, var(--muted-foreground) 6%, transparent);
}

.admin-sm-presets {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.375rem;
  font-size: 0.75rem;
}
.admin-sm-presets-label { margin-right: 0.25rem; }
.admin-sm-preset-btn {
  padding: 0.125rem 0.5rem;
  font-size: 0.6875rem;
  line-height: 1.4;
}
.admin-sm-preset-btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}
.admin-sm-preset-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.125rem 0.25rem;
  margin-left: auto;
}
.admin-sm-preset-clear .icon { width: 0.875rem; height: 0.875rem; }
.admin-sm-pagination-slot { flex-shrink: 0; }

.admin-sm-sales {
  display: flex;
  flex-direction: column;
}
.admin-sm-sales-wrap {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  height: 100%;
  min-height: 0;
}
.admin-sm-sales-stats { font-size: 0.75rem; margin: 0; }
.admin-sm-sales-table { flex: 1; overflow: auto; min-height: 0; }
.admin-sm-bulk-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.375rem 0.5rem;
  background: color-mix(in srgb, var(--primary) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--primary) 25%, transparent);
  border-radius: var(--radius);
  font-size: 0.75rem;
}
.admin-sm-bulk-count { font-weight: 600; }
.admin-sm-table th, .admin-sm-table td { font-size: 0.75rem; }
.admin-sm-sale-outlier {
  background: color-mix(in srgb, hsl(0 75% 55%) 10%, transparent);
}
.admin-sm-sale-outlier td { color: color-mix(in srgb, hsl(0 75% 55%) 90%, var(--foreground)); }

/* Field-spec-driven CRUD form — sales-manager modal + other admin entity
   edits. */
.admin-crud-form { display: flex; flex-direction: column; gap: 0.75rem; }
.admin-crud-field { display: flex; flex-direction: column; gap: 0.25rem; }
.admin-crud-field-bool {
  flex-direction: row;
  align-items: center;
  gap: 0.5rem;
}
.admin-crud-field-bool .admin-crud-label { order: 1; margin: 0; text-transform: none; font-weight: 500; letter-spacing: 0; font-size: 0.8125rem; color: var(--foreground); }
.admin-crud-label {
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted-foreground);
}
.admin-crud-input {
  font: inherit;
  background: var(--input);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.375rem 0.5rem;
  color: var(--foreground);
}
.admin-crud-input:focus {
  outline: none;
  border-color: var(--ring);
  box-shadow: var(--field-focus-ring);
}
.admin-crud-help {
  font-size: 0.6875rem;
  color: var(--muted-foreground);
  margin: 0;
}
.admin-crud-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.5rem;
}
.admin-crud-status {
  font-size: 0.75rem;
  margin: 0;
  color: var(--muted-foreground);
}
.admin-crud-status-ok { color: var(--success, #22c55e); }
.admin-crud-status-error { color: var(--destructive); }

/* Shared stacked-bar chart (daily traffic / collectibles created / dq
   activity). Legend chips are real <button>s (keyboard-accessible); one
   body-level tooltip is shared across charts — ensureChartTooltip() in
   admin.js. */
.admin-chart {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.admin-chart-bars {
  display: flex;
  gap: 2px;
  height: 8rem;
  align-items: stretch;
}
.admin-chart-bars-sm { height: 4rem; }
.admin-chart-bar {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  border-radius: 2px;
  cursor: crosshair;
  transition: background 120ms;
}
.admin-chart-bar:hover {
  background: color-mix(in srgb, var(--border) 40%, transparent);
}
.admin-chart-stack {
  display: flex;
  flex-direction: column-reverse;
  border-radius: 2px 2px 0 0;
  overflow: hidden;
  min-height: 0;
}
.admin-chart-seg { min-height: 1px; }
.admin-chart-bar-skeleton {
  flex: 1;
  height: 100%;
  border-radius: 2px;
}
.admin-chart-axis {
  display: flex;
  justify-content: space-between;
  font-size: 0.625rem;
  color: var(--muted-foreground);
}
.admin-chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  font-size: 0.6875rem;
  color: var(--muted-foreground);
  margin-top: 0.25rem;
}
.admin-chart-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  background: transparent;
  border: 0;
  padding: 0.125rem 0.375rem;
  border-radius: var(--radius);
  cursor: pointer;
  color: inherit;
  font: inherit;
  transition: opacity 120ms;
}
.admin-chart-legend-item:hover { background: var(--bg-muted-hover); }
.admin-chart-legend-item-off { opacity: 0.4; }
.admin-chart-legend-item-off .admin-chart-legend-dot { filter: grayscale(0.7); }
.admin-chart-legend-item-off .admin-chart-legend-chip { text-decoration: line-through; }
.admin-chart-legend-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 2px;
  flex-shrink: 0;
}
.admin-chart-tip {
  position: fixed;
  display: none;
  z-index: 9999;
  background: var(--card);
  color: var(--foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.5rem 0.625rem;
  box-shadow: 0 6px 24px -4px color-mix(in srgb, black 25%, transparent);
  font-size: 0.75rem;
  min-width: 9rem;
  max-width: 18rem;
  pointer-events: none;
}
.admin-chart-tip-head {
  font-weight: 600;
  margin-bottom: 0.375rem;
  color: var(--foreground);
}
.admin-chart-tip-rows {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}
.admin-chart-tip-row {
  display: grid;
  grid-template-columns: 0.625rem 1fr auto;
  align-items: center;
  gap: 0.5rem;
}
.admin-chart-tip-dot {
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 2px;
}
.admin-chart-tip-label { color: var(--muted-foreground); }
.admin-chart-tip-value { font-variant-numeric: tabular-nums; font-weight: 500; }
.admin-chart-tip-row-zero { opacity: 0.45; }
.admin-chart-tip-row-zero .admin-chart-tip-dot { filter: grayscale(0.7); }
.admin-chart-tip-total {
  display: flex;
  justify-content: space-between;
  margin-top: 0.375rem;
  padding-top: 0.375rem;
  border-top: 1px solid var(--border);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.admin-pagination {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.75rem;
  font-size: 0.75rem;
  color: var(--muted-foreground);
}
.admin-pagination-nav {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
}
.admin-pagination-btn {
  padding: 0.125rem 0.5rem;
  min-width: 1.75rem;
  transition: background 120ms;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.admin-pagination-icon {
  width: 1rem;
  height: 1rem;
}

/* Standard admin <details> summary — native marker hidden, lucide chevron
   rotates 90° on open; .admin-details-chevron isolates the transform from
   sibling text. */
details > summary.admin-details-summary {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0.375rem;
  cursor: pointer;
}
/* All three selectors are needed: list-style:none alone leaves Chrome's
   UA-shadow marker — suppress the legacy webkit pseudo AND modern ::marker. */
details > summary.admin-details-summary::-webkit-details-marker { display: none; }
details > summary.admin-details-summary::marker { content: ''; }
.admin-details-chevron {
  transition: transform 0.15s ease;
  flex-shrink: 0;
  color: var(--muted-foreground);
}
details[open] > summary.admin-details-summary > .admin-details-chevron {
  transform: rotate(90deg);
}
.admin-pagination-btn:hover:not(:disabled):not(.admin-pagination-btn-disabled) {
  background: color-mix(in srgb, var(--muted-foreground) 12%, transparent);
}
.admin-pagination-btn:disabled,
.admin-pagination-btn-disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
/* Inline spinner beside "Showing 1–10 of N" while a cloak() fetch is in
   flight. */
.admin-pagination-count {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.admin-pagination-count::after {
  content: '';
  width: 0.75rem;
  height: 0.75rem;
  border: 2px solid color-mix(in srgb, var(--muted-foreground) 30%, transparent);
  border-top-color: var(--muted-foreground);
  border-radius: 50%;
  animation: admin-pagination-spin 0.7s linear infinite;
  opacity: 0;
  transition: opacity 80ms;
}
.admin-pagination-loading .admin-pagination-count::after { opacity: 1; }

/* Filler rows pad short pages to per_page so the card doesn't collapse;
   hidden cells get an nbsp pseudo to keep natural row height. */
.admin-row-filler {
  visibility: hidden;
  pointer-events: none;
}
.admin-row-filler td::after,
.admin-row-filler th::after {
  content: '\00A0';
}
@keyframes admin-pagination-spin {
  to { transform: rotate(360deg); }
}
/* Canonical spinner for loads where skeletons don't fit; three sizes, same
   keyframes as the pagination spinner. */
.admin-spinner {
  display: inline-block;
  border: 2px solid color-mix(in srgb, var(--muted-foreground) 25%, transparent);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: admin-pagination-spin 0.7s linear infinite;
  vertical-align: middle;
}
.admin-spinner-sm { width: 0.875rem; height: 0.875rem; border-width: 2px; }
.admin-spinner-md { width: 1.25rem; height: 1.25rem; border-width: 2px; }
.admin-spinner-lg { width: 2rem;     height: 2rem;    border-width: 3px; }
/* Usage: <div class="admin-loading"><span class="admin-spinner
   admin-spinner-md"></span> Loading…</div> */
.admin-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.625rem;
  padding: 1.5rem;
  color: var(--muted-foreground);
  font-size: 0.8125rem;
}
@media (prefers-reduced-motion: reduce) {
  .admin-spinner { animation: none; }
}

/* Background-job chip stack — bottom-right list of in-flight jobs; each chip
   auto-dismisses 3.5s after its job hits a terminal state. */
.admin-jobs-stack {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 9100;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  pointer-events: none;
  /* Capped so a runaway job list can't cover the page; scrolls internally. */
  max-height: 60vh;
  overflow-y: auto;
}
.admin-job-chip {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: 0.5rem;
  padding: 0.5rem 0.875rem;
  font-size: 0.8125rem;
  color: var(--foreground);
  box-shadow: 0 6px 18px -8px color-mix(in srgb, black 40%, transparent);
  min-width: 12rem;
  max-width: 22rem;
  transition: opacity 200ms, transform 200ms;
}
.admin-job-chip[data-state="done"] {
  border-left-color: var(--success, #22c55e);
}
.admin-job-chip[data-state="failed"] {
  border-left-color: var(--destructive);
}
.admin-job-chip-label {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.admin-job-chip-leaving {
  opacity: 0;
  transform: translateX(20px);
}
/* Pagination renders <a> when active, <span> when disabled — no underline on
   the <a>, same shape for the <span>. */
a.admin-pagination-btn,
a.admin-pagination-btn:hover {
  text-decoration: none;
}
.admin-pagination-page {
  font-variant-numeric: tabular-nums;
  min-width: 4rem;
  text-align: center;
}

/* Skeletons mirror the real elements' dimensions so the swap doesn't shift
   layout; pulse drops on prefers-reduced-motion. */
.admin-skeleton {
  display: inline-block;
  background: var(--secondary);
  border-radius: var(--radius);
  animation: admin-skeleton-pulse 1.6s ease-in-out infinite;
}
/* Sized from the same --stat-*-line vars as the real elements — one source of
   truth, the swap never changes box height. */
.admin-skeleton-value { width: 60%; height: var(--stat-value-line); margin-bottom: 0.125rem; }
.admin-skeleton-label { width: 75%; height: var(--stat-label-line); }
/* generic row-cell bar — sized to a typical .admin-table cell line-box */
.admin-skeleton-bar { height: 1.3rem; }
/* full-width loading row for the DQ tab's imperative widgets (no template
   skeleton path) */
.dq-skeleton-row { display: block; width: 100%; height: 2.25rem; margin-bottom: 0.5rem; }

@keyframes admin-skeleton-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}
@media (prefers-reduced-motion: reduce) {
  .admin-skeleton { animation: none; }
}
/* Touch targets — WCAG 2.5.5 (AAA) / Apple HIG: 44×44 CSS px. Desktop keeps
   the denser toolbar (a mouse is precise); this widens only phone-driven
   controls. web/tests/e2e/test_journeys.py asserts the floor at 390px, so an
   unsized new nav control fails the build. */
@media (max-width: 767.98px) {
  .theme-toggle,
  .ctid-filter-toggle,
  .view-toggle button,
  .view-toggle-btn,
  .btn-icon,
  [data-mobile-search-trigger] {
    min-width: 44px;
    min-height: 44px;
  }
  /* Thumb-aimed fields — --field-height drives the first three. */
  .search-input,
  .search-bar .btn,
  .input-with-icon,
  .filter-select,
  .custom-select-btn,
  .pagination .btn,
  .ctid-filter-reset {
    min-height: 44px;
  }
  :root {
    --field-height: 44px;
  }
}
