/* weedbud console — type, color, layout */

:root {
  /* Phosphor palette */
  --accent: oklch(84% 0.29 142deg);
  --accent-soft: oklch(84% 0.29 142deg / 16%);
  --accent-ink: oklch(91% 0.22 142deg);

  --bg-0: #050807;
  --bg-1: #0c110e;
  --bg-2: #141a16;
  --bg-3: #1c241f;
  --line: #253029;
  --line-strong: #334038;
  --fg-0: #ecfaf2;
  --fg-1: oklch(88% 0.08 142deg);
  --fg-2: oklch(76% 0.11 142deg);
  --fg-3: oklch(62% 0.09 142deg);
  --accent-deep: oklch(18% 0.08 142deg);

  --cat-flower: oklch(86% 0.28 142deg);
  --cat-extract: oklch(86% 0.29 85deg);
  --cat-vape: oklch(83% 0.26 205deg);
  --cat-edible: oklch(85% 0.28 30deg);
  --cat-topical: oklch(84% 0.24 318deg);
  --cat-tincture: oklch(84% 0.2 250deg);

  --font-display: "Geist", system-ui, sans-serif;
  --font-body: "Geist", system-ui, sans-serif;
  --font-ui: var(--font-body);
  --font-mono: "JetBrains Mono", "IBM Plex Mono", ui-monospace, menlo, monospace;

  --row-h: 38px;
  --rail-w: 280px;
}

html[data-density="compact"] {
  --row-h: 30px;
  --rail-w: 252px;
}

html[data-theme="light"] {
  --bg-0: #faf8f1;
  --bg-1: #f3efe3;
  --bg-2: #ece7d6;
  --bg-3: #e0dac6;
  --line: #d6cfb8;
  --line-strong: #b5ac90;
  --fg-0: #1a1813;
  --fg-1: #3c3a32;
  --fg-2: #6a665a;
  --fg-3: #8e8978;
  --accent: oklch(52% 0.22 142deg);
  --accent-soft: oklch(52% 0.22 142deg / 14%);
  --accent-ink: oklch(42% 0.2 142deg);
}

html[data-mono="1"] body,
html[data-mono="1"] .topbar,
html[data-mono="1"] .rail-section-title,
html[data-mono="1"] .results-table,
html[data-mono="1"] .stat-label {
  font-family: var(--font-mono);
  letter-spacing: -0.01em;
}

* {
  box-sizing: border-box;
}

html,
body,
#root {
  height: 100%;
  margin: 0;
}

body {
  background: var(--bg-0);
  color: var(--fg-0);
  font-family: var(--font-body);
  font-size: 13.5px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizelegibility;
}

.mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* Scrollbar globals + .num-fixed / .th-num / .td-num live in
   /table.css. */
/* Brand chip list — nested inside the already-scrolling filter rail;
   use a hair-thin thumb that fades in on hover to reduce the
   double-scrollbar visual clutter. */
.brand-scroll {
  scrollbar-color: transparent transparent;
  max-height: 180px;
  overflow-y: auto;
}
.brand-scroll::-webkit-scrollbar {
  width: 2px;
}
.brand-scroll::-webkit-scrollbar-thumb {
  background: transparent;
}
.brand-scroll:hover {
  scrollbar-color: var(--line) transparent;
}
.brand-scroll:hover::-webkit-scrollbar-thumb {
  background: var(--line);
}

/* ───────────────── top bar ──────────────────────────────────────── */

.app {
  display: flex;
  flex-direction: column;
  height: 100dvh;
  min-height: 0;
}

.topbar {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 0 18px;
  height: 44px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-1);
  flex: 0 0 auto;
  position: relative;
  z-index: 10;
}

/* Placeholder for the eventual weedbud logo: large wordmark, no
   subtitle.  Swap the inner content to an <img> / <svg> when the real
   asset lands; the wrapper sizing stays put. */
.brand {
  display: flex;
  align-items: center;
  gap: 8px;
}
.brand-icon {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  display: block;
}
.brand-name {
  font-family: "Barlow Semi Condensed", sans-serif;
  font-style: normal;
  font-weight: 800;
  font-size: 26px;
  letter-spacing: -0.02em;
  line-height: 1;
}
.brand-weed {
  color: #2ed470;
}
.brand-bud {
  color: #c4f24a;
}

.tabs {
  display: flex;
  gap: 4px;
}
.tab {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--fg-2);
  padding: 0 12px;
  font: inherit;
  font-size: 13px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  gap: 8px;
  align-self: stretch;
}
.tab:hover {
  color: var(--fg-0);
  background: var(--bg-2);
}
.tab.is-on {
  color: var(--fg-0);
  background: var(--line-strong);
}

.tab-badge {
  display: inline-grid;
  place-items: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--accent);
  color: #0e0d0b;
  font-size: 10px;
  font-weight: 700;
  font-family: var(--font-mono);
  /* line-height: 1 collapses the digit's line-box to its glyph height
     so place-items: center actually centres the glyph rather than the
     ascender-padded line-box -- otherwise the digit reads as
     bottom-aligned next to the much-larger "Map" text in its parent
     .tab flex row. */
  line-height: 1;
}

.topbar-right {
  margin-left: auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 3px;
}

.pending-counts-note {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
}
.pending-line {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 14px;
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition:
    max-height 0.15s ease,
    opacity 0.15s ease;
  pointer-events: none;
  white-space: nowrap;
  text-align: right;
}
.pending-line.is-on {
  max-height: 20px;
  opacity: 1;
}
.pending-add {
  color: var(--accent-ink);
}
.pending-remove {
  color: oklch(72% 0.16 28deg);
}

.db-stats {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--fg-2);
}
.db-stats-val {
  color: var(--fg-0);
}

/* ───────────────── category switcher ────────────────────────────── */

.cat-switcher {
  display: flex;
  align-items: stretch;
  gap: 4px;
  padding: 6px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-1);
  flex: 0 0 auto;
  overflow-x: auto;
}
.cat-tab {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 14px;
  border-radius: 7px;
  background: none;
  border: none;
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  color: var(--fg-2);
  white-space: nowrap;
}
.cat-tab:hover {
  color: var(--fg-0);
  background: var(--bg-2);
}
.cat-tab.is-on {
  color: var(--fg-0);
  background: var(--line-strong);
}
.cat-tab-count {
  font-size: 10px;
  color: var(--fg-3);
}
.cat-tab.is-on .cat-tab-count {
  color: var(--accent-ink);
}
.cat-tab-count.is-error {
  color: oklch(72% 0.16 28deg);
}

/* ───────────────── on-demand blob load / error states ──────────────── */

.blob-state {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  text-align: center;
  padding: 0 40px;
}
.blob-logo {
  animation: blob-logo-pulse 1.4s ease-in-out infinite;
}
.blob-logo .brand-icon {
  width: 44px;
  height: 44px;
}
@keyframes blob-logo-pulse {
  0%,
  100% {
    transform: scale(1);
    opacity: 0.85;
  }
  50% {
    transform: scale(1.12);
    opacity: 1;
  }
}
.blob-state-icon {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: color-mix(in oklch, oklch(72% 0.16 28deg) 18%, transparent);
  color: oklch(72% 0.16 28deg);
  font-size: 20px;
}
.blob-state-title {
  color: var(--fg-0);
  font-size: 14px;
}
.blob-state-msg {
  color: var(--fg-3);
  font-size: 11.5px;
  max-width: 340px;
}

.main {
  flex: 1;
  min-height: 0;
  display: flex;
}

/* ───────────────── filter rail ──────────────────────────────────── */

.query-pane {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  min-width: 0;
}
.query-body {
  display: flex;
  flex: 1;
  min-height: 0;
  min-width: 0;
}

/* match count chip in topbar */
.match-count-chip {
  display: inline-flex;
  align-items: center;
  background: var(--accent-soft);
  color: var(--accent-ink);
  border-radius: 4px;
  padding: 2px 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
.match-count-chip .match-count-val {
  font-variant-numeric: tabular-nums;
}
.match-count-chip .match-count-lbl {
  font-size: 10px;
  margin-left: 3px;
  opacity: 0.75;
}

.filter-rail {
  flex: 0 0 var(--rail-w);
  position: relative;
  background: var(--bg-1);
  border-right: 1px solid var(--line);
  /* flex column: rail-footer sticks to top, rail-body scrolls below it */
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Scrollable filter content */
.rail-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 14px 16px 8px;
}

/* Always-visible header: match count + reset.
   Desktop: column layout. Mobile overrides to row. */
.rail-footer {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-1);
}

.rail-match-count {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg-2);
  white-space: nowrap;
  /* button reset */
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  cursor: pointer;
  text-align: left;
}
.rail-match-num {
  font-size: 16px;
  font-weight: 700;
  color: var(--accent-ink);
  font-variant-numeric: tabular-nums;
}
.rail-match-lbl {
  font-size: 11px;
}

/* margin (not padding) so adjacent sections' gaps collapse with each
   other and with their own children's control/title margins -- every
   boundary in the rail (section-to-section, ctrl-to-ctrl, title-to-chips)
   ends up the same ~10px instead of stacking into uneven gaps. No divider
   line: the uppercase section titles already separate groups visually. */
.rail-section {
  margin: 10px 0;
}
.rail-section-title {
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-3);
  margin-bottom: 8px;
  font-family: var(--font-mono);
}

.search-wrap {
  position: relative;
  display: flex;
  align-items: center;
  background: var(--bg-0);
  border: 1px solid var(--line);
  border-radius: 6px;
}
.search-icon {
  position: absolute;
  left: 9px;
  color: var(--fg-3);
}
.search-input {
  background: none;
  border: none;
  outline: none;
  color: var(--fg-0);
  font: inherit;
  padding: 7px 28px;
  width: 100%;
}
.search-input::placeholder {
  color: var(--fg-3);
}
.search-clear {
  position: absolute;
  right: 4px;
  background: none;
  border: none;
  color: var(--fg-3);
  cursor: pointer;
  width: 22px;
  height: 22px;
  border-radius: 4px;
  font-size: 16px;
  line-height: 1;
}
.search-clear:hover {
  background: var(--bg-2);
  color: var(--fg-0);
}

.chiprow {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.chip {
  background: var(--bg-0);
  border: 1px solid var(--line);
  color: var(--fg-1);
  cursor: pointer;
  font: inherit;
  font-size: 11.5px;
  padding: 4px 9px;
  border-radius: 5px;
  font-family: var(--font-mono);
  transition:
    background 0.12s,
    border-color 0.12s,
    color 0.12s;
}
.chip:hover {
  border-color: var(--line-strong);
  color: var(--fg-0);
}
.chip.is-on {
  background: var(--accent-soft);
  color: var(--accent-ink);
  border-color: color-mix(in oklch, var(--accent) 40%, transparent);
}

.ctrl {
  margin: 10px 0;
}
.ctrl-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 6px;
}
.ctrl-label {
  color: var(--fg-1);
  font-size: 12px;
}
.ctrl-value {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg-0);
}
.ctrl-value-dim {
  color: var(--fg-3);
}

.single-range {
  position: relative;
  height: 24px;
}
.single-range-track {
  position: absolute;
  left: 0;
  right: 0;
  top: 11px;
  height: 2px;
  background: var(--line);
  border-radius: 999px;
}
.single-range-fill {
  position: absolute;
  top: 11px;
  height: 2px;
  border-radius: 999px;
  background: var(--accent);
}
.single-range input[type="range"] {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  width: 100%;
  background: none;
  -webkit-appearance: none;
  appearance: none;
  height: 24px;
  margin: 0;
}
.single-range input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--bg-0);
  border: 2px solid var(--accent);
  cursor: grab;
  margin-top: 0;
  box-shadow: 0 1px 3px rgb(0 0 0 / 40%);
}
.single-range input[type="range"]::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--bg-0);
  border: 2px solid var(--accent);
  cursor: grab;
}
.single-range input[type="range"]::-webkit-slider-runnable-track {
  background: transparent;
}
.single-range input[type="range"]::-moz-range-track {
  background: transparent;
}

.select {
  width: 100%;
  background: var(--bg-0);
  border: 1px solid var(--line);
  color: var(--fg-0);
  padding: 6px 8px;
  border-radius: 5px;
  font: inherit;
  font-family: var(--font-mono);
  font-size: 12px;
  margin-top: 10px;
}

/* ───────────────── buttons ──────────────────────────────────────── */

.btn {
  background: var(--bg-2);
  border: 1px solid var(--line);
  color: var(--fg-0);
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  padding: 6px 11px;
  border-radius: 5px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.btn:hover {
  background: var(--bg-3);
  border-color: var(--line-strong);
}
.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.btn-primary {
  background: var(--accent);
  color: #0e0d0b;
  border-color: var(--accent);
  font-weight: 600;
}
.btn-primary:hover {
  filter: brightness(1.08);
}
.btn-ghost {
  background: none;
}
.btn-ghost:hover {
  background: var(--bg-2);
}
.btn-mini {
  padding: 3px 8px;
  font-size: 11px;
}

/* ───────────────── results ──────────────────────────────────────── */

.results-pane {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

/* Old fixed-stats grid rules retired; everything moved into .stats-band.
   The `html[data-mono="1"] .stat-label` rule above no longer matches
   anything, harmless to leave. */
.num-sep {
  color: var(--fg-3);
  font-size: 12px;
}

.results-sql {
  background: var(--bg-0);
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 0;
  max-height: 200px;
}
.sql-label {
  padding: 6px 10px;
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--accent-ink);
  font-family: var(--font-mono);
  border-bottom: 1px solid var(--line);
  background: color-mix(in oklch, var(--accent) 9%, var(--bg-0));
  display: flex;
  align-items: center;
  gap: 8px;
}
.sql-label::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--accent);
  box-shadow: 0 0 6px var(--accent);
  animation: pulse 1.6s ease-in-out infinite;
}
@keyframes pulse {
  50% {
    opacity: 0.35;
  }
}
.sql-body {
  margin: 0;
  padding: 10px 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-1);
  white-space: pre-wrap;
  overflow-y: auto;
  line-height: 1.5;
}

/* "Restricted to" summary -- collapsed by default to just the count
   + a toggle.  Expanded reveals a vertical list of dispensaries.  No
   more horizontal chip-wrap, no overflow measurement. */
.pref-strip {
  display: flex;
  flex-direction: column;
  padding: 10px 16px;
  border-top: 1px solid var(--line);
  flex-shrink: 0;
}
.pref-strip-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 22px;
}
.pref-strip-label {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--fg-2);
  white-space: nowrap;
}
.pref-strip-actions {
  display: flex;
  gap: 4px;
  align-items: center;
  flex-shrink: 0;
}
.pref-strip-toggle {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--accent-ink);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
}
.pref-strip-toggle:hover {
  color: var(--fg-0);
}
.pref-strip-chevron {
  font-size: 9px;
  color: var(--fg-2);
  transition: color 0.1s;
}
.pref-strip-toggle:hover .pref-strip-chevron {
  color: var(--fg-0);
}

/* Expanded list: vertical, one row per dispensary, scrollable when it
   gets long so the table below stays in view. */
.pref-list {
  list-style: none;
  margin: 6px 0 2px;
  padding: 0;
  max-height: 220px;
  overflow-y: auto;
  border: 1px solid color-mix(in oklch, var(--accent) 20%, transparent);
  border-radius: 4px;
  background: var(--bg-0);
}
.pref-list-row {
  display: flex;
  align-items: center;
  position: relative;
  width: 100%;
  padding: 5px 10px;
  border-bottom: 1px solid var(--line);
  background: none;
  border-left: none;
  border-right: none;
  border-top: none;
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  text-align: left;
  color: var(--fg-0);
}
.pref-list-row:last-child {
  border-bottom: none;
}
.pref-list-row:hover {
  background: var(--bg-3);
}
.pref-list-name {
  color: var(--fg-0);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
  min-width: 0;
}
.pref-list-remove-hint {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 10px;
  color: var(--fg-3);
  font-family: var(--font-mono);
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.15s;
  pointer-events: none;
  background: var(--bg-3);
  padding-left: 4px;
}
.pref-list-row:hover .pref-list-remove-hint {
  opacity: 1;
}

.terp-card {
  display: flex;
  flex-direction: column;
  width: max-content;
  flex-shrink: 0;
  gap: 5px;
  background: var(--bg-2);
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  padding: 6px 10px;
}
.terp-card-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}
.terp-card-name {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--fg-0);
  letter-spacing: 0.02em;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.terp-card-pct {
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  color: var(--accent-ink);
  flex-shrink: 0;
}

/* ─── table ─── */

.table-wrap {
  flex: 1;
  overflow: auto;
  min-width: 0;
}
.results-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
  table-layout: fixed;
  /* min-width (sum of the fixed columns' widths) is set inline by query.tsx
     -- see fixedColsWidth. Without it, table-layout:fixed silently shrinks
     every column proportionally to fit whenever their sum exceeds the
     wrapper (ignoring their set widths -- this is what let DOSE ellipsize
     with no way to widen it back). With the floor, the table overflows
     .table-wrap (which scrolls horizontally) instead of squeezing. */
}
/* Column widths are set as inline styles on <col> elements by the JSX.
   Store column has no inline width and takes whatever space remains
   (within the width:100% budget once the min-width floor is satisfied).
   See the `cols` array in query.tsx for the actual widths. */
/* Extra left padding on store cells creates visible breathing room between
   the right-aligned ADDED column and the left-aligned STORE column. */
.results-table .td-store,
.results-table th.th-store {
  padding-left: 24px;
}
.results-table th,
.results-table td {
  text-align: left;
  vertical-align: middle;
  padding: 0 12px;
  height: var(--row-h);
  border-bottom: 1px solid var(--line);
  overflow: hidden;
}
.results-table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bg-1);
  color: var(--fg-2);
  font-weight: 500;
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-family: var(--font-mono);
  /* Columns are a fixed size (no drag-to-resize); only sortable headers
     are clickable, so they alone get the pointer affordance. */
  cursor: default;
  user-select: none;
  white-space: nowrap;
  border-bottom: 1px solid var(--line-strong);
  /* Extra right padding gives the sort glyph and the column-boundary
     border (below) some breathing room from the label text. */
  padding-right: 18px;
}
.results-table thead th.is-sortable {
  cursor: pointer;
}
/* Column-boundary separator: a plain border, not a JS-rendered element --
   crisp at every boundary, never clipped or misaligned. Every header except
   the first gets one on its leading edge (the boundary with its left
   neighbour). Previously this was a ::after pseudo-element centered on the
   cell edge and half-clipped by the cell's overflow:hidden, so sub-pixel
   rounding rendered or dropped it inconsistently per column/zoom -- e.g. no
   line between PRODUCT and BRAND, or between THC and TERPS. */
.results-table thead th + th {
  border-left: 1px solid var(--line-strong);
}
.results-table thead th:hover {
  color: var(--fg-0);
}
/* Active sort column: accent underline + full-brightness text */
.results-table thead th.is-sort-active {
  color: var(--fg-0);
  box-shadow: inset 0 -2px 0 var(--accent);
}
/* .sort-glyph base colours live in /table.css. */

/* Resizable drag handle: used interactively by the filter-rail's own
   resizer. The results table has fixed column widths and doesn't render
   this element -- see the border-based separator above. 8px hit zone
   pinned inside the element's right edge, with a ::after separator centered
   on that edge (right:0 + translateX(50%) shifts the 1px line onto the
   boundary). */
.col-resize-handle {
  position: absolute;
  top: 0;
  right: 0;
  width: 8px;
  height: 100%;
  cursor: col-resize;
  touch-action: none;
}
.col-resize-handle::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  transform: translateX(50%);
  width: 1px;
  height: 100%;
  background: var(--line-strong);
  transition:
    background 0.12s,
    width 0.12s;
}
.col-resize-handle:hover::after {
  background: var(--accent);
  width: 2px;
}

.results-table tbody tr:hover {
  background: var(--bg-1);
}
.results-table tbody tr:nth-child(2n) {
  background: color-mix(in oklch, var(--bg-1) 32%, transparent);
}
.results-table tbody tr:nth-child(2n):hover {
  background: var(--bg-1);
}

/* .th-num / .td-num / .num-fixed → /table.css */
.td-added.is-floor {
  color: var(--fg-3);
}

.th-cat {
  width: 70px;
}

.cat-pill {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 3px;
  font-size: 10px;
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: lowercase;
}
.cat-flower {
  color: var(--cat-flower);
  background: color-mix(in oklch, var(--cat-flower) 18%, transparent);
}
.cat-extract {
  color: var(--cat-extract);
  background: color-mix(in oklch, var(--cat-extract) 18%, transparent);
}
.cat-vape {
  color: var(--cat-vape);
  background: color-mix(in oklch, var(--cat-vape) 18%, transparent);
}
.cat-edible {
  color: var(--cat-edible);
  background: color-mix(in oklch, var(--cat-edible) 18%, transparent);
}
.cat-topical {
  color: var(--cat-topical);
  background: color-mix(in oklch, var(--cat-topical) 18%, transparent);
}
.cat-tincture {
  color: var(--cat-tincture);
  background: color-mix(in oklch, var(--cat-tincture) 18%, transparent);
}

.td-product-name {
  color: var(--fg-0);
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
/* Text-node children of a flex container can't be targeted by CSS, so
   the product name is wrapped in a span; this rule does the actual
   ellipsis. */
.td-product-text {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* td-product is the positioning root for the hover tooltip; overflow:visible
   lets the tooltip escape the cell without disturbing the fixed table layout. */
.results-table .td-product {
  overflow: visible;
  position: relative;
}

.td-brand {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.td-store {
  overflow: hidden;
}
.td-store .store-link {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: inline-block;
}
.td-price {
  color: var(--fg-1);
  line-height: 1.15;
}
.td-price-was {
  display: block;
  font-size: 10px;
  color: var(--fg-3);
  text-decoration: line-through;
  font-variant-numeric: tabular-nums;
}
.td-price.is-sale .td-price-now {
  color: var(--accent-ink);
  font-weight: 600;
}
.dim {
  color: var(--fg-3);
}

.stype {
  display: inline-grid;
  place-items: center;
  width: 16px;
  height: 16px;
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 10px;
  flex-shrink: 0;
  line-height: 1;
}
.stype-indica {
  background: oklch(36% 0.06 280deg);
  color: oklch(85% 0.1 290deg);
}
.stype-sativa {
  background: oklch(36% 0.06 80deg);
  color: oklch(86% 0.12 95deg);
}
.stype-hybrid {
  background: oklch(36% 0.06 140deg);
  color: oklch(86% 0.12 145deg);
}

.store-link {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--fg-1);
  font: inherit;
  font-size: 12px;
  padding: 0;
  margin: 0;
  text-align: left;
}
.store-link:hover {
  color: var(--accent-ink);
}

/* Store popup — position:fixed escapes any overflow:auto ancestor (table scroll). */
.store-popup {
  position: fixed;
  z-index: 9999;
  transform: translateY(calc(-100% - 6px));
  background: #16140f;
  border: 1px solid #2b2820;
  border-radius: 6px;
  padding: 7px 11px;
  display: flex;
  align-items: center;
  gap: 10px;
  box-shadow: 0 4px 14px rgb(0 0 0 / 35%);
  white-space: nowrap;
  font-size: 11.5px;
  pointer-events: auto;
}
/* Shared popup content — distance span and directions link used in both
   .wb-tooltip (map marker) and .store-popup (table/mobile). */
.wb-popup-dist {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--accent);
}
.wb-popup-dir {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: #a09880;
  text-decoration: none;
  white-space: nowrap;
}
.wb-popup-dir:hover {
  text-decoration: underline;
}
.wb-popup-shop {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: #a09880;
  text-decoration: none;
  white-space: nowrap;
}
.wb-popup-shop:hover {
  text-decoration: underline;
}

/* Multi-store row — informational text, no button (row click opens detail) */
.store-count {
  font-size: 12px;
  color: var(--fg-2);
  font-family: var(--font-mono);
}

.td-empty {
  height: 120px !important;
  text-align: center !important;
  color: var(--fg-2);
  font-family: var(--font-mono);
}

.results-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 20px;
  border-top: 1px solid var(--line);
  background: var(--bg-1);
  font-family: var(--font-mono);
  font-size: 11.5px;
}
.page-info {
  color: var(--fg-2);
}
.pager {
  display: flex;
  align-items: center;
  gap: 3px;
}
.pager-btn {
  padding: 3px 7px;
  font-size: 13px;
  line-height: 1;
  min-width: 26px;
  justify-content: center;
}
.page-of {
  color: var(--fg-2);
  padding: 0 5px;
  letter-spacing: 0.01em;
}
.page-sep {
  color: var(--fg-3);
  margin: 0 2px;
}

/* ───────────────── map ──────────────────────────────────────────── */

.map-pane {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
}
.btn-icon {
  background: var(--bg-2);
  border: 1px solid var(--line);
  color: var(--fg-0);
  cursor: pointer;
  font: inherit;
  padding: 5px;
  border-radius: 5px;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.btn-icon:hover {
  background: var(--bg-3);
  border-color: var(--line-strong);
}
.btn-icon:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
@keyframes loc-pulse {
  0%,
  100% {
    opacity: 0.5;
  }
  50% {
    opacity: 1;
  }
}
/* Floating toast over the map — the Locate button now lives in the topbar,
   so geolocation errors surface here instead of inline beside the button. */
.locate-error {
  position: absolute;
  top: 12px;
  left: 0;
  right: 0;
  margin-inline: auto;
  width: max-content;
  max-width: 80%;
  z-index: 600;
  font-size: 12px;
  color: #fff;
  background: #ef4444;
  border-radius: 6px;
  padding: 6px 12px;
  box-shadow: 0 4px 16px rgb(0 0 0 / 25%);
}
.map-canvas {
  flex: 1;
  min-height: 0;
  background: #0f1a13;
}
.leaflet-tile-pane {
  filter: brightness(1.5);
}

.map-callout {
  position: absolute;
  bottom: 16px;
  left: 0;
  right: 0;
  margin-inline: auto;
  width: calc(100% - 40px);
  max-width: 900px;
  z-index: 500;
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 4px 8px 6px 4px;
  display: flex;
  flex-direction: column;
  gap: 0;
  box-shadow: 0 4px 16px rgb(0 0 0 / 25%);
}
.map-callout-row {
  display: flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}
.map-callout-hint {
  text-align: center;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--fg-3);
  padding: 0 8px 2px;
  user-select: none;
}
.map-callout-locate {
  display: flex;
  align-items: center;
  gap: 7px;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--fg-0);
  font: inherit;
  font-size: 12px;
  font-family: var(--font-mono);
  padding: 5px 12px;
  border-radius: 999px;
  flex-shrink: 0;
  transition: background 0.12s;
}
.map-callout-locate:hover {
  background: var(--bg-2);
}
.map-callout-locate:disabled {
  opacity: 0.6;
  cursor: default;
}
.map-callout-locate.is-on {
  color: var(--accent-ink);
}
.map-callout-locate.is-on svg {
  stroke: var(--accent);
}
.map-callout-locate.is-locating {
  animation: loc-pulse 1s ease-in-out infinite;
}
.map-callout-locate-label {
  white-space: nowrap;
}
.map-callout-close {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--fg-3);
  font-size: 16px;
  line-height: 1;
  padding: 2px 6px;
  border-radius: 999px;
  flex-shrink: 0;
}
.map-callout-close:hover {
  color: var(--fg-0);
  background: var(--bg-2);
}
.map-callout input[type="range"] {
  flex: 1;
  min-width: 0;
  accent-color: var(--accent);
}
.map-callout input[type="range"]:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
/* Mobile: full-width pill with small edge margins; slider grows to fill.
   position:fixed so the pill is viewport-relative and not affected by the
   map toolbar overflowing .map-pane beyond the viewport width. */
html[data-mobile="1"] .map-callout {
  position: fixed;
  left: 12px;
  right: 12px;
  width: auto;
  margin-inline: 0;
}

/* Bigger thumb (26px) for comfortable dragging; explicit track so
   we can control thumb vertical centering after removing native appearance. */
html[data-mobile="1"] .map-callout input[type="range"] {
  flex: 1;
  min-width: 0;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  height: 36px;
}
html[data-mobile="1"] .map-callout input[type="range"]::-webkit-slider-runnable-track {
  height: 3px;
  background: var(--line);
  border-radius: 999px;
}
html[data-mobile="1"] .map-callout input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  margin-top: -11.5px;
  background: var(--accent);
  border: 2px solid var(--bg-1);
  box-shadow: 0 1px 4px rgb(0 0 0 / 20%);
  cursor: pointer;
}
html[data-mobile="1"] .map-callout input[type="range"]::-moz-range-track {
  height: 3px;
  background: var(--line);
  border-radius: 999px;
}
html[data-mobile="1"] .map-callout input[type="range"]::-moz-range-thumb {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--bg-1);
  box-shadow: 0 1px 4px rgb(0 0 0 / 20%);
}
html[data-mobile="1"] .leaflet-control-zoom {
  display: none;
}
.leaflet-control-zoom a {
  background: #fff;
  color: #222;
  border-bottom: 1px solid #ddd;
}

/* Cannabis-leaf marker using the real traced leaf.svg.
   Unselected: small, desaturated, semi-transparent.
   Selected: full size, full color, accent halo. */
.wb-marker {
  position: relative;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition:
    transform 0.14s ease,
    filter 0.14s ease;
}
.wb-marker:hover {
  transform: scale(1.15);
}

.wb-leaf {
  width: 22px;
  height: 22px;
  display: block;
  filter: opacity(0.45);
  transition: filter 0.14s ease;
}

/* Selected state */
.wb-marker.is-on .wb-leaf {
  filter: none;
}
.wb-marker.is-on::before {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 999px;
  border: 2px solid var(--accent);
  background: transparent;
  z-index: -1;
}
/* Marker about to be deselected during a circle drag — pulsates */
@keyframes wb-pending-remove {
  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.35;
    transform: scale(0.78);
  }
}
.wb-marker-wrap.is-pending-remove .wb-marker,
.is-pending-remove .wb-marker {
  animation: wb-pending-remove 0.7s ease-in-out infinite;
}
/* Marker about to be selected during a circle drag — show the
   selected ring eagerly so the user sees the future state. */
.is-pending-add .wb-marker::before {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 999px;
  border: 2px dashed var(--accent);
  background: transparent;
  z-index: -1;
  animation: wb-pending-add 1s ease-in-out infinite;
}
@keyframes wb-pending-add {
  0%,
  100% {
    opacity: 0.55;
  }
  50% {
    opacity: 1;
  }
}

.wb-tooltip {
  background: #16140f !important;
  color: #ece6d6 !important;
  border: 1px solid #2b2820 !important;
  border-radius: 6px !important;
  padding: 6px 9px !important;
  font-family: var(--font-ui);
  box-shadow: 0 4px 14px rgb(0 0 0 / 35%) !important;
}
.wb-tooltip::before {
  display: none !important;
}
.wb-tip-name {
  font-size: 12px;
  color: #ece6d6;
}
.wb-tip-footer {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-top: 4px;
}
/* .wb-popup-dist / .wb-popup-dir defined above (shared with .store-popup) */

.wb-geo-center {
  background: transparent !important;
  border: none !important;
}
.wb-geo-center-inner {
  width: 44px;
  height: 44px;
  border-radius: 999px;
  background: rgb(255 255 255 / 95%);
  border: 2.5px solid var(--accent);
  box-shadow: 0 2px 10px rgb(0 0 0 / 30%);
  cursor: grab;
  display: grid;
  place-items: center;
}
.wb-geo-center-inner::after {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 999px;
  background: var(--accent);
}

/* ═══════════════════════════════════════════════════════════════
   Mobile layout  (html[data-mobile="1"])
   Two full-screen activities: Map → Products.
   Filter rail becomes a slide-in drawer; Ask bar sits at the top
   of the Products screen; text search inline in mobile toolbar.
   ═══════════════════════════════════════════════════════════════ */

/* Topbar: strip out desktop-only chrome */
html[data-mobile="1"] .topbar {
  padding: 0 12px;
  gap: 8px;
}
html[data-mobile="1"] .tabs,
html[data-mobile="1"] .topbar-right,
html[data-mobile="1"] .pending-counts-note {
  display: none;
}
html[data-mobile="1"] .brand-name {
  font-size: 22px;
}
html[data-mobile="1"] .brand-icon {
  width: 26px;
  height: 26px;
}
html[data-mobile="1"] .brand {
  gap: 6px;
}

/* Mobile nav buttons */
/* No margin-left:auto here — on the map screen the Clear icon button
   carries the auto, grouping [Clear][save] on the right.  When the
   topbar doesn't include Clear (e.g. mobile products screen), the
   immediately preceding sibling owns the auto instead. */
.mobile-save-btn {
  background: var(--accent);
  border: none;
  border-radius: 6px;
  color: #fff;
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 7px 12px;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.mobile-save-btn span[aria-hidden] {
  font-size: 9px;
}
/* Topbar "Filter N products" pill — mobile products screen (opens the
   filter drawer) and desktop with the rail collapsed (re-expands it).
   The live N is propagated up from QueryView. */
.filter-summary-btn {
  background: none;
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--fg-0);
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  padding: 6px 11px;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  line-height: 1;
  gap: 5px;
}
.filter-summary-btn:hover {
  background: var(--bg-2);
}
.filter-summary-center {
  flex: 1;
  display: flex;
  justify-content: center;
}
.filter-icon {
  width: 14px;
  height: 11px;
  flex-shrink: 0;
}
.filter-summary-btn.has-active {
  border-color: var(--accent);
}
.filter-summary-btn.has-active .filter-icon circle {
  fill: var(--accent);
}
.mobile-map-btn {
  background: var(--accent);
  border: none;
  border-radius: 6px;
  color: #fff;
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 7px 12px;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.mobile-map-btn span[aria-hidden] {
  font-size: 9px;
}
.mobile-map-btn .tab-badge {
  background: #fff;
  color: var(--accent);
}
.filter-summary-btn .mono {
  font-family: var(--font-mono);
  font-weight: 700;
  color: var(--accent-ink);
}

/* Filter rail becomes a fixed left-side drawer on mobile */
html[data-mobile="1"] .filter-rail {
  position: fixed;
  left: 0;
  top: 0;
  width: 85vw;
  max-width: 340px;
  height: 100dvh;
  z-index: 200;
  overflow: hidden;
  transform: translateX(-100%);
  transition: transform 200ms ease;
  flex: none;
}
/* Android back-gesture clearance moves to the scrollable body and footer */
html[data-mobile="1"] .rail-body {
  padding-left: 28px;
  padding-right: 28px;
}
html[data-mobile="1"] .rail-footer {
  flex-direction: row;
  align-items: center;
  gap: 12px;
  padding-left: 28px;
  padding-right: 28px;
}
/* Shrink brand chip list on mobile so sliders stay reachable without much scrolling */
html[data-mobile="1"] .brand-scroll {
  max-height: 96px;
}
html[data-mobile="1"] .filter-rail.is-open {
  transform: translateX(0);
  box-shadow: 6px 0 32px rgb(0 0 0 / 45%);
}
/* Dim overlay behind open drawer */
.filter-overlay {
  position: fixed;
  inset: 0;
  z-index: 199;
  background: rgb(0 0 0 / 50%);
}
/* First-visit splash modal — must sit above Leaflet, which paints its
   marker / popup / control panes at z-index 400–1000 (see leaflet.css).
   At z-index 201 the splash overlay still dimmed the screen but Leaflet
   punched through the middle, hiding the splash card behind the map. */
.splash-overlay {
  position: fixed;
  inset: 0;
  z-index: 10001;
  background: rgb(0 0 0 / 50%);
  display: flex;
  align-items: center;
  justify-content: center;
}
.splash-card {
  background: var(--bg-1);
  border-radius: 10px;
  padding: 28px 32px;
  max-width: 520px;
  width: 90%;
  max-height: 80vh;
  overflow-y: auto;
  box-shadow: 0 8px 40px rgb(0 0 0 / 50%);
  font-family: var(--font-body);
}
.splash-card h1 {
  font-family: "Barlow Semi Condensed", Geist, system-ui, sans-serif;
  font-weight: 800;
  letter-spacing: -0.01em;
}
.splash-card h2,
.splash-card h3 {
  font-family: var(--font-display);
  font-weight: 600;
}
.splash-btn {
  margin-top: 20px;
  float: right;
  background: var(--accent);
  border: none;
  border-radius: 6px;
  color: #fff;
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 7px 12px;
  white-space: nowrap;
}
/* PA MMJ-card gate — entry confirmation, above splash (and above Leaflet). */
.age-gate-overlay {
  position: fixed;
  inset: 0;
  z-index: 10002;
  background: rgb(0 0 0 / 50%);
  display: flex;
  align-items: center;
  justify-content: center;
}
.age-gate-card {
  background: var(--bg-1);
  border-radius: 10px;
  padding: 32px 36px;
  max-width: 420px;
  width: 90%;
  box-shadow: 0 8px 40px rgb(0 0 0 / 50%);
  font-family: var(--font-body);
  text-align: center;
}
.age-gate-q {
  font-family: "Barlow Semi Condensed", Geist, system-ui, sans-serif;
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin-bottom: 22px;
}
.age-gate-btns {
  display: flex;
  gap: 12px;
  justify-content: center;
}
.age-gate-btn {
  border-radius: 6px;
  padding: 7px 12px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  min-width: 96px;
}
.age-gate-btn.is-yes {
  background: var(--accent);
  color: #fff;
  border: none;
}
.age-gate-btn.is-no {
  background: transparent;
  color: var(--fg-1);
  border: 1px solid var(--fg-3);
}
.age-gate-decline {
  font-size: 15px;
  line-height: 1.5;
  color: var(--fg-1);
}
.age-gate-decline a {
  color: var(--accent);
  text-decoration: underline;
}
/* About / feedback modal — the whole brand area is the trigger */
button.brand-tappable {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.brand-tappable:hover {
  opacity: 0.85;
}
.brand-tappable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}
/* Pulse the brand until the user opens About once (wb.about.seen.v1). */
.brand.is-pulsing {
  animation: brand-pulse 2.4s ease-in-out 4;
  transform-origin: left center;
}
@keyframes brand-pulse {
  0%,
  100% {
    transform: scale(1);
    filter: drop-shadow(0 0 0 transparent);
  }
  50% {
    transform: scale(1.035);
    filter: drop-shadow(0 0 6px var(--accent-soft));
  }
}
.about-overlay {
  position: fixed;
  inset: 0;
  z-index: 10001;
  background: rgb(0 0 0 / 55%);
  display: flex;
  align-items: center;
  justify-content: center;
}
.about-card {
  position: relative;
  background: var(--bg-1);
  border-radius: 10px;
  padding: 28px 32px;
  max-width: 520px;
  width: 90%;
  max-height: 80vh;
  overflow-y: auto;
  box-shadow: 0 8px 40px rgb(0 0 0 / 50%);
  font-family: var(--font-body);
}
.about-close {
  position: absolute;
  top: 10px;
  right: 12px;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--fg-3);
  font-size: 22px;
  line-height: 1;
  padding: 4px 6px;
}
.about-close:hover {
  color: var(--fg-1);
}
.about-body {
  margin-bottom: 24px;
}
.about-body h1 {
  font-family: "Barlow Semi Condensed", Geist, system-ui, sans-serif;
  font-weight: 800;
  letter-spacing: -0.01em;
}
.about-body h2,
.about-body h3 {
  font-family: var(--font-display);
  font-weight: 600;
}
/* Wordmark + short git id (fallback about-body only -- a custom about_html
   supplies its own heading). Version stays faint; the inventory-updated
   line below uses the same fg-2 as the paragraph -- it's current info the
   patient should actually read, not a faint technical aside. */
.about-heading-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0 0 10px;
}
.about-heading-row h2 {
  margin: 0;
}
.about-version {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-3);
  opacity: 0.65;
}
.about-updated {
  margin-top: 24px;
  margin-bottom: 24px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--fg-2);
}
/* Feedback form */
.feedback-form {
  border-top: 1px solid var(--bg-3);
  padding-top: 20px;
}
.feedback-heading {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 15px;
  margin-bottom: 10px;
  color: var(--fg-1);
}
.feedback-direct {
  font-size: 13px;
  color: var(--fg-2);
  margin-bottom: 16px;
  line-height: 1.5;
}
.feedback-direct a {
  color: var(--accent);
  text-decoration: none;
}
.feedback-direct a:hover {
  text-decoration: underline;
}

/* Hide rail resize handle on mobile (drawer width is CSS-fixed) */
html[data-mobile="1"] .filter-rail .col-resize-handle {
  display: none;
}
/* Keep terp names capped on mobile so the card stays narrow for side-by-side layout */
html[data-mobile="1"] .terp-card-name {
  max-width: 90px;
}

/* Mobile toolbar: inline search + Filters button */
.mobile-toolbar {
  display: none;
}
html[data-mobile="1"] .mobile-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-1);
  flex: 0 0 auto;
}
.mobile-filter-btn {
  white-space: nowrap;
  flex: 0 0 auto;
  background: var(--bg-0);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--fg-0);
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  padding: 6px 11px;
}
.mobile-filter-btn.has-active {
  border-color: var(--accent);
  color: var(--accent);
}

/* Rendered inside .pulldown-body-inner (mobile only) — stays above keyboard */
.mobile-match-count {
  padding: 5px 8px 3px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-2);
  flex-shrink: 0;
}
.mobile-match-num {
  color: var(--fg-0);
}

/* ─── Mobile card list (.m-list) ────────────────────────────────
   Two-column scrolling list shown on mobile in place of the table.
   Each .m-row shows product name + store name; tapping opens an
   inline detail panel. */
.m-list {
  list-style: none;
  margin: 0;
  padding: 0;
  flex: 1;
  overflow: hidden auto;
  min-width: 0;
  /* MobileProductDetail (query.tsx) does its own scroll-position fixup when
     a row's detail collapses back to its compact height. Native CSS scroll
     anchoring support is inconsistent across browsers (notably Safari), so
     rather than get correct behavior on some browsers and none on others,
     opt out everywhere and let the JS be the single, consistent mechanism --
     letting both act at once double-corrects and overshoots. */
  overflow-anchor: none;
}
.m-row {
  border-bottom: 1px solid var(--line);
}
.m-row-main {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 8px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
/* When a row is open, the row header + detail panel form one
   accent-tinted group with a 3px lime stripe down the left edge and
   a 2px accent terminator at the bottom — visually bracketing the
   pair so they read as a single unit until the user collapses it. */
.m-row.is-open {
  position: relative;
}
.m-row.is-open::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--accent);
  pointer-events: none;
}
.m-row-product {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 6px;
}
.m-row-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
  color: var(--fg-0);
}
.m-row-store {
  flex-shrink: 0;
  font-size: 12px;
  color: var(--fg-2);
  font-family: var(--font-mono);
  text-align: right;
  max-width: 42%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.m-empty {
  padding: 20px 16px;
  color: var(--fg-3);
  font-size: 13px;
  list-style: none;
}
.m-sort-rail {
  display: flex;
  gap: 6px;
  padding: 7px 12px 6px;
  flex-shrink: 0;
  border-bottom: 1px solid var(--line);
  /* The price chip's per-category label ("$ PER 1/8TH") is wider than the
     others, so chips size to content and fill the width when they fit; if a
     label overflows on a narrow phone, the rail scrolls rather than clipping. */
  overflow-x: auto;
}
.m-sort-chip {
  /* grow to fill when the row has room, but never shrink below the label
     (flex-shrink 0) -- a long label overflows into the rail's scroll. */
  flex: 1 0 auto;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-align: center;
  padding: 4px 8px;
  border-radius: 3px;
  border: 1px solid var(--line-strong);
  color: var(--fg-2);
  background: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  white-space: nowrap;
}
.m-sort-chip.is-active {
  border-color: transparent;
  background: var(--accent-soft);
  color: var(--accent-ink);
}
/* Collapse-all chip shared by mobile sort rail and desktop product header.
   Distinct fg-1 border so it stands apart from sort chips/headers when it
   appears.  Sized to slot into either container without throwing off layout. */
.collapse-all-btn {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1;
  padding: 2px 6px;
  border: 1px solid var(--fg-1);
  border-radius: 3px;
  background: var(--accent-soft);
  color: var(--accent-ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  white-space: nowrap;
}
.m-sort-rail .collapse-all-btn {
  padding: 4px 6px;
  font-size: 11px;
}
.results-th .collapse-all-btn {
  margin-right: 6px;
}
.m-row-sort-val {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--accent-ink);
  min-width: 5.5ch;
  text-align: right;
}
.product-detail-mobile {
  padding: 10px 14px 14px;
  background: var(--bg-0);
}

/* ─── Mobile pulldown panel ────────────────────────────────────
   A slide-down drawer that houses the Ask box, search + Filters,
   and the preferred-stores summary. When tucked away, only the
   results table is visible above the handle tab.

   The grid-template-rows 0fr↔1fr trick gives a smooth auto-height
   transition without measuring the content. Inner-inner div
   ensures the row transitions correctly. */
.pulldown {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  background: var(--bg-1);
  position: relative;
  /* a faint amber rim along the top edge — like firelight catching
     the lip of a drawer */
  box-shadow: inset 0 1px 0 0 oklch(76% 0.17 75deg / 8%);
}
.pulldown-body {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 320ms cubic-bezier(0.22, 1, 0.36, 1);
  background: var(--bg-1);
}
.pulldown.is-closed .pulldown-body {
  grid-template-rows: 0fr;
}
.pulldown-body-inner {
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: opacity 200ms ease;
}
.pulldown.is-closed .pulldown-body-inner {
  opacity: 0;
}

/* The pulldown wraps several borderless sections — knock the
   double-borders out so it reads as one continuous surface. */
.pulldown .views-row,

/* The Ask cell inside the pulldown — its own little stage. */
.pulldown-ask {
  padding: 10px 12px 12px;
  background: var(--bg-1);
  border-bottom: 1px solid var(--line);
  position: relative;
}
.pulldown-section-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-ink);
  margin: 0 0 7px 1px;
}
/* The handle: always visible, the only thing left when the panel is closed. */
.pulldown-handle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  background: var(--bg-1);
  border: none;
  border-bottom: 1px solid var(--line);
  padding: 7px 0;
  cursor: pointer;
  font: inherit;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-2);
  -webkit-tap-highlight-color: transparent;
  transition: color 0.15s;
}
.pulldown-handle:hover {
  color: var(--fg-1);
}
.pulldown-handle:focus-visible {
  outline: none;
}
.pulldown.is-closed .pulldown-handle {
  color: var(--accent-ink);
  border-top: 1px solid var(--line);
}

/* ─── Views row (saved views + quick chips) ──────────────────── */
.views-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-1);
  flex: 0 0 auto;
  flex-wrap: wrap;
  min-height: 38px;
}
.views-row-quick {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
  align-items: center;
}
.views-row-sep {
  width: 1px;
  height: 18px;
  background: var(--line-strong);
  flex-shrink: 0;
  align-self: center;
}
.views-row-saved {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
  align-items: center;
}

.quick-chip {
  background: var(--bg-0);
  border: 1px solid var(--line);
  color: var(--fg-2);
  cursor: pointer;
  font: inherit;
  font-size: 11.5px;
  font-family: var(--font-mono);
  padding: 3px 9px;
  border-radius: 999px;
  transition:
    background 0.12s,
    border-color 0.12s,
    color 0.12s;
  white-space: nowrap;
}
.quick-chip:hover {
  border-color: var(--line-strong);
  color: var(--fg-0);
  background: var(--bg-2);
}
.quick-chip.is-on {
  background: var(--accent-soft);
  color: var(--accent-ink);
  border-color: color-mix(in oklch, var(--accent) 40%, transparent);
}

.view-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--bg-0);
  border: 1px solid var(--line);
  color: var(--fg-1);
  cursor: pointer;
  font: inherit;
  font-size: 11.5px;
  padding: 3px 6px 3px 9px;
  border-radius: 4px;
  transition:
    background 0.12s,
    border-color 0.12s;
  white-space: nowrap;
}
.view-chip:hover {
  border-color: var(--line-strong);
  color: var(--fg-0);
}
.view-chip.is-on {
  background: var(--accent-soft);
  color: var(--accent-ink);
  border-color: color-mix(in oklch, var(--accent) 50%, transparent);
}
.view-chip-name {
  max-width: 16ch;
  overflow: hidden;
  text-overflow: ellipsis;
}
.view-chip-del {
  color: var(--fg-3);
  font-size: 13px;
  line-height: 1;
  padding: 0 2px;
  border-radius: 3px;
  cursor: pointer;
}
.view-chip-del:hover {
  color: var(--fg-0);
  background: var(--bg-3);
}
.view-chip-add {
  background: none;
  border: 1px dashed var(--line);
  color: var(--fg-3);
  cursor: pointer;
  font: inherit;
  font-size: 11.5px;
  padding: 3px 9px;
  border-radius: 4px;
  transition:
    border-color 0.12s,
    color 0.12s;
  white-space: nowrap;
}
.view-chip-add:hover {
  border-color: var(--accent);
  color: var(--accent-ink);
}
.view-name-input {
  background: var(--bg-0);
  border: 1px solid var(--accent);
  color: var(--fg-0);
  font: inherit;
  font-size: 11.5px;
  padding: 3px 8px;
  border-radius: 4px;
  outline: none;
  width: 14ch;
}

/* ─── Rail collapse ──────────────────────────────────────────── */
/* Collapsed rail (desktop) shrinks to 0 width -- entry point back in
   is the topbar's Filter-N-products pill (.filter-summary-btn), not an
   in-rail control. */
.filter-rail.is-collapsed .rail-body,
.filter-rail.is-collapsed .rail-footer {
  display: none;
}

/* Collapsed rows are click-to-open; the open row (product-detail-row) isn't
   clickable as a whole -- only its header closes it -- so reset the cursor. */
.result-row {
  cursor: pointer;
}
.result-row.product-detail-row {
  cursor: default;
}

/* ─── Product detail (desktop) ──────────────────────────────────
   Open row: its columns are replaced in place by one colSpan detail
   cell. Mirror the mobile open panel — bg-0 fill, 3px lime left stripe
   (inset box-shadow, no layout shift), 2px accent bottom terminator.
   The base .results-table td rule fixes row height and clips overflow;
   the detail cell must undo both so the full panel shows, and the
   padding !important beats the base 0-12px cell padding. */
.product-detail-row > td {
  background: var(--bg-0);
  border-bottom: 2px solid var(--line-strong);
  box-shadow: inset 3px 0 0 var(--accent);
  padding: 10px 12px !important;
  height: auto !important;
  overflow: visible !important;
}
/* Mobile uses a <div class="product-detail-cell">, not a <td>, so the
   !important above doesn't apply there; this sets its base padding.
   8px sides match .m-row-main's 8px padding so the strain badge aligns. */
.product-detail-cell {
  padding: 10px 8px 14px;
}
/* Header doubles as the close affordance: it's the same "product name" top
   line the row opened from, so clicking it collapses the row. Keeps the name
   in the row's normal type treatment (matches .td-product-text / .m-row-name)
   -- it's a name, not a title -- but lets it wrap so the full name shows. */
.product-detail-header {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin-bottom: 6px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.product-detail-name-text {
  min-width: 0;
  font-size: 14px;
  color: var(--fg-0);
}
.product-detail-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.product-detail-brand {
  font-size: 11.5px;
  color: var(--fg-2);
  font-family: var(--font-mono);
}
.product-detail-form {
  font-size: 10px;
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  color: var(--fg-2);
  border: 1px solid var(--line-strong);
  border-radius: 3px;
  padding: 1px 6px;
}
.product-detail-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 20px;
  margin-bottom: 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}
.product-detail-stat {
  display: flex;
  align-items: baseline;
  gap: 5px;
}
.product-detail-stat-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-3);
}
.product-detail-stat-val {
  font-size: 12px;
  color: var(--fg-0);
  font-variant-numeric: tabular-nums;
}
.product-detail-stat-was {
  font-size: 10px;
  color: var(--fg-3);
  text-decoration: line-through;
  font-variant-numeric: tabular-nums;
}
.product-detail-body {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: 14px 24px;
}
/* Terpenes section: natural width, doesn't compress. */
.product-detail-section {
  flex-shrink: 0;
}
/* Stores section: fills remaining width; store names ellipsize before prices hide.
   On desktop a max-width prevents it from ballooning across the full table row. */
.product-detail-stores {
  flex: 1;
  min-width: 0;
}
html[data-mobile="0"] .product-detail-stores {
  max-width: 400px;
}
.product-detail-section-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-3);
  margin-bottom: 6px;
}
.product-detail-price-unit {
  font-size: 8.5px;
  letter-spacing: 0.06em;
  text-transform: none;
  color: var(--fg-3);
}
.product-detail-store-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 4px 8px;
  border-radius: 4px;
  border: 1px solid transparent;
  margin-bottom: 2px;
}
.product-detail-store-row.is-best {
  background: var(--accent-soft);
  border-color: color-mix(in oklch, var(--accent) 30%, transparent);
}
.product-detail-store-name {
  flex: 1;
  min-width: 0;
  font-size: 12px;
  color: var(--fg-0);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.product-detail-store-price-group {
  display: flex;
  align-items: center;
  gap: 5px;
  flex-shrink: 0;
}
.product-detail-store-price {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--accent-ink);
  font-weight: 600;
  width: 32px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
/* Delta sits left of the price; hidden placeholder for the best-price row keeps
   the price column aligned. Fixed width covers "+$99" at mono 11px. */
.product-detail-store-delta {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-3);
  width: 30px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
/* ─── Split view ─────────────────────────────────────────────── */
.main.is-split {
  flex-direction: row;
}
.split-divider {
  flex: 0 0 5px;
  background: var(--line);
  cursor: col-resize;
  transition: background 0.12s;
  position: relative;
}
.split-divider:hover {
  background: var(--accent);
}
.split-view-btn {
  background: none;
  border: 1px solid var(--line);
  color: var(--fg-2);
  cursor: pointer;
  width: 28px;
  height: 28px;
  border-radius: 5px;
  font-size: 15px;
  line-height: 1;
  display: grid;
  place-items: center;
  transition:
    background 0.12s,
    color 0.12s,
    border-color 0.12s;
  flex-shrink: 0;
}
.split-view-btn:hover {
  border-color: var(--line-strong);
  color: var(--fg-0);
  background: var(--bg-2);
}
.split-view-btn.is-on {
  background: var(--accent-soft);
  border-color: color-mix(in oklch, var(--accent) 40%, transparent);
  color: var(--accent-ink);
}
