/* ============================================================
   Stackpeek side panel — tokens + component styles
   Tokens are the same contract as the marketing site.
   Applied to :root and to any [data-sp-theme] subtree so a
   single page can preview both schemes.
   ============================================================ */

:root,
[data-sp-theme] {
  --sp-font-sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --sp-font-mono: ui-monospace, "SF Mono", SFMono-Regular, "Cascadia Mono",
    "Roboto Mono", Menlo, Consolas, "Liberation Mono", monospace;

  --sp-fs-micro: 10px;
  --sp-fs-xs: 11px;
  --sp-fs-sm: 12px;
  --sp-fs-md: 13px;
  --sp-fs-lg: 15px;
  --sp-fs-xl: 17px;

  --sp-lh-tight: 1.2;
  --sp-lh-snug: 1.35;
  --sp-lh-normal: 1.55;

  --sp-fw-regular: 400;
  --sp-fw-medium: 500;
  --sp-fw-semibold: 600;

  --sp-tracking-caps: 0.08em;
  --sp-tracking-tight: -0.01em;

  --sp-space-1: 4px;
  --sp-space-2: 8px;
  --sp-space-3: 12px;
  --sp-space-4: 16px;
  --sp-space-5: 24px;
  --sp-space-6: 32px;

  --sp-hairline: 1px;
  --sp-radius-sm: 2px;
  --sp-radius-md: 4px;
  --sp-radius-lg: 6px;

  --sp-bg: #ffffff;
  --sp-bg-subtle: #f7f8f9;
  --sp-bg-inset: #f1f3f5;
  --sp-surface: #ffffff;

  --sp-border: #e3e6ea;
  --sp-border-strong: #c9ced6;

  --sp-text: #14161a;
  --sp-text-muted: #545c6a;
  --sp-text-faint: #6b7280;

  --sp-accent: #2b5ce6;
  --sp-accent-hover: #1f47bd;
  --sp-accent-on: #ffffff;
  --sp-accent-bg: #eef2ff;
  --sp-accent-border: #c3cffa;

  /* Category tints — app-category markers only. Desaturated siblings of
     the accent hue; never used for text, fills, CTAs or status. */
  --sp-tint-1: oklch(62% 0.13 265);
  --sp-tint-2: oklch(64% 0.11 200);
  --sp-tint-3: oklch(66% 0.10 155);
  --sp-tint-4: oklch(68% 0.11 75);
  --sp-tint-5: oklch(62% 0.12 320);

  /* Lightness and chroma for every category marker; the hue comes from
     the [data-sp-cat] rules further down. */
  --sp-cat-l: 64%;
  --sp-cat-c: 0.11;

  --sp-focus-ring: 2px solid var(--sp-accent);
  --sp-focus-offset: 2px;

  --sp-dur-fast: 90ms;
  --sp-dur-med: 160ms;
  --sp-ease: cubic-bezier(0.2, 0, 0.3, 1);

  color-scheme: light;
}

[data-sp-theme="dark"] {
  --sp-bg: #0e1013;
  --sp-bg-subtle: #14171c;
  --sp-bg-inset: #1a1e24;
  --sp-surface: #12151a;

  --sp-border: #262b33;
  --sp-border-strong: #3a4150;

  --sp-text: #e8ebef;
  --sp-text-muted: #a2aab6;
  --sp-text-faint: #8b939f;

  --sp-accent: #7d9bff;
  --sp-accent-hover: #9ab0ff;
  --sp-accent-on: #0b0e13;
  --sp-accent-bg: #161c2c;
  --sp-accent-border: #2c3a5e;

  --sp-tint-1: oklch(72% 0.13 265);
  --sp-tint-2: oklch(74% 0.11 200);
  --sp-tint-3: oklch(76% 0.10 155);
  --sp-tint-4: oklch(78% 0.11 75);
  --sp-tint-5: oklch(72% 0.12 320);
  --sp-cat-l: 74%;

  color-scheme: dark;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-sp-theme="light"]) {
    --sp-bg: #0e1013;
    --sp-bg-subtle: #14171c;
    --sp-bg-inset: #1a1e24;
    --sp-surface: #12151a;
    --sp-border: #262b33;
    --sp-border-strong: #3a4150;
    --sp-text: #e8ebef;
    --sp-text-muted: #a2aab6;
    --sp-text-faint: #8b939f;
    --sp-accent: #7d9bff;
    --sp-accent-hover: #9ab0ff;
    --sp-accent-on: #0b0e13;
    --sp-accent-bg: #161c2c;
    --sp-accent-border: #2c3a5e;
    --sp-tint-1: oklch(72% 0.13 265);
    --sp-tint-2: oklch(74% 0.11 200);
    --sp-tint-3: oklch(76% 0.10 155);
    --sp-tint-4: oklch(78% 0.11 75);
    --sp-tint-5: oklch(72% 0.12 320);
    --sp-cat-l: 74%;
    color-scheme: dark;
  }
}

/* ============================================================
   Panel shell
   ============================================================ */

.sp-panel {
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  min-height: 100%;
  background: var(--sp-bg);
  color: var(--sp-text);
  font-family: var(--sp-font-sans);
  font-size: var(--sp-fs-md);
  line-height: var(--sp-lh-normal);
  -webkit-font-smoothing: antialiased;
}

/* The site's type scale is a step larger at every size, so the panel declares
   its own. Custom properties inherit, so every rule inside resolves against
   these on both surfaces while the marketing page keeps its scale elsewhere.
   Colours are already identical in both files and are deliberately absent here. */
.sp-panel {
  --sp-font-sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --sp-fs-micro: 10px;
  --sp-fs-xs: 11px;
  --sp-fs-sm: 12px;
  --sp-fs-md: 13px;
  --sp-fs-lg: 15px;
  --sp-fs-xl: 17px;
  --sp-lh-tight: 1.2;
  --sp-lh-normal: 1.55;
  --sp-tracking-tight: -0.01em;
}

.sp-panel *,
.sp-panel *::before,
.sp-panel *::after { box-sizing: border-box; }
.sp-panel p, .sp-panel h1, .sp-panel h2, .sp-panel ul, .sp-panel li { margin: 0; }
.sp-panel ul { padding: 0; list-style: none; }
.sp-panel :where(a, button, input, summary):focus-visible {
  outline: var(--sp-focus-ring);
  outline-offset: var(--sp-focus-offset);
  border-radius: var(--sp-radius-sm);
}

/* ============================================================
   Everything below this line was scoped by this change. (The four rules
   directly above -- .sp-panel *, .sp-panel p/h1/h2/ul/li, .sp-panel ul, and
   .sp-panel :where(...):focus-visible -- were already scoped before it.)

   The marketing site links this same file. Eighteen selectors are defined
   both here and in stackpeek.css, thirteen with different rules, so an
   unscoped rule here silently restyles the marketing page -- or gets
   clobbered by it, depending on link order.

   App.svelte's root element is .sp-panel, so scoping changes nothing in the
   extension while giving the site specificity-based isolation that does not
   depend on load order. panel_scoping.test.ts fails on any rule that
   escapes.
   ============================================================ */

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

/* Header — persistent chrome */
.sp-panel .sp-hd {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: var(--sp-space-2);
  padding: var(--sp-space-2) var(--sp-space-3);
  border-bottom: var(--sp-hairline) solid var(--sp-border);
  background: var(--sp-bg-subtle);
}
.sp-panel .sp-hd__mark { display: flex; flex: none; }
.sp-panel .sp-hd__domain {
  flex: 1;
  min-width: 0;
  font-family: var(--sp-font-mono);
  font-size: var(--sp-fs-sm);
  color: var(--sp-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
  text-align: left;
}
.sp-panel .sp-iconbtn {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: var(--sp-hairline) solid transparent;
  border-radius: var(--sp-radius-md);
  background: transparent;
  color: var(--sp-text-muted);
  cursor: pointer;
  transition: background-color var(--sp-dur-fast) var(--sp-ease),
              color var(--sp-dur-fast) var(--sp-ease);
}
.sp-panel .sp-iconbtn:hover { background: var(--sp-bg-inset); color: var(--sp-text); }
.sp-panel .sp-iconbtn svg { width: 14px; height: 14px; display: block; }

/* Sections */
.sp-panel .sp-body { flex: 1; }
.sp-panel .sp-sec {
  border-bottom: var(--sp-hairline) solid var(--sp-border);
  padding: var(--sp-space-3);
}
.sp-panel .sp-sec__hd {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-space-2);
  margin-bottom: var(--sp-space-3);
}
/* <details> nests inside .sp-sec rather than replacing it, so the section
   landmark and its aria-labelledby survive. Both elements are layout-
   transparent, so .sp-sec__hd keeps its baseline-spread layout by moving to
   the summary. */
.sp-panel .sp-sec > details { display: block; }
.sp-panel summary.sp-sec__hd { cursor: pointer; list-style: none; }
.sp-panel summary.sp-sec__hd::-webkit-details-marker { display: none; }
/* The caret is the only new affordance. It is drawn on the summary rather than
   supplied by the UA marker so it can sit at the end of the flex row. */
.sp-panel summary.sp-sec__hd::after {
  content: "";
  width: 6px;
  height: 6px;
  border-right: var(--sp-hairline) solid var(--sp-text-faint);
  border-bottom: var(--sp-hairline) solid var(--sp-text-faint);
  transform: rotate(45deg);
  transition: transform var(--sp-dur-fast) var(--sp-ease);
}
.sp-panel details[open] > summary.sp-sec__hd::after { transform: rotate(-135deg); }
/* A collapsible head has three items where every other head has two, and
   space-between strands the count in the middle of the row. The count belongs
   where it sits in the four sections that do not collapse -- hard right -- and
   the caret is an affordance, so it takes the edge. An auto margin claims the
   free space before justify-content can distribute it. */
.sp-panel summary.sp-sec__hd .sp-count { margin-left: auto; }
.sp-panel .sp-label {
  font-family: var(--sp-font-mono);
  font-size: var(--sp-fs-micro);
  letter-spacing: var(--sp-tracking-caps);
  text-transform: uppercase;
  /* Weight and full-strength colour so a section head outranks the rows
     beneath it; at 10px uppercase mono, weight alone is too slight. */
  font-weight: var(--sp-fw-semibold);
  color: var(--sp-text);
}
.sp-panel .sp-count {
  font-family: var(--sp-font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--sp-fs-xs);
  color: var(--sp-text-faint);
}

/* ============================================================
   ThemeCard — the one accent-carrying element
   ============================================================ */

.sp-panel .sp-theme {
  display: flex;
  flex-direction: column;
  gap: var(--sp-space-1);
  padding: var(--sp-space-3);
  border: var(--sp-hairline) solid var(--sp-accent-border);
  border-left: 2px solid var(--sp-accent);
  border-radius: var(--sp-radius-sm);
  background: var(--sp-accent-bg);
}
.sp-panel .sp-theme__top {
  display: flex;
  align-items: baseline;
  gap: var(--sp-space-2);
  flex-wrap: wrap;
}
.sp-panel .sp-theme__name {
  font-size: var(--sp-fs-lg);
  font-weight: var(--sp-fw-semibold);
  letter-spacing: var(--sp-tracking-tight);
  color: var(--sp-text);
}
.sp-panel a.sp-theme__name {
  text-decoration: underline;
  text-decoration-color: var(--sp-accent-border);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: text-decoration-color var(--sp-dur-fast) var(--sp-ease);
}
.sp-panel a.sp-theme__name:hover { text-decoration-color: var(--sp-accent); }
.sp-panel .sp-theme__version {
  font-family: var(--sp-font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--sp-fs-sm);
  color: var(--sp-accent);
}
.sp-panel .sp-theme__meta {
  display: flex;
  align-items: baseline;
  gap: var(--sp-space-2);
  flex-wrap: wrap;
  font-family: var(--sp-font-mono);
  font-size: var(--sp-fs-xs);
  color: var(--sp-text-muted);
}
.sp-panel .sp-theme__meta .sp-sep { color: var(--sp-border-strong); }
.sp-panel .sp-theme__mod {
  font-family: var(--sp-font-mono);
  font-size: var(--sp-fs-micro);
  letter-spacing: 0.04em;
  color: var(--sp-text);
  border: var(--sp-hairline) solid var(--sp-accent-border);
  border-radius: var(--sp-radius-sm);
  padding: 0 4px;
  background: var(--sp-bg);
}

/* custom / headless — deliberate non-answers, no accent */
.sp-panel .sp-theme--plain {
  border: var(--sp-hairline) solid var(--sp-border-strong);
  border-left: 2px solid var(--sp-border-strong);
  background: var(--sp-bg-subtle);
}
.sp-panel .sp-theme--plain .sp-theme__name { color: var(--sp-text); }
.sp-panel .sp-theme--dashed {
  border: 1px dashed var(--sp-border-strong);
  background: transparent;
}
.sp-panel .sp-theme__note {
  font-size: var(--sp-fs-sm);
  color: var(--sp-text-muted);
  text-wrap: pretty;
}

/* ============================================================
   AppList
   ============================================================ */

.sp-panel .sp-cats { display: flex; flex-direction: column; gap: var(--sp-space-3); }
.sp-panel .sp-cat { display: flex; flex-direction: column; gap: var(--sp-space-1); }
.sp-panel .sp-cat + .sp-cat {
  padding-top: var(--sp-space-3);
  border-top: var(--sp-hairline) solid var(--sp-border);
}
.sp-panel .sp-cat__label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--sp-font-mono);
  font-size: var(--sp-fs-micro);
  letter-spacing: var(--sp-tracking-caps);
  text-transform: uppercase;
  color: var(--sp-text-faint);
}
.sp-panel .sp-cat__label::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 1px;
  background: var(--sp-cat-tint, var(--sp-border-strong));
}
/* Category markers. Every category carries a hue; lightness and chroma are one
   pair of tokens, so the whole set reads as one system and switches with the
   scheme automatically. Hues are spaced so categories that display next to each
   other land at least 40 degrees apart -- that separation is what the eye
   actually uses, since neighbouring groups are what get compared.

   Keyed to the category, never to DOM position, so a category keeps its colour
   whether or not the others are present. A category with no rule here sets no
   --sp-cat-tint at all, so .sp-cat__label::before falls back to the neutral
   marker -- which is why these are written out per category rather than composed
   from a hue variable: an unset hue makes the colour function invalid, and an
   invalid substitution drops the background entirely instead of falling back.

   Written one declaration per line because colour literals belong on token
   lines; check_colour_literals enforces it.

   The first five hues are the original --sp-tint-1..5 values, unchanged, so the
   established categories keep the colours the design settled on.
   Shared convention: same attribute values in stackpeek.css. */
.sp-panel [data-sp-cat="email-sms"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 265);
}
.sp-panel [data-sp-cat="page-builder"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 200);
}
.sp-panel [data-sp-cat="reviews"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 155);
}
.sp-panel [data-sp-cat="upsell"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 75);
}
.sp-panel [data-sp-cat="subscriptions"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 320);
}
.sp-panel [data-sp-cat="sales"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 0);
}
.sp-panel [data-sp-cat="marketing"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 133);
}
.sp-panel [data-sp-cat="store-design"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 293);
}
.sp-panel [data-sp-cat="customer-service"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 67);
}
.sp-panel [data-sp-cat="social-media"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 227);
}
.sp-panel [data-sp-cat="analytics"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 13);
}
.sp-panel [data-sp-cat="advertising"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 147);
}
.sp-panel [data-sp-cat="discounts"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 307);
}
.sp-panel [data-sp-cat="payments"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 93);
}
.sp-panel [data-sp-cat="shipping-delivery"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 240);
}
.sp-panel [data-sp-cat="orders"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 27);
}
.sp-panel [data-sp-cat="product-management"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 173);
}
.sp-panel [data-sp-cat="search-navigation"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 333);
}
.sp-panel [data-sp-cat="localization"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 107);
}
.sp-panel [data-sp-cat="loyalty"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 253);
}
.sp-panel [data-sp-cat="trust-security"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 40);
}
.sp-panel [data-sp-cat="privacy-compliance"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 187);
}
.sp-panel [data-sp-cat="dropshipping"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 347);
}
.sp-panel [data-sp-cat="seo"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 120);
}
.sp-panel [data-sp-cat="store-management"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 280);
}
.sp-panel [data-sp-cat="performance"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 53);
}
.sp-panel [data-sp-cat="accessibility"] {
  --sp-cat-tint: oklch(var(--sp-cat-l) var(--sp-cat-c) 213);
}
.sp-panel .sp-items { display: flex; flex-direction: column; }
.sp-panel .sp-item {
  display: flex;
  align-items: baseline;
  gap: var(--sp-space-2);
  min-height: 22px;
  font-size: var(--sp-fs-md);
  color: var(--sp-text);
}
.sp-panel .sp-item__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Recognized apps link to their listing. Accent stays reserved for the
   theme, so the affordance is a hairline underline, not a colour. */
.sp-panel a.sp-item__name {
  color: var(--sp-text);
  text-decoration: underline;
  text-decoration-color: var(--sp-border-strong);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  transition: text-decoration-color var(--sp-dur-fast) var(--sp-ease);
}
.sp-panel a.sp-item__name:hover { text-decoration-color: var(--sp-text); }
.sp-panel .sp-flag {
  flex: none;
  font-family: var(--sp-font-mono);
  font-size: var(--sp-fs-micro);
  line-height: 15px;
  color: var(--sp-text-faint);
  border: var(--sp-hairline) solid var(--sp-border-strong);
  border-radius: var(--sp-radius-sm);
  padding: 0 4px;
  cursor: help;
}
/* No rule above it. A hairline is how this design separates one section from
   the next -- .sp-sec carries that border -- so repeating it inside a section
   reads as a second boundary and splits the section in two. Space alone is
   enough to set a footnote apart from what it annotates. */
.sp-panel .sp-foot-note {
  margin-top: var(--sp-space-3);
  font-size: var(--sp-fs-xs);
  color: var(--sp-text-faint);
  text-wrap: pretty;
}
/* "Show 20 more" reuses .sp-foot-note's spacing/typography but, unlike the
   Apps section's static footnote, is a real <button> — reset UA chrome (which
   .sp-foot-note alone leaves untouched: no bare `button` rule exists in this
   file) so it renders as bare, right-aligned text, matching
   BestSellers.svelte's borderless, flex-end `.more`, not a platform button. */
.sp-panel button.sp-foot-note {
  display: block;
  width: fit-content;
  margin-left: auto;
  padding: 0;
  border: 0;
  background: transparent;
  font-family: var(--sp-font-sans);
  cursor: pointer;
}

/* ============================================================
   PixelBadges
   ============================================================ */

.sp-panel .sp-badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-space-1);
}
.sp-panel .sp-badge {
  font-family: var(--sp-font-mono);
  font-size: var(--sp-fs-xs);
  color: var(--sp-text);
  border: var(--sp-hairline) solid var(--sp-border-strong);
  border-radius: var(--sp-radius-sm);
  padding: 2px var(--sp-space-2);
  background: var(--sp-surface);
}
.sp-panel .sp-quiet {
  margin-top: var(--sp-space-2);
  font-family: var(--sp-font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--sp-fs-xs);
  color: var(--sp-text-faint);
}

/* ============================================================
   Best sellers — ranked list
   ============================================================ */

.sp-panel .sp-bs { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; }
.sp-panel .sp-bs li {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: var(--sp-space-2);
}
.sp-panel .sp-rank {
  font-family: var(--sp-font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--sp-fs-micro);
  color: var(--sp-text-faint);
  min-width: 1.5em;
  text-align: right;
}
.sp-panel .sp-bs-name {
  font-family: var(--sp-font-sans);
  font-size: var(--sp-fs-sm);
  color: var(--sp-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sp-panel .sp-price {
  font-family: var(--sp-font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--sp-fs-xs);
  color: var(--sp-text);
}

/* Export progress rule — track and fill, never the accent */
.sp-panel .sp-track { height: 2px; border-radius: var(--sp-radius-sm); background: var(--sp-border); overflow: hidden; }
.sp-panel .sp-fill { height: 100%; background: var(--sp-text-faint); }

/* ============================================================
   StoreIntelligence — one container, two states
   ============================================================ */

.sp-panel .sp-si { display: flex; flex-direction: column; gap: var(--sp-space-3); }
.sp-panel .sp-si__copy {
  font-size: var(--sp-fs-sm);
  color: var(--sp-text-muted);
  text-wrap: pretty;
}
/* Product digest — borderless key/value rows.
   Deliberately not .sp-metric*: .sp-metrics is defined in this file AND in
   stackpeek.css with different children and a different display, and the
   site's copy is live on the store-intelligence section. Two files, one
   selector, two meanings is the collision this name avoids. */
.sp-panel .sp-facts { display: grid; gap: var(--sp-space-1); }
.sp-panel .sp-fact {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-space-3);
  align-items: baseline;
  font-size: var(--sp-fs-sm);
}
.sp-panel .sp-fact__k { color: var(--sp-text-muted); }
.sp-panel .sp-fact__v {
  font-family: var(--sp-font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--sp-text);
}

.sp-panel .sp-si-form { display: flex; flex-wrap: wrap; gap: var(--sp-space-2); }
.sp-panel .sp-si-input {
  flex: 1 1 140px;
  min-width: 0;
  padding: 6px var(--sp-space-2);
  border: var(--sp-hairline) solid var(--sp-border-strong);
  border-radius: var(--sp-radius-md);
  background: var(--sp-surface);
  color: var(--sp-text);
  font-family: var(--sp-font-mono);
  font-size: var(--sp-fs-sm);
}
.sp-panel .sp-si-input::placeholder { color: var(--sp-text-faint); }
.sp-panel .sp-hint { flex: 1 0 100%; font-size: var(--sp-fs-xs); color: var(--sp-text-faint); }

/* ============================================================
   Buttons
   ============================================================ */

.sp-panel .sp-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-space-2);
  padding: 6px var(--sp-space-3);
  border: var(--sp-hairline) solid transparent;
  border-radius: var(--sp-radius-md);
  font-family: var(--sp-font-sans);
  font-size: var(--sp-fs-sm);
  font-weight: var(--sp-fw-medium);
  line-height: var(--sp-lh-tight);
  cursor: pointer;
  transition: background-color var(--sp-dur-fast) var(--sp-ease),
              color var(--sp-dur-fast) var(--sp-ease);
}
.sp-panel .sp-btn--primary { background: var(--sp-accent); color: var(--sp-accent-on); }
.sp-panel .sp-btn--primary:hover { background: var(--sp-accent-hover); }
.sp-panel .sp-btn--quiet {
  background: transparent;
  border-color: var(--sp-border-strong);
  color: var(--sp-text);
}
.sp-panel .sp-btn--quiet:hover:not(:disabled) { background: var(--sp-bg-inset); }
/* The export control sits directly above the Trackers badges, and .sp-btn--quiet
   shares their fill, border colour and centred text -- differing only by 2px of
   radius and 4px of padding, so it read as a fourth badge sitting alone.
   Badges are inline pills that hug their text; a full-bleed filled bar cannot be
   mistaken for one. The separation is shape and fill, never accent: an accent
   export button would make the panel's brightest object a control rather than
   the detection result. */
.sp-panel .sp-btn--export {
  display: flex;
  width: 100%;
  padding: var(--sp-space-2) var(--sp-space-3);
  background: var(--sp-bg-inset);
  border-color: var(--sp-border-strong);
  color: var(--sp-text);
}
.sp-panel .sp-btn--export:hover:not(:disabled) { background: var(--sp-border); }
.sp-panel .sp-btn--export svg { width: 12px; height: 12px; flex: none; }
.sp-panel .sp-btn:disabled { cursor: default; color: var(--sp-text-faint); }
/* A control sitting directly in a section carries its own rhythm. .sp-sec has no
   gap of its own, and giving it one would double-space every section head --
   .sp-sec__hd already brings margin-bottom. Scoped to direct children so the
   buttons inside .sp-state, which sit in that container's own flex gap, are
   untouched. */
.sp-panel .sp-sec > .sp-btn {
  margin-top: var(--sp-space-3);
  margin-bottom: var(--sp-space-2);
}

/* ============================================================
   Terminal states (3–6) and loading
   ============================================================ */

.sp-panel .sp-state {
  display: flex;
  flex-direction: column;
  gap: var(--sp-space-3);
  align-items: flex-start;
  padding: var(--sp-space-5) var(--sp-space-3);
}
.sp-panel .sp-state__code {
  font-family: var(--sp-font-mono);
  font-size: var(--sp-fs-micro);
  letter-spacing: var(--sp-tracking-caps);
  text-transform: uppercase;
  color: var(--sp-text-faint);
  border: var(--sp-hairline) solid var(--sp-border);
  border-radius: var(--sp-radius-sm);
  padding: 1px 5px;
}
.sp-panel .sp-state__title {
  font-size: var(--sp-fs-xl);
  font-weight: var(--sp-fw-semibold);
  letter-spacing: var(--sp-tracking-tight);
  line-height: var(--sp-lh-snug);
}
.sp-panel .sp-state__body {
  font-size: var(--sp-fs-sm);
  color: var(--sp-text-muted);
  text-wrap: pretty;
}
.sp-panel .sp-state__list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-space-1);
  width: 100%;
  padding-top: var(--sp-space-2);
  border-top: var(--sp-hairline) solid var(--sp-border);
  font-family: var(--sp-font-mono);
  font-size: var(--sp-fs-xs);
  color: var(--sp-text-faint);
}
.sp-panel .sp-state__row {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-space-2);
}

/* Loading — skeleton of the eventual layout */
.sp-panel .sp-scan {
  display: flex;
  align-items: center;
  gap: var(--sp-space-2);
  font-family: var(--sp-font-mono);
  font-size: var(--sp-fs-xs);
  color: var(--sp-text-muted);
}
.sp-panel .sp-spinner {
  width: 12px;
  height: 12px;
  border: 1.5px solid var(--sp-border-strong);
  border-top-color: var(--sp-accent);
  border-radius: 50%;
  animation: sp-spin 700ms linear infinite;
}
@keyframes sp-spin { to { transform: rotate(360deg); } }

.sp-panel .sp-skel {
  border-radius: var(--sp-radius-sm);
  background: var(--sp-bg-inset);
  animation: sp-pulse 1200ms var(--sp-ease) infinite alternate;
}
@keyframes sp-pulse { from { opacity: 1; } to { opacity: 0.45; } }
.sp-panel .sp-skel--theme { height: 62px; border-radius: var(--sp-radius-sm); }
.sp-panel .sp-skel--row { height: 12px; }
.sp-panel .sp-skel-rows { display: flex; flex-direction: column; gap: var(--sp-space-2); }

@media (prefers-reduced-motion: reduce) {
  .sp-panel .sp-spinner,
  .sp-panel .sp-skel { animation: none; }
  .sp-panel .sp-spinner { border-top-color: var(--sp-accent); }
  .sp-panel * { transition-duration: 0.01ms !important; }
}

/* Footer */
.sp-panel .sp-ft {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-space-2);
  padding: var(--sp-space-2) var(--sp-space-3);
  border-top: var(--sp-hairline) solid var(--sp-border);
  background: var(--sp-bg-subtle);
  font-size: var(--sp-fs-xs);
  color: var(--sp-text-faint);
}
.sp-panel .sp-ft a { color: var(--sp-text-muted); text-decoration: none; }
.sp-panel .sp-ft a:hover { color: var(--sp-text); text-decoration: underline; }
.sp-panel .sp-ft__v { font-family: var(--sp-font-mono); }

/* Wider panel: the user dragged it out. Density stays; lines get longer. */
@container (min-width: 440px) {
  .sp-panel .sp-sec { padding: var(--sp-space-3) var(--sp-space-4); }
  .sp-panel .sp-hd, .sp-panel .sp-ft { padding-left: var(--sp-space-4); padding-right: var(--sp-space-4); }
  .sp-panel .sp-cats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-space-3) var(--sp-space-4); }
  .sp-panel .sp-cat + .sp-cat { padding-top: 0; border-top: 0; }
}
