/* DropNZ design system: tokens and rules come from the dropnz-design skill (design-model.yaml). */

:root {
  --font-display: 'Bungee', Impact, 'Arial Black', sans-serif;
  --font-body: 'Rubik', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'Space Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  --font-pixel: 'Silkscreen', 'Space Mono', monospace;

  --text-display: 44px;
  --text-heading: 26px;
  --text-subheading: 17px;
  --text-body: 15px;
  --text-body-sm: 13px;
  --text-caption: 12px;
  --text-label: 11px;
  --price-lg: 22px;
  --price-md: 16px;
  --price-was: 13px;

  --space-2xs: 2px;
  --space-xs: 4px;
  --space-sm: 8px;
  --space-md: 16px;
  --space-lg: 24px;
  --space-xl: 32px;
  --space-2xl: 48px;

  --radius-element: 2px;
  --radius-control: 4px;
  --radius-component: 8px;
  --radius-container: 12px;
  --radius-pill: 999px;

  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --duration-fast: 100ms;
  --duration-medium: 180ms;
  --duration-slow: 280ms;

  --shadow-1: 3px 3px 0 0 var(--shadow-ink);
  --shadow-2: 5px 5px 0 0 var(--shadow-ink);
  --shadow-3: 8px 8px 0 0 var(--shadow-ink);
  --shadow-selected: 3px 3px 0 0 var(--accent);
  --glow-restock: 0 0 0 1px var(--restock), 0 0 24px -4px var(--restock);

  /* Discord's own button colour, a shade darker for 6.4:1 white text; the same in both themes. */
  --discord: #4752c4;
  --on-discord: #ffffff;
}

/* Dark "Cabinet" is the default. */
:root,
[data-theme='dark'] {
  --background: #08070f;
  --bg: var(--background);
  --surface1: #111020;
  --surface2: #1b1a2e;
  --surface3: #2c2b45;
  --border: #1b1a2e;
  --border-visible: #4c4b69;
  --text1: #f4f3f9;
  --text2: #b3b2cb;
  --text3: #8c8bab;
  --text4: #6a6989;
  --accent: #22dcec;
  --accent-subtle: #062a31;
  --on-accent: #08070f;
  --success: #3df5a0;
  --success-bg: #06331f;
  --warning: #ffd93d;
  --warning-bg: #3a2e00;
  --error: #ff5a6e;
  --error-bg: #420a13;
  --restock: #ff3dcb;
  --restock-bg: #25041a;
  --deal: #ff8a3d;
  --deal-bg: #401a03;
  --shadow-ink: #2c2b45;
  --card-border: var(--border);
  --btn-border: transparent;
  --grain-opacity: 0.06;
  --halftone: rgb(34 220 236 / 16%);
  --scanline: rgb(255 255 255 / 5%);
  color-scheme: dark;
}

/* Light "Daylight Print": ink borders on paper. */
[data-theme='light'] {
  --background: #f4f3f9;
  --bg: var(--background);
  --surface1: #ffffff;
  --surface2: #e9e8f2;
  --surface3: #d5d4e4;
  --border: #d5d4e4;
  --border-visible: #08070f;
  --text1: #08070f;
  --text2: #4c4b69;
  --text3: #6a6989;
  --text4: #8c8bab;
  --accent: #00788a;
  --accent-subtle: #e6fdff;
  --on-accent: #ffffff;
  --success: #0a7f50;
  --success-bg: #e7fef3;
  --warning: #7a6000;
  --warning-bg: #fffbe0;
  --error: #c21832;
  --error-bg: #ffebee;
  --restock: #b80a89;
  --restock-bg: #ffe8f9;
  --deal: #b34400;
  --deal-bg: #fff0e5;
  --shadow-ink: #08070f;
  --card-border: var(--border-visible);
  --btn-border: var(--border-visible);
  --grain-opacity: 0.04;
  --halftone: rgb(8 7 15 / 14%);
  --scanline: rgb(8 7 15 / 5%);
  color-scheme: light;
}

/* ── Base ─────────────────────────────────────────────── */

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

[hidden] {
  display: none !important;
}

html {
  background: var(--background);
}

/* A column, the main part taking whatever height is left: the footer stays at the window's foot on
   a short page rather than halfway up it with the page's background below. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--background);
  color: var(--text1);
  font: 400 var(--text-body) / 1.5 var(--font-body);
  -webkit-font-smoothing: antialiased;
}

body > main {
  flex: 1 0 auto;
}

/* A page's gate (signed out): what it is and the one way in, as a sign-in sheet puts it. */
.gate {
  display: grid;
  justify-items: center;
  gap: 14px;
  max-width: 440px;
  margin: 48px auto;
  padding: 36px 28px;
  text-align: center;
}

.gate h2 {
  font-size: 22px;
  line-height: 1.25;
}

.gate p {
  color: var(--text2);
}

.gate .btn {
  width: 100%;
  margin-top: 6px;
}

.gate-icon {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--accent-subtle);
  color: var(--accent);
  font-size: 26px;
}

.gate .gate-note {
  color: var(--text3);
  font-size: var(--text-body-sm);
}

.gate-note a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* The gate inside a card that is already there (the radar's alerts tab). */
.gate.gate-inline {
  margin: 0 auto;
  padding: 20px 4px 12px;
}

/* Grain: page background only. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: var(--grain-opacity);
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}

a {
  color: inherit;
  text-decoration: none;
}

button,
input,
select {
  font: inherit;
  color: inherit;
}

button {
  background: transparent;
  border: none;
  cursor: pointer;
}

/* Keyboard focus: a solid ring a little off the edge, as Apple and Shopify draw it (a dashed one
   read as a rendering fault). Never shown for a tap or a click. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

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

.pixel {
  font-family: var(--font-pixel);
  font-size: var(--text-label);
  line-height: 1;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.glyph {
  display: inline-block;
  width: 12px;
  height: 12px;
  flex-shrink: 0;
}

.glyph-24 {
  width: 24px;
  height: 24px;
}

.glyph-36 {
  width: 36px;
  height: 36px;
}

.scanlines {
  position: relative;
}

.scanlines::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: repeating-linear-gradient(to bottom, var(--scanline) 0 1px, transparent 1px 3px);
}

.live-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 1px;
  background: var(--success);
  flex-shrink: 0;
}

.live-dot.is-live {
  animation: blink 1s steps(2, end) infinite;
}

.live-dot.is-warn {
  background: var(--warning);
}

.live-dot.is-error {
  background: var(--error);
}

@keyframes blink {
  50% {
    opacity: 0.15;
  }
}

/* ── Site shell: one header and footer on every page (src/web/shell.ts) ───────────────────────── */

.container {
  position: relative;
  z-index: 10;
  width: 100%;
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 32px;
}

:root {
  --header-height: 68px;
}

@media (max-width: 900px) {
  :root {
    --header-height: 60px;
  }
}

/* The header stays with the page on every screen: the radar's bar is pinned right under it. Once the
   page scrolls (nav.js) it turns glassy. The glass is on ::before, as a backdrop-filter on the header
   itself would trap the phone menu (position: fixed) inside it. */
.lp-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--background);
  border-bottom: 2px solid var(--border);
  transition:
    background-color var(--duration-slow) var(--ease),
    border-color var(--duration-slow) var(--ease);
}

.lp-header::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0;
  background: color-mix(in srgb, var(--background) 78%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  backdrop-filter: blur(14px) saturate(1.4);
  transition: opacity var(--duration-slow) var(--ease);
  pointer-events: none;
}

.lp-header.is-scrolled:not(.is-open) {
  background: transparent;
  border-bottom-color: var(--border-visible);
}

.lp-header.is-scrolled:not(.is-open)::before {
  opacity: 1;
}

.lp-header .container {
  display: flex;
  align-items: center;
  gap: 32px;
  height: var(--header-height);
}

.lp-header .logo {
  padding: 0;
  font-size: 22px;
}

.lp-nav {
  display: flex;
  gap: 24px;
  font-weight: 500;
  font-size: var(--text-body-sm);
  color: var(--text2);
}

.lp-nav a {
  position: relative;
  padding: 6px 0;
  transition: color var(--duration-medium) var(--ease);
}

/* An accent rule that grows out from under the link on hover, and stays under the page you're on. */
.lp-nav a::after {
  content: '';
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transition: transform var(--duration-slow) var(--ease);
}

.lp-nav a:hover,
.lp-nav a[aria-current='page'] {
  color: var(--text1);
}

.lp-nav a:hover::after,
.lp-nav a[aria-current='page']::after {
  transform: scaleX(1);
}

.lp-header-end {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 12px;
}

/* Signed in: the profile, an initial in a tile and the first name, trimmed so a long one never
   pushes the header onto two rows. */
.nav-account {
  gap: 8px;
  padding-left: 4px;
  text-transform: none;
  letter-spacing: 0;
}

.nav-avatar {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: var(--radius-control);
  background: var(--accent);
  color: var(--on-accent);
  font: 400 13px / 1 var(--font-display);
}

.nav-account .nav-name {
  max-width: 110px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The menu and its button are a phone's. */
.nav-toggle,
.site-menu {
  display: none;
}

.btn-discord {
  background: var(--discord);
  color: var(--on-discord);
  border: 2px solid var(--btn-border);
  box-shadow: var(--shadow-1);
}

.logo {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 6px;
  font-family: var(--font-display);
  font-size: 20px;
  line-height: 1;
}

.logo b {
  color: var(--accent);
  font-weight: 400;
}

.logo-mark {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-control);
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: var(--shadow-1);
}

/* ── The header's logo, alive (src/web/shell.ts headerLogo) ──
   Once a visit the bolt drops into its tile, lands with a spark ring and the word glitches in. Hover
   jolts the bolt and sparks the ring (the word stays still); the open phone menu sets its cyan ring pulsing and the
   bolt flickering; a scrolled page tucks the tile in a little, tilted. */
.logo-live .logo-mark {
  position: relative;
  transition:
    transform var(--duration-slow) var(--ease),
    background-color var(--duration-slow) var(--ease);
}

.logo-live .logo-bolt {
  position: relative;
}

.logo-ring {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 2px solid var(--accent);
  opacity: 0;
  pointer-events: none;
}

.logo-live .logo-word {
  display: inline-block;
}

.logo-intro .logo-bolt {
  animation: logo-drop 640ms cubic-bezier(0.3, 1.4, 0.5, 1) 120ms both;
}

.logo-intro .logo-ring {
  animation: logo-spark 620ms var(--ease) 560ms;
}

.logo-intro .logo-word {
  animation: logo-glitch 420ms steps(1) 520ms both;
}

.logo-live:hover .logo-bolt,
.logo-live:focus-visible .logo-bolt {
  animation: logo-jolt 460ms var(--ease);
}

.logo-live:hover .logo-ring,
.logo-live:focus-visible .logo-ring {
  animation: logo-spark 560ms var(--ease);
}

.is-scrolled:not(.is-open) .logo-live .logo-mark {
  transform: scale(0.88) rotate(-8deg);
}

/* The tile keeps its cyan while the menu is open; its ring pulses (the close button is the pink one). */
.is-open .logo-live .logo-ring {
  animation: logo-spark 1400ms var(--ease) infinite;
}

.is-open .logo-live .logo-bolt {
  animation: logo-flicker 1400ms steps(1) infinite;
}

@keyframes logo-drop {
  from {
    opacity: 0;
    transform: translateY(-22px) scaleY(1.3);
  }
  55% {
    opacity: 1;
    transform: translateY(2px) scaleY(0.8);
  }
}

@keyframes logo-spark {
  from {
    opacity: 0.9;
    transform: scale(1);
  }
  to {
    opacity: 0;
    transform: scale(1.75);
  }
}

@keyframes logo-jolt {
  20% {
    transform: rotate(-14deg) scale(1.15);
  }
  45% {
    transform: rotate(10deg) scale(1.1);
  }
  70% {
    transform: rotate(-5deg);
  }
}

/* RGB split in the radar's two colours, stepping like a bad signal locking on. */
@keyframes logo-glitch {
  0% {
    opacity: 0;
    transform: translateX(-4px);
    text-shadow: 3px 0 var(--restock), -3px 0 var(--accent);
  }
  20% {
    opacity: 1;
    transform: translateX(3px) skewX(-8deg);
    text-shadow: -3px 0 var(--restock), 2px 0 var(--accent);
  }
  40% {
    transform: translateX(-2px);
    text-shadow: 2px 0 var(--restock), -1px 0 var(--accent);
  }
  60% {
    transform: translateX(1px) skewX(4deg);
    text-shadow: -1px 0 var(--restock), 1px 0 var(--accent);
  }
  80%,
  100% {
    transform: none;
    text-shadow: none;
  }
}

@keyframes logo-flicker {
  0%,
  100% {
    opacity: 1;
  }
  8% {
    opacity: 0.35;
  }
  12% {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .logo-live .logo-bolt,
  .logo-live .logo-ring,
  .logo-live .logo-word {
    animation: none !important;
  }

  .logo-live .logo-mark {
    transition: none;
  }
}

.lp-footer {
  position: relative;
  z-index: 1;
  padding: 56px 0 48px;
  background: var(--surface1);
  border-top: 2px solid var(--border);
}

.foot-grid {
  display: grid;
  grid-template-columns: 1.4fr repeat(4, 1fr);
  gap: 32px;
  margin-bottom: 40px;
}

.foot-grid .logo {
  padding: 0;
}

.foot-grid p {
  max-width: 300px;
  margin-top: 14px;
  font-size: var(--text-body-sm);
  color: var(--text3);
}

.foot-col h3 {
  margin-bottom: 14px;
  font-weight: 400;
  color: var(--text3);
}

.foot-col a {
  display: block;
  padding: 4px 0;
  font-size: var(--text-body-sm);
  color: var(--text2);
}

.foot-col a:hover {
  color: var(--accent);
}

.foot-legal {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
  font: 400 var(--text-caption) var(--font-body);
  color: var(--text3);
  font-variant-numeric: tabular-nums;
}

/* The live "browsing now" count in the footer (public/presence.js). */
.live-count {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.live-count[hidden] {
  display: none;
}

.live-count b {
  color: var(--text1);
}

@media (max-width: 900px) {
  /* One row that stays at the top of the screen: the logo, Sign in (or the profile) and the menu
     button. Nothing slides it away while the page scrolls. */
  .lp-header .container {
    position: relative;
    z-index: 20;
  }

  .lp-nav {
    display: none;
  }

  /* The menu button, and the menu's close in the same place: two bars that cross. */
  .nav-toggle {
    display: grid;
    flex-shrink: 0;
    place-items: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 2px solid var(--border-visible);
    border-radius: var(--radius-control);
    background: var(--surface2);
    color: var(--text1);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition:
      border-color var(--duration-medium) var(--ease),
      background-color var(--duration-medium) var(--ease);
  }

  .nav-toggle[aria-expanded='true'] {
    border-color: var(--restock);
    background: var(--restock-bg);
  }

  .nav-toggle:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
  }

  .nav-toggle-bars {
    position: relative;
    display: block;
    width: 20px;
    height: 10px;
  }

  .nav-toggle-bars span {
    position: absolute;
    left: 0;
    width: 100%;
    height: 2px;
    border-radius: 2px;
    background: currentColor;
    transition:
      top var(--duration-medium) var(--ease) var(--duration-medium),
      transform var(--duration-medium) var(--ease);
  }

  .nav-toggle-bars span:nth-child(1) {
    top: 0;
  }

  .nav-toggle-bars span:nth-child(2) {
    top: 8px;
  }

  /* The bars meet in the middle, then turn: the cross is drawn in two clean moves, undone in reverse. */
  .nav-toggle[aria-expanded='true'] .nav-toggle-bars span {
    top: 4px;
    transition:
      top var(--duration-medium) var(--ease),
      transform var(--duration-medium) var(--ease) var(--duration-medium);
  }

  .nav-toggle[aria-expanded='true'] .nav-toggle-bars span:nth-child(1) {
    transform: rotate(45deg);
  }

  .nav-toggle[aria-expanded='true'] .nav-toggle-bars span:nth-child(2) {
    transform: rotate(-45deg);
  }

  /* The menu covers the screen under the header, opaque, so the page can't show through or be
     scrolled behind it. It drops like a curtain from the header's edge and its rows follow one after
     another; closing, it all rises back at once (nav.js keeps it on screen until it has). */
  .site-menu {
    position: fixed;
    top: var(--header-height);
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 10;
    display: flex;
    flex-direction: column;
    gap: 20px;
    padding: 16px 16px calc(16px + env(safe-area-inset-bottom));
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--background);
    border-top: 2px solid var(--border);
    clip-path: inset(0 0 100% 0);
    transition: clip-path 300ms cubic-bezier(0.7, 0, 0.3, 1);
  }

  .site-menu[hidden] {
    display: none;
  }

  .is-open .site-menu {
    clip-path: inset(0 0 0 0);
    transition-duration: 420ms;
    transition-timing-function: cubic-bezier(0.2, 0.9, 0.2, 1);
  }

  .site-menu-item,
  .site-menu-end {
    opacity: 0;
    transform: translateY(-12px);
    transition:
      opacity 160ms var(--ease),
      transform 160ms var(--ease);
  }

  .is-open .site-menu-item,
  .is-open .site-menu-end {
    opacity: 1;
    transform: none;
    transition-duration: 380ms;
    transition-delay: calc(120ms + var(--i, 0) * 70ms);
  }

  @media (prefers-reduced-motion: reduce) {
    .site-menu,
    .site-menu-item,
    .site-menu-end,
    .nav-toggle-bars span {
      transition: none !important;
    }
  }

  /* The page behind holds still. Only on <html>: with <body> hidden too, the body turns into its own
     scroll box and the sticky header falls back to the top of the page, off the screen. */
  html.site-menu-open {
    overflow: hidden;
  }

  /* Over everything while open, the radar's restock pop-ups and sheets too. */
  html.site-menu-open .lp-header {
    z-index: 70;
  }

  .site-menu-links {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .site-menu-item {
    display: flex;
    align-items: center;
    gap: 14px;
    min-height: 72px;
    padding: 12px 14px;
    border: 2px solid var(--border);
    border-radius: var(--radius-container);
    background: var(--surface1);
    color: var(--text1);
    -webkit-tap-highlight-color: transparent;
  }

  .site-menu-item:active {
    border-color: var(--border-visible);
    background: var(--surface2);
  }

  .site-menu-item:focus-visible {
    border-color: var(--accent);
    outline: none;
  }

  .site-menu-icon {
    display: grid;
    flex-shrink: 0;
    place-items: center;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-component);
    background: var(--surface2);
    color: var(--text1);
    font-size: 22px;
  }

  .site-menu-item[aria-current='page'] {
    border-color: var(--accent);
    background: var(--accent-subtle);
  }

  .site-menu-item[aria-current='page'] .site-menu-icon {
    background: var(--accent);
    color: var(--on-accent);
  }

  .site-menu-text {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
  }

  .site-menu-text b {
    font-weight: 600;
    font-size: 18px;
  }

  .site-menu-text small {
    color: var(--text2);
    font-size: var(--text-body-sm);
  }

  .site-menu-go {
    color: var(--text3);
    font-size: 18px;
  }

  /* The account and Discord: last, at the bottom of the screen where a thumb reaches. */
  .site-menu-end {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-top: auto;
  }

  .site-menu-end .btn {
    gap: 10px;
    min-height: 50px;
    font-size: 14px;
  }

  .site-menu-end .btn[hidden] {
    display: none;
  }

  .site-menu-end i {
    font-size: 20px;
  }

  .lp-header .logo {
    font-size: 19px;
  }

  .lp-header-end {
    gap: 8px;
  }

  .foot-grid {
    grid-template-columns: 1fr 1fr;
  }

  .foot-grid > :first-child {
    grid-column: 1 / -1;
  }
}

@media (max-width: 520px) {
  .container {
    padding: 0 16px;
  }

  .lp-header .container {
    gap: 12px;
  }
}

/* A phone shows the signed-in profile as just its initial. */
@media (max-width: 420px) {
  .nav-account {
    padding: 0 4px;
  }

  .nav-account .nav-name {
    display: none;
  }
}

/* The narrowest phones keep the logo mark and drop the word. */
@media (max-width: 330px) {
  .lp-header .logo-word {
    display: none;
  }
}

/* ── Radar: its views, pulse and tab-open alerts in one row under the header ───────────────────── */

.radar-page .container {
  max-width: 1440px;
}

.radar-bar {
  position: sticky;
  top: var(--header-height);
  z-index: 40;
  background: var(--background);
  border-bottom: 2px solid var(--border);
}

.radar-bar-in {
  position: relative;
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 60px;
}

/* The admin's views, behind one Admin button: a dropdown under it here, a sheet on a phone. */
.admin-menu {
  position: absolute;
  top: calc(100% - 6px);
  z-index: 50;
  display: flex;
  flex-direction: column;
  min-width: 220px;
  padding: 6px;
  background: var(--surface1);
  border: 2px solid var(--border-visible);
  border-radius: var(--radius-component);
  box-shadow: var(--shadow-2);
}

.admin-menu[hidden] {
  display: none;
}

.admin-menu-head {
  display: none;
}

.admin-menu [data-tab] {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  padding: 0 12px;
  border-radius: var(--radius-control);
  color: var(--text2);
  font-weight: 500;
  font-size: var(--text-body-sm);
  text-align: left;
}

.admin-menu [data-tab] i {
  font-size: 18px;
}

.admin-menu [data-tab]:hover,
.admin-menu [data-tab]:focus-visible {
  background: var(--surface2);
  color: var(--text1);
}

.admin-menu [data-tab][aria-selected='true'] {
  color: var(--accent);
}

.admin-menu .count-badge {
  position: static;
  margin-left: auto;
}

[data-admin-open] .caret {
  font-size: 12px;
}

.radar-tabs {
  display: flex;
  gap: 2px;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}

.radar-tabs::-webkit-scrollbar {
  display: none;
}

.radar-tabs button {
  flex-shrink: 0;
  height: 40px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  border-radius: var(--radius-control);
  font-weight: 500;
  font-size: var(--text-body-sm);
  color: var(--text2);
  white-space: nowrap;
  transition: background var(--duration-fast) var(--ease), color var(--duration-fast) var(--ease);
}

.radar-tabs button[hidden] {
  display: none;
}

.radar-tabs button i {
  font-size: 18px;
}

.radar-tabs button:hover {
  color: var(--text1);
  background: var(--surface2);
}

.radar-tabs button[aria-selected='true'] {
  color: var(--text1);
  background: var(--surface2);
  box-shadow: inset 0 -3px 0 var(--accent);
}

.radar-tabs button[aria-selected='true'] i {
  color: var(--accent);
}

.nav-count {
  font-size: 11px;
  color: var(--text3);
}

.nav-count:empty {
  display: none;
}

.nav-count .badge {
  height: 18px;
}

.radar-tools {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

/* The tracker's pulse: a status line and when it last loaded. */
.lcd {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 38px;
  padding: 0 12px;
  border-radius: var(--radius-control);
  background: var(--surface1);
  border: 2px solid var(--border);
}

.lcd-text {
  display: grid;
  gap: 3px;
  min-width: 0;
}

.lcd-line {
  color: var(--success);
}

.lcd.is-warn .lcd-line {
  color: var(--warning);
}

.lcd.is-error .lcd-line {
  color: var(--error);
}

.lcd-sub {
  overflow: hidden;
  font-size: 11px;
  line-height: 1;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--text3);
}

.radar-main {
  position: relative;
  z-index: 1;
}

.content {
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding-top: var(--space-lg);
  padding-bottom: var(--space-2xl);
}

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

/* ── Controls ─────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  height: 40px;
  padding: 0 18px;
  border-radius: var(--radius-control);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1;
  white-space: nowrap;
  transition:
    transform var(--duration-fast) var(--ease),
    box-shadow var(--duration-fast) var(--ease);
}

.btn i {
  font-size: 16px;
}

.btn:hover:not(:disabled) {
  transform: translate(-1px, -1px);
  box-shadow: var(--shadow-2);
}

.btn:active:not(:disabled) {
  transform: translate(3px, 3px);
  box-shadow: none;
}

.btn:disabled {
  opacity: 0.4;
  box-shadow: none;
  cursor: not-allowed;
}

.btn-sm {
  height: 32px;
  padding: 0 12px;
  font-size: 13px;
}

.btn-primary {
  background: var(--accent);
  color: var(--on-accent);
  border: 2px solid var(--btn-border);
  box-shadow: var(--shadow-1);
}

/* Quiet: Log in beside the one bright Sign up. */
.btn-ghost {
  background: transparent;
  color: var(--text2);
  border: 2px solid transparent;
}

.btn-ghost:hover:not(:disabled) {
  transform: none;
  box-shadow: none;
  color: var(--text1);
  background: var(--surface2);
}

/* Header buttons all stand the same height as the icon buttons beside them. */
.lp-header-end .btn {
  height: 38px;
}

.btn-secondary {
  background: var(--surface2);
  color: var(--text1);
  border: 2px solid var(--border-visible);
  box-shadow: var(--shadow-1);
}

.btn-restock {
  background: var(--restock);
  color: var(--on-accent);
  border: 2px solid var(--btn-border);
  box-shadow: var(--shadow-1);
}

.icon-btn {
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-control);
  background: var(--surface2);
  border: 2px solid var(--border-visible);
  font-size: 18px;
  color: var(--text1);
}

.icon-btn:hover {
  border-color: var(--text2);
}

.toggle-btn {
  height: 38px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0 14px;
  border-radius: var(--radius-control);
  border: 2px solid var(--border-visible);
  background: var(--surface1);
  color: var(--text2);
  font-weight: 600;
  font-size: 13px;
  line-height: 1;
  white-space: nowrap;
}

.toggle-btn i {
  font-size: 16px;
}

.toggle-btn:hover {
  color: var(--text1);
  border-color: var(--text2);
}

.toggle-btn[aria-pressed='true'] {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-subtle);
}

.link-btn {
  font-weight: 600;
  font-size: var(--text-body-sm);
  color: var(--accent);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

.link-btn:hover {
  color: var(--text1);
  text-decoration-color: var(--accent);
}

.kbd {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  height: 22px;
  min-width: 22px;
  padding: 0 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-element);
  background: var(--surface3);
  color: var(--text2);
  font: 400 var(--text-caption) / 1 var(--font-mono);
}

/* ── Badges & tags ────────────────────────────────────── */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--radius-element);
  border: 1.5px solid currentColor;
  font: 400 var(--text-label) / 1 var(--font-pixel);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

.badge svg {
  width: 10px;
  height: 10px;
}

.badge-in {
  background: var(--success-bg);
  color: var(--success);
}

.badge-low {
  background: var(--warning-bg);
  color: var(--warning);
}

.badge-restock {
  background: var(--restock-bg);
  color: var(--restock);
}

.badge-out {
  background: var(--surface3);
  color: var(--text2);
  border-color: var(--surface3);
}

.badge-deal {
  background: var(--deal-bg);
  color: var(--deal);
}

.badge-info {
  background: var(--accent-subtle);
  color: var(--accent);
}

.badge-error {
  background: var(--error-bg);
  color: var(--error);
}

.badge-nodata {
  background: transparent;
  color: var(--text3);
  border-style: dashed;
}

.tag {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 7px;
  border-radius: var(--radius-element);
  background: var(--surface3);
  color: var(--text2);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1;
  white-space: nowrap;
}

.count-badge {
  position: absolute;
  top: -6px;
  right: -10px;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-element);
  background: var(--restock);
  color: var(--on-accent);
  outline: 2px solid var(--surface1);
  font: 400 var(--text-label) / 1 var(--font-pixel);
}

.count-badge.is-error {
  background: var(--error);
}

/* ── Cards / KPIs ─────────────────────────────────────── */

.card {
  position: relative;
  background: var(--surface1);
  border: 2px solid var(--card-border);
  border-radius: var(--radius-component);
  box-shadow: var(--shadow-1);
}

/* What the radar holds, under the last card: context, not a dashboard. */
.summary {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  font-size: var(--text-body-sm);
  color: var(--text3);
}

.summary-line {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px 8px;
}

.summary b {
  color: var(--text1);
  font-weight: 600;
}

.summary .is-hot,
.summary .is-hot b {
  color: var(--restock);
}

.summary .is-hot i {
  margin-right: 4px;
  vertical-align: -2px;
}

.summary .sep {
  color: var(--border-visible);
}

/* ── Pop-ups (watched items in stock, what just changed) ─ */
/* Float over the page in a corner, never pushing it about; each has a cross. */

.toasts {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: min(360px, calc(100vw - 32px));
  pointer-events: none;
}

.toast {
  position: relative;
  padding: 12px 40px 12px 14px;
  border-radius: var(--radius-component);
  background: var(--surface1);
  border: 2px solid var(--border);
  box-shadow: var(--shadow-1);
  pointer-events: auto;
  animation: toast-in 180ms ease-out;
}

.toast.is-restock {
  border-color: var(--restock);
  box-shadow: var(--glow-restock);
}

.toast.is-deal {
  border-color: var(--deal);
}

@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .toast {
    animation: none;
  }
}

.toast-x {
  position: absolute;
  top: 6px;
  right: 6px;
}

.toast-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
}

.toast.is-restock .toast-head i {
  color: var(--restock);
}

.toast.is-deal .toast-head i {
  color: var(--deal);
}

.toast-title {
  margin: 6px 0 0;
  font-weight: 600;
  font-size: var(--text-body-sm);
}

.toast-meta {
  display: block;
  margin: 2px 0 0;
  font-size: var(--text-caption);
  color: var(--text3);
}

.toast-list {
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 6px;
  font-size: var(--text-body-sm);
}

.toast-list a {
  color: var(--text1);
  font-weight: 600;
}

.toast-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}

/* ── Watchlist rows ───────────────────────────────────── */

.watch-list {
  display: grid;
  gap: 10px;
}

.watch-row {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr) auto;
  gap: 14px;
  align-items: start;
  padding: 12px;
}

.watch-row.is-in {
  border-color: var(--restock);
}

.watch-thumb {
  display: grid;
  place-items: center;
  width: 72px;
  height: 72px;
  border-radius: var(--radius-control);
  background: var(--surface2);
  overflow: hidden;
}

.watch-thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.watch-main h3 {
  margin: 0;
  font-size: 15px;
  line-height: 1.3;
}

.watch-main h3 a {
  color: var(--text1);
}

.watch-store {
  margin-top: 2px;
  font-size: var(--text-caption);
  color: var(--text3);
}

.watch-status {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 8px 0 0;
  font-size: var(--text-body-sm);
  color: var(--text2);
}

.watch-updates {
  display: grid;
  gap: 4px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-caption);
  color: var(--text2);
}

.watch-updates li {
  display: flex;
  align-items: center;
  gap: 8px;
}

.watch-updates time {
  margin-left: auto;
  color: var(--text3);
}

.watch-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
}

@media (max-width: 600px) {
  .watch-row {
    grid-template-columns: 56px minmax(0, 1fr);
  }

  .watch-thumb {
    width: 56px;
    height: 56px;
  }

  .watch-actions {
    grid-column: 1 / -1;
    flex-direction: row;
    justify-content: flex-start;
    flex-wrap: wrap;
  }

  .watch-actions [data-unwatch] {
    margin-left: auto;
  }
}

/* ── Choosing stores ──────────────────────────────────── */

.watch-sheet-product {
  margin: 0 0 12px;
  font-size: var(--text-body-sm);
  color: var(--text2);
}

.watch-sheet-product b {
  color: var(--text1);
  font-size: 15px;
}

.scope-choice {
  display: grid;
  gap: 2px;
  margin-bottom: 8px;
}

.store-picks {
  display: grid;
  gap: 10px;
  max-height: min(46vh, 380px);
  overflow-y: auto;
  padding: 4px 2px 8px;
  border-top: 1px solid var(--border);
}

.store-group {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 4px 8px;
  margin: 0;
  padding: 0;
  border: 0;
}

.store-group legend {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0 4px;
  font: 700 var(--text-caption) / 1 var(--font-body);
  text-transform: uppercase;
  color: var(--text3);
  font-variant-numeric: tabular-nums;
}

.store-pick {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 36px;
  padding: 4px 8px;
  border-radius: var(--radius-control);
  font-size: var(--text-body-sm);
  cursor: pointer;
}

.store-pick:hover {
  background: var(--surface2);
}

.store-pick span {
  flex: 1;
  min-width: 0;
}

.store-pick small {
  font: 400 var(--text-caption) var(--font-body);
  color: var(--text3);
  font-variant-numeric: tabular-nums;
}

.store-pick.is-in small {
  color: var(--success);
}

.opt-sub {
  margin-left: 26px;
}

/* ── Filter bar ───────────────────────────────────────── */

.filters {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 18px;
  margin-bottom: 20px;
}

.field {
  position: relative;
  display: flex;
  align-items: center;
}

.search-field {
  flex: 1;
  min-width: 220px;
}

.input-lg {
  height: 56px;
  padding: 0 52px 0 50px;
  font-size: 17px;
}

.search-field:has(.input-lg) > i {
  left: 18px;
  font-size: 20px;
}

.search-field:has(.input-lg) .kbd {
  right: 16px;
}

.field > i {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text3);
  font-size: 16px;
  pointer-events: none;
}

.input {
  width: 100%;
  height: 44px;
  padding: 0 40px;
  border-radius: var(--radius-control);
  background: var(--surface2);
  border: 2px solid var(--border-visible);
  color: var(--text1);
  outline: none;
  transition:
    border-color var(--duration-fast) var(--ease),
    box-shadow var(--duration-fast) var(--ease);
}

.input::placeholder {
  color: var(--text3);
}

.input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-subtle);
}

.input::-webkit-search-cancel-button {
  display: none;
}

/* Checkbox rendered as a single-segment pill toggle. */
.chip input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.chip input:focus-visible + span {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.chips {
  display: flex;
  gap: var(--space-sm);
  flex-wrap: wrap;
}

.chip {
  position: relative;
  display: inline-flex;
  cursor: pointer;
}

.chip span {
  height: 32px;
  display: inline-flex;
  align-items: center;
  padding: 0 14px;
  border-radius: var(--radius-pill);
  border: 2px solid var(--border-visible);
  background: var(--surface1);
  color: var(--text2);
  font-weight: 500;
  font-size: 13px;
  line-height: 1;
  white-space: nowrap;
  transition:
    background var(--duration-fast) var(--ease),
    color var(--duration-fast) var(--ease);
}

.chip:hover span {
  color: var(--text1);
  border-color: var(--text2);
}

.chip input:checked + span,
.chip[aria-pressed='true'] span {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  box-shadow: var(--shadow-1);
}

.chips-bare {
  margin-bottom: 20px;
}

/* One row of dropdown pills and toggles: Store, Region, Language, In stock, Watching ... Sort. */
.filterbar {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  flex-wrap: wrap;
}

/* On a phone the pills scroll in a row behind an all-filters chip; on a computer that chip doesn't show. */
.search-row {
  display: flex;
  align-items: stretch;
  gap: 10px;
}

.filterbar .filters-btn,
.filterbar .sheet-head,
.filterbar .sheet-foot {
  display: none;
}

.filters-count[hidden] {
  display: none;
}

.menu-anchor {
  position: relative;
}

.sort-anchor {
  margin-left: auto;
}

/* The Type pill and the short sort label are for phones; a computer has room for the chip strip. */
.type-anchor,
.fpill-short {
  display: none;
}

/* A filter's name, value and chevron, and the in-stock switch: its row in the phone's filter sheet
   only. The option pages' back arrow, likewise. */
.fpill-name,
.fpill-value,
.row-go,
.fpill-switch,
.menu-head .menu-back {
  display: none;
}

@media (min-width: 861px) {
  .type-sheet,
  .type-sheet[hidden] {
    display: contents !important;
  }

  .type-sheet > .menu-head,
  .type-sheet > .menu-foot {
    display: none;
  }
}

.fpill {
  position: relative;
  height: 36px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 12px 0 14px;
  border-radius: var(--radius-pill);
  border: 2px solid var(--border-visible);
  background: var(--surface1);
  color: var(--text2);
  font-weight: 600;
  font-size: 13px;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease),
    border-color var(--duration-fast) var(--ease),
    color var(--duration-fast) var(--ease);
}

.fpill:hover {
  color: var(--text1);
  border-color: var(--text2);
}

.fpill > i {
  font-size: 15px;
}

.fpill .caret {
  font-size: 12px;
  color: var(--text3);
  transition: transform var(--duration-fast) var(--ease);
}

.fpill[aria-expanded='true'] {
  color: var(--text1);
  border-color: var(--accent);
}

.fpill[aria-expanded='true'] .caret {
  transform: rotate(180deg);
}

/* Picked: accent ink on the subtle accent fill. The solid accent stays with the type chips above. */
.fpill.is-active,
.fpill-toggle:has(input:checked) {
  background: var(--accent-subtle);
  border-color: var(--accent);
  color: var(--text1);
}

.fpill.is-active > i,
.fpill-toggle:has(input:checked) > i {
  color: var(--accent);
}

.fpill-label {
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Sort is a setting, not a filter, so it sits quiet until hovered. */
.fpill-quiet {
  border-color: transparent;
  background: transparent;
}

.fpill-toggle input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.fpill:focus-visible,
.fpill-toggle:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 40;
  width: 300px;
  max-height: min(460px, 70vh);
  display: flex;
  flex-direction: column;
  background: var(--surface1);
  border: 2px solid var(--border-visible);
  border-radius: var(--radius-component);
  box-shadow: var(--shadow-2);
}

.menu[hidden] {
  display: none;
}

.menu-end {
  left: auto;
  right: 0;
}

.menu-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: 12px 14px 8px;
}

.menu-head b {
  font-weight: 600;
  font-size: 15px;
}

/* Desktop closes on a click outside; the sheet on a phone gets a close button. */
.menu-x {
  display: none;
}

.menu-note {
  padding: 0 14px 8px;
  font-size: var(--text-caption);
  color: var(--text3);
}

.menu-search {
  padding: 0 10px 8px;
}

.menu-search > i {
  left: 22px;
  top: calc(50% - 4px);
}

.menu-search .input {
  height: 36px;
  padding: 0 12px 0 34px;
  font-size: 14px;
}

.menu-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  list-style: none;
  padding: 2px 6px 6px;
}

.menu-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: 10px 14px;
  border-top: 1px solid var(--border);
}

.opt {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 36px;
  padding: 6px 8px;
  border-radius: var(--radius-control);
  font-size: 14px;
  color: var(--text1);
  cursor: pointer;
}

.opt:hover {
  background: var(--surface2);
}

.opt.is-empty {
  color: var(--text3);
}

.opt-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.opt-name small {
  display: block;
  font: 400 var(--text-caption) / 1.3 var(--font-body);
  color: var(--text3);
  font-variant-numeric: tabular-nums;
}

.opt-count {
  font: 400 var(--text-caption) var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text3);
}

/* Checkbox and radio as the system draws them: 18px, 2px border, accent when on. */
.opt input {
  appearance: none;
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin: 0;
  display: grid;
  place-items: center;
  border: 2px solid var(--border-visible);
  border-radius: var(--radius-element);
  background: var(--surface1);
  cursor: pointer;
}

.opt input[type='radio'] {
  border-radius: 50%;
}

.opt:hover input {
  border-color: var(--text2);
}

.opt input:checked {
  border-color: var(--accent);
}

.opt input[type='checkbox']:checked {
  background: var(--accent);
}

.opt input[type='checkbox']:checked::after {
  content: '';
  width: 5px;
  height: 9px;
  border: solid var(--on-accent);
  border-width: 0 2px 2px 0;
  transform: translateY(-1px) rotate(45deg);
}

.opt input[type='radio']:checked::after {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

.opt input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.menu-backdrop {
  display: none;
}

/* Each active filter as a chip that undoes it; only there once something is picked. */
.results-row {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  flex-wrap: wrap;
  min-height: 28px;
}

/* Under the grid: how much is showing, then the radar's summary. */
.results-foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-top: var(--space-lg);
  padding: var(--space-md) 0;
  border-top: 2px dashed var(--border);
  text-align: center;
}

.count {
  font-size: var(--text-body-sm);
  color: var(--text2);
}

.count b {
  font: 700 var(--text-body-sm) var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text1);
}

.count:empty {
  display: none;
}

.active-chips {
  display: contents;
}

.active-chip {
  height: 28px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 8px 0 12px;
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--accent);
  background: var(--accent-subtle);
  color: var(--text1);
  font-weight: 500;
  font-size: 13px;
  cursor: pointer;
}

.active-chip i {
  font-size: 12px;
  color: var(--accent);
}

.active-chip:hover i {
  color: var(--text1);
}

.active-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* ── Product grid ─────────────────────────────────────── */

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: var(--space-md);
}

.product {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: var(--space-md);
  min-width: 0;
  transition:
    transform var(--duration-medium) var(--ease),
    box-shadow var(--duration-medium) var(--ease);
}

.product:hover {
  transform: translate(-1px, -1px);
  box-shadow: var(--shadow-2);
}

.product.is-watched {
  border-color: var(--accent);
  box-shadow: var(--shadow-selected);
}

/* The glow belongs to the single freshest restock on screen. */
.product.is-restock {
  border-color: var(--restock);
  box-shadow: var(--glow-restock);
}

/* One link stretched over the card is the click target; the watch button, maps links and the
   availability toggle sit above it and stay independently clickable. */
.card-link {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
}

.card-link:focus-visible {
  outline-offset: 2px;
}

.well {
  position: relative;
  aspect-ratio: 1 / 1;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: var(--radius-control);
  background: var(--surface2);
}

.well img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 10px;
}

/* Product photos are shot on white; multiply lets that white take the paper tone instead of
   glaring out of the dark cabinet. */
.well.has-image {
  background: #e9e8f2;
}

.well.has-image img,
.event-thumb.has-image img {
  mix-blend-mode: multiply;
}

.product.is-out .well img {
  filter: grayscale(1);
  opacity: 0.55;
}

.halftone::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: radial-gradient(var(--halftone) 1.2px, transparent 1.4px);
  background-size: 6px 6px;
  -webkit-mask-image: linear-gradient(135deg, #000 0%, transparent 75%);
  mask-image: linear-gradient(135deg, #000 0%, transparent 75%);
}

.well .glyph {
  color: var(--text4);
}

.well-status {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  max-width: calc(100% - 56px);
}

.product-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.product h3 {
  font-weight: 600;
  font-size: var(--text-body);
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
  min-height: 2.6em;
}

.product-where {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  margin-top: -6px;
  font-size: var(--text-body-sm);
  color: var(--text2);
}

.product-where span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.product-where i {
  flex-shrink: 0;
  color: var(--success);
}

.product-where.is-none,
.product-where.is-none i {
  color: var(--text3);
}

/* Where it's sold, a step below the title: regular weight and quieter, as a shop's card puts it. */
.product-store {
  margin-top: -4px;
  font: 500 var(--text-body-sm) / 1.3 var(--font-body);
  color: var(--text3);
}

/* A store-wide caution on each of its products (Toyworld's unreliable stock). Above the card's
   full-card link, so its text can be read and selected. */
.stock-notice {
  position: relative;
  z-index: 1;
  margin: 0;
  padding: 4px 8px;
  display: flex;
  gap: 6px;
  align-items: flex-start;
  font-size: var(--text-caption);
  line-height: 1.35;
  color: var(--warning);
  background: var(--warning-bg);
  border-radius: 6px;
}

.stock-notice i {
  flex: none;
  margin-top: 2px;
}

.product-price {
  margin-top: auto;
  display: flex;
  align-items: baseline;
  gap: var(--space-xs);
  flex-wrap: wrap;
}

.price-unknown {
  color: var(--text3);
  font-size: var(--text-body-sm);
}

.price {
  font: 700 var(--price-lg) / 1.1 var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text1);
}

.price-md {
  font-size: var(--price-md);
}

.price-was {
  font: 400 var(--price-was) var(--font-mono);
  color: var(--text3);
  text-decoration: line-through;
}

.product.is-out .price {
  color: var(--text3);
}

/* Per-branch availability */
/* A card's two ways to be told, in words: DM me, and Speed checkout, one above the other so neither
   is cut short. Above the card's link, at its foot. */
.card-actions {
  position: relative;
  z-index: 2;
  display: grid;
  gap: 6px;
  margin-top: auto;
}

.card-act {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 0;
  min-height: 34px;
  padding: 0 10px;
  border: 2px solid var(--border-visible);
  border-radius: var(--radius-control);
  background: var(--surface1);
  color: var(--text1);
  font-size: var(--text-body-sm);
  font-weight: 600;
  white-space: nowrap;
  transition:
    border-color var(--duration-fast) var(--ease),
    color var(--duration-fast) var(--ease);
}

.card-act span {
  overflow: hidden;
  text-overflow: ellipsis;
}

.card-act:hover {
  border-color: var(--text2);
}

.card-act[aria-pressed='true'] {
  border-color: var(--accent);
  color: var(--accent);
}

.card-act-speed i {
  color: var(--warning);
}

.stock-detail {
  position: relative;
  z-index: 2;
  border-top: 1px solid var(--border);
  padding-top: 8px;
}

.stock-detail summary {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  list-style: none;
  font-weight: 500;
  font-size: var(--text-body-sm);
  color: var(--text2);
}

.stock-detail summary::-webkit-details-marker {
  display: none;
}

.stock-detail summary i {
  margin-left: auto;
  color: var(--text3);
  transition: transform var(--duration-medium) var(--ease);
}

.stock-detail[open] summary i {
  transform: rotate(180deg);
  color: var(--accent);
}

.stock-detail summary:hover {
  color: var(--text1);
}

.stock-list {
  list-style: none;
  margin-top: 8px;
  max-height: 220px;
  overflow-y: auto;
}

.stock-row {
  display: flex;
  align-items: center;
  min-height: 36px;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 0;
  border-top: 1px solid var(--border);
  font-size: var(--text-body-sm);
}

.stock-row:first-child {
  border-top: none;
}

.stock-row .loc {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

/* A branch's name over two lines at most: "JB Hi-Fi sto..." said nothing of which one. */
.stock-row .loc span:last-of-type {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-height: 1.3;
}

.stock-row.is-out {
  color: var(--text3);
}

.stock-row .level {
  flex-shrink: 0;
  font: 400 var(--text-caption) var(--font-body);
  color: var(--text3);
  font-variant-numeric: tabular-nums;
}

.stock-row.is-in .level {
  color: var(--success);
}

.maps-link {
  color: var(--text3);
  font-size: 14px;
}

/* The branch name is the directions link: it keeps the row's text colour, the pin carries the hint. */
a.loc.maps-link {
  align-self: stretch;
  color: inherit;
  font-size: inherit;
}

a.loc.maps-link i {
  color: var(--text3);
}

.maps-link:hover,
a.loc.maps-link:hover i {
  color: var(--accent);
}

/* Skeleton: a hard-edged band stepping across, never a soft shimmer. */
.skel {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--radius-control);
  background: var(--surface2);
}

.skel::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  width: 30%;
  background: var(--surface3);
  animation: sweep 1.2s steps(8, end) infinite;
}

@keyframes sweep {
  from {
    left: -30%;
  }
  to {
    left: 100%;
  }
}

.empty {
  grid-column: 1 / -1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: var(--space-2xl) var(--space-lg);
  text-align: center;
}

.empty-art {
  position: relative;
  width: 88px;
  height: 88px;
  margin-bottom: 6px;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: 50%;
  background: var(--surface2);
  color: var(--accent);
}

.empty-art .glyph {
  position: relative;
  z-index: 1;
}

.empty h2 {
  font-weight: 600;
  font-size: var(--text-subheading);
  color: var(--text2);
}

.empty p {
  max-width: 380px;
  color: var(--text3);
}

/* ── Activity feed ────────────────────────────────────── */

.feed {
  list-style: none;
  overflow: hidden;
}

/* Two lines, as an order list draws them: the product and when; then what happened, where, and
   the price at the end. */
.event {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr);
  align-items: center;
  gap: 14px;
  min-height: 64px;
  padding: 10px 16px;
  border-top: 1px solid var(--border);
}

.event:first-child {
  border-top: none;
}

.event:hover {
  background: var(--surface2);
}

.event.is-new {
  background: var(--restock-bg);
  box-shadow: inset 3px 0 0 var(--restock);
}

.event-thumb {
  position: relative;
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: var(--radius-control);
  background: var(--surface2);
  color: var(--text4);
}

.event-thumb.has-image {
  background: #e9e8f2;
}

.event-thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 4px;
}

.event-main {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.event-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  min-width: 0;
}

.event-main a {
  min-width: 0;
  font-weight: 600;
  font-size: var(--text-body-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.event-main a:hover {
  color: var(--accent);
}

.event-line {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-size: var(--text-body-sm);
  color: var(--text2);
}

.event-line .badge {
  flex-shrink: 0;
}

.event-store {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.event-price {
  display: flex;
  flex-shrink: 0;
  align-items: baseline;
  gap: 6px;
  margin-left: auto;
}

.event-price b {
  color: var(--text1);
  font-weight: 700;
}

.event-price s {
  color: var(--text3);
  font-size: var(--text-caption);
}

.event time {
  flex-shrink: 0;
  color: var(--text3);
  font: 400 var(--text-caption) var(--font-body);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ── Stores ───────────────────────────────────────────── */

/* Every store as one grouped list, a row each (as iOS Settings lists things): two columns on a
   wide screen. A row browses that store; its small button opens the store's own site. */
.stores {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(360px, 100%), 1fr));
  column-gap: var(--space-xl);
  padding: 4px 18px;
  background: var(--surface1);
  border: 2px solid var(--card-border);
  border-radius: var(--radius-container);
  box-shadow: var(--shadow-1);
}

.store-line {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  border-bottom: 1px solid var(--border);
}

.store-line-main {
  display: flex;
  flex: 1;
  align-items: center;
  gap: 12px;
  min-width: 0;
  min-height: 64px;
  padding: 10px 0;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.store-line-main:hover .store-line-name,
.store-line-main:focus-visible .store-line-name {
  color: var(--accent);
}

.store-line .monogram {
  flex-shrink: 0;
}

.store-line-text {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.store-line-name,
.store-line-meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.store-line-name {
  font-weight: 600;
}

.store-line-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--text3);
  font-size: var(--text-body-sm);
  font-variant-numeric: tabular-nums;
}

.store-line.is-failing .store-line-meta {
  color: var(--error);
}

.store-line-count {
  display: flex;
  flex-shrink: 0;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1.15;
}

.store-line-count b {
  color: var(--text1);
  font-size: 17px;
}

.store-line-count small {
  color: var(--text3);
  font-size: var(--text-caption);
}

.store-line-count.is-zero b {
  color: var(--text4);
}

.store-line-go {
  flex-shrink: 0;
  color: var(--text4);
}

.store-line-site {
  display: grid;
  flex-shrink: 0;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-control);
  color: var(--text3);
}

.store-line-site:hover,
.store-line-site:focus-visible {
  background: var(--surface2);
  color: var(--text1);
}

@media (max-width: 860px) {
  .stores {
    padding: 2px 4px 2px 14px;
  }

  /* The whole row is the button; the name gets the chevron's room. */
  .store-line-go {
    display: none;
  }
}

.store {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 18px;
  min-width: 0;
}

.store.is-failing {
  border-color: var(--error);
}

.store-top {
  display: flex;
  align-items: center;
  gap: 12px;
}

.monogram {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  border-radius: var(--radius-control);
  background: var(--surface3);
  font-family: var(--font-display);
  font-size: 15px;
}

.store-name {
  display: block;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.store-name:hover {
  color: var(--accent);
}

.store-via {
  font: 400 var(--text-caption) var(--font-body);
  color: var(--text3);
  font-variant-numeric: tabular-nums;
}

.store-mid {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
}

.store-count {
  font-family: var(--font-display);
  font-size: var(--text-heading);
  line-height: 1;
}

.store-count.is-zero {
  color: var(--text4);
}

.store-count small {
  display: block;
  margin-top: 6px;
  color: var(--text3);
}

.store-check {
  display: flex;
  align-items: center;
  gap: 6px;
  font: 400 var(--text-caption) var(--font-body);
  color: var(--text3);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.store-error {
  padding: 8px 10px;
  border-radius: var(--radius-control);
  background: var(--error-bg);
  box-shadow: inset 3px 0 0 var(--error);
  font: 400 var(--text-caption) / 1.4 var(--font-body);
  color: var(--text1);
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}

.store-foot > span:first-child {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.store-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

.store-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font: 400 var(--text-caption) var(--font-body);
  color: var(--text3);
  font-variant-numeric: tabular-nums;
}

/* ── Watchlist tab ────────────────────────────────────── */

.count-badge.is-in {
  background: var(--success);
  color: var(--on-accent);
}

/* ── Account ──────────────────────────────────────────── */

.watch-sync {
  margin: -8px 0 0;
  color: var(--text2);
  font-size: var(--text-body-sm);
}

.watch-sync .link-btn {
  font-size: inherit;
}

.acct .opt {
  padding-left: 0;
}

.acct-note {
  font-size: var(--text-body-sm);
  line-height: 1.5;
  color: var(--text2);
}

.acct-error {
  margin-top: 12px;
  font-size: var(--text-body-sm);
  color: var(--error);
}

.acct-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 12px;
}

.acct-danger {
  color: var(--error);
}

.acct-note a,
.acct-fine a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.acct-fine {
  margin-top: 14px;
  font-size: var(--text-caption);
  line-height: 1.5;
  color: var(--text3);
}

/* Straight back from member login: one line saying what just switched on. */
.member-note {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 16px;
  padding: 10px 14px;
  border-radius: 4px;
  background: var(--success-bg);
  border-left: 2px solid var(--success);
  font-size: var(--text-body-sm);
}

.member-note i {
  font-size: 18px;
  color: var(--success);
}

/* The radar trails the Discord; one quiet line says so, and where live is. */
.delay-note {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  font-size: var(--text-caption);
  color: var(--text3);
}

.delay-note .sep {
  color: var(--border-visible);
}

.delay-note i {
  color: var(--text3);
}

.delay-note a {
  font-weight: 600;
  color: var(--accent);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

/* ── Modals (welcome, account) ────────────────────────── */

.modal {
  width: min(520px, calc(100vw - 32px));
  max-height: min(720px, calc(100vh - 48px));
  /* A phone's toolbars eat into 100vh; dvh is the height actually on screen. */
  max-height: min(720px, calc(100dvh - 32px));
  margin: auto;
  padding: 0;
  color: var(--text1);
  background: var(--surface1);
  border: 2px solid var(--border-visible);
  border-radius: var(--radius-container);
  box-shadow: var(--shadow-3);
}

.modal[open] {
  display: flex;
  flex-direction: column;
}

.modal::backdrop {
  background-color: rgb(8 7 15 / 80%);
  background-color: color-mix(in srgb, var(--background) 80%, transparent);
  background-image: radial-gradient(var(--halftone) 1.2px, transparent 1.4px);
  background-size: 8px 8px;
}

.modal-head {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 20px 24px 14px;
}

.modal-head h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 22px;
  line-height: 1;
}

.modal-x {
  margin-left: auto;
}

/* flex: 1 1 auto, not flex: 1: Safari squashes a 0%-basis child of an auto-height column to
   nothing, which left the dialogs compressed with their text hidden on iPhones. */
.modal-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 0 24px 16px;
}

/* Warning banner, as the system draws one: tinted fill, 2px left rule, icon in the status colour. */
.modal-note {
  display: flex;
  gap: 12px;
  padding: 12px 16px;
  border-radius: 4px;
  background: var(--warning-bg);
  border-left: 2px solid var(--warning);
  font-size: var(--text-body-sm);
}

.modal-note > i {
  flex-shrink: 0;
  font-size: 20px;
  color: var(--warning);
}

.modal-note b {
  font-weight: 600;
}

.modal-note p {
  margin-top: 4px;
  line-height: 1.5;
  color: var(--text2);
}

.modal-intro {
  font-size: 15px;
  line-height: 1.55;
  color: var(--text2);
}

.modal-plan + .modal-note {
  margin-top: 18px;
}

.modal-body h3 {
  margin: 22px 0 8px;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text3);
}

.modal-plan {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding-left: 20px;
  font-size: var(--text-body-sm);
  line-height: 1.5;
  color: var(--text2);
}

.modal-plan b {
  color: var(--text1);
  font-weight: 600;
}

.modal-plan li::marker {
  color: var(--accent);
}

.modal-links {
  display: flex;
  gap: 8px;
  margin-top: 10px;
  font-size: var(--text-body-sm);
  color: var(--text3);
}

.modal-links a {
  font-weight: 600;
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.modal-foot {
  flex-shrink: 0;
  display: flex;
  justify-content: flex-end;
  gap: var(--space-sm);
  padding: 14px 24px 20px;
  border-top: 1px solid var(--border);
}

/* ── Mobile tab bar ───────────────────────────────────── */

.tabbar {
  display: none;
}

/* ── Responsive ───────────────────────────────────────── */

@media (max-width: 860px) {
  .radar-bar {
    position: static;
  }

  .radar-bar-in {
    min-height: 56px;
    gap: 8px;
  }

  .radar-tabs {
    display: none;
  }

  .radar-tools {
    flex: 1;
    min-width: 0;
    margin-left: 0;
    gap: 8px;
  }

  .lcd {
    flex: 1;
    min-width: 0;
  }

  .toggle-btn span {
    display: none;
  }

  .radar-tools .toggle-btn {
    padding: 0 10px;
  }

  .content {
    padding-top: var(--space-md);
    padding-bottom: var(--space-xl);
  }

  /* The footer's last line clears the tab bar fixed over it. */
  .radar-page .lp-footer {
    padding-bottom: calc(48px + 64px + env(safe-area-inset-bottom));
  }

  .filters {
    gap: 12px;
    padding: 14px;
  }

  .input-lg {
    height: 48px;
    padding-right: 16px;
    font-size: 16px;
  }

  .search-field .kbd {
    display: none;
  }

  /* Chips become a single swipeable strip, faded at the edge to say there's more. */
  .chips {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    margin: 0 -14px;
    padding: 0 14px 4px;
    -webkit-mask-image: linear-gradient(90deg, #000 85%, transparent);
    mask-image: linear-gradient(90deg, #000 85%, transparent);
  }

  .chips::-webkit-scrollbar {
    display: none;
  }

  .chips-bare {
    margin: 0 -16px 16px;
    padding: 0 16px 4px;
  }

  /* Like a shopping app's search: the box on its own, then one row of chips that scrolls sideways.
     The first opens every filter in a sheet and says how many are on; each other chip opens its own
     sheet, filled once it is set and showing what it is set to. No box around any of it, and no
     second row of chips to undo them (the filled chips say what is on; Clear all is in the sheet). */
  .filters {
    gap: 10px;
    margin-bottom: 14px;
    padding: 0;
    background: none;
    border: 0;
    box-shadow: none;
  }

  .search-field {
    min-width: 0;
  }

  .filters .results-row {
    display: none;
  }

  .filterbar {
    display: flex;
    flex-wrap: nowrap;
    gap: 8px;
    margin: 0 -16px;
    padding: 0 16px 2px;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(90deg, #000 88%, transparent);
    mask-image: linear-gradient(90deg, #000 88%, transparent);
  }

  .filterbar::-webkit-scrollbar {
    display: none;
  }

  /* A mask clips everything inside it, the menus that open from the row among them. */
  .filterbar:has(.menu:not([hidden])) {
    -webkit-mask-image: none;
    mask-image: none;
  }

  .filterbar > *,
  .type-anchor {
    display: block;
    flex-shrink: 0;
  }

  .filterbar .fpill {
    height: 38px;
    padding: 0 12px;
    gap: 6px;
    border-color: transparent;
    background: var(--surface2);
    color: var(--text1);
    font-weight: 600;
    font-size: 14px;
  }

  /* Words, not icons, in the row: the icons come back in the sheet. */
  .filterbar .menu-anchor .fpill > i:first-child,
  .filterbar .fpill-toggle > i {
    display: none;
  }

  .filterbar .fpill-label {
    max-width: 150px;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .filterbar .fpill .caret {
    font-size: 12px;
  }

  .filterbar .fpill.is-active,
  .filterbar .fpill-toggle:has(input:checked) {
    border-color: var(--accent);
    background: var(--accent);
    color: var(--on-accent);
  }

  .filterbar .filters-btn {
    display: inline-flex;
    order: -1;
    padding: 0 14px;
    font-size: 15px;
  }

  .filterbar .filters-btn i {
    font-size: 18px;
  }

  .filterbar .filters-btn:has(.filters-count:not([hidden])) {
    background: var(--accent);
    color: var(--on-accent);
  }

  .filters-count {
    font-weight: 700;
  }

  .filterbar .fpill-toggle {
    display: inline-flex;
    order: 1;
  }

  .lang-anchor {
    order: 2;
  }

  .sort-anchor {
    order: 3;
    margin-left: 0;
  }

  .sort-anchor .fpill-label {
    display: none;
  }

  .fpill-short {
    display: inline;
  }

  /* Behind the first chip, every filter in one sheet, as the Shop app lays it out: a row a filter
     with what is picked at its end, a switch for "In stock only", and Show results at the foot. A
     row opens its options as a page over the same sheet, with a back arrow, never a second sheet
     stacked on the first. */
  .filters.is-sheet-open {
    --sheet-h: min(560px, calc(100dvh - 64px));
  }

  .filters.is-sheet-open .filterbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 48;
    display: flex;
    flex-direction: column;
    gap: 0;
    height: var(--sheet-h);
    margin: 0;
    padding: 0;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--surface1);
    border-top: 2px solid var(--border-visible);
    border-radius: 16px 16px 0 0;
    -webkit-mask-image: none;
    mask-image: none;
    animation: sheet-up var(--duration-slow) var(--ease);
  }

  .filters.is-sheet-open .filterbar > * {
    width: 100%;
  }

  .filters.is-sheet-open .filterbar .filters-btn {
    display: none;
  }

  .filters.is-sheet-open .filterbar .sheet-head {
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    order: 0;
    align-items: center;
    justify-content: space-between;
    min-height: 60px;
    padding: 0 8px 0 20px;
    background: var(--surface1);
    border-bottom: 1px solid var(--border);
    font-size: 18px;
  }

  .filters.is-sheet-open .sheet-head .menu-x {
    width: 44px;
    height: 44px;
    border: 0;
    background: transparent;
    font-size: 20px;
  }

  /* A row: the filter's name, what is picked, a chevron. */
  .filters.is-sheet-open .filterbar .fpill {
    justify-content: flex-start;
    gap: 12px;
    width: 100%;
    height: auto;
    min-height: 56px;
    padding: 0 20px;
    border: 0;
    border-bottom: 1px solid var(--border);
    border-radius: 0;
    background: transparent;
    color: var(--text1);
    font-size: 16px;
    font-weight: 500;
    white-space: nowrap;
  }

  .filters.is-sheet-open .filterbar .fpill:active {
    background: var(--surface2);
  }

  .filters.is-sheet-open .filterbar .fpill > i:first-child,
  .filters.is-sheet-open .filterbar .fpill-label,
  .filters.is-sheet-open .filterbar .fpill-short,
  .filters.is-sheet-open .filterbar .fpill .caret {
    display: none;
  }

  .filters.is-sheet-open .fpill-name {
    display: block;
    flex-shrink: 0;
  }

  .filters.is-sheet-open .fpill-value {
    display: block;
    flex: 1;
    min-width: 0;
    overflow: hidden;
    color: var(--text3);
    font-weight: 400;
    text-align: right;
    text-overflow: ellipsis;
  }

  .filters.is-sheet-open .fpill.is-active .fpill-value {
    color: var(--accent);
    font-weight: 500;
  }

  .filters.is-sheet-open .row-go {
    display: block;
    flex-shrink: 0;
    color: var(--text4);
    font-size: 16px;
  }

  .filters.is-sheet-open .sort-anchor {
    order: 1;
  }

  .filters.is-sheet-open .type-anchor {
    order: 2;
  }

  .filters.is-sheet-open .filterbar > .menu-anchor:not(.type-anchor):not(.lang-anchor):not(.sort-anchor) {
    order: 3;
  }

  .filters.is-sheet-open .lang-anchor {
    order: 4;
  }

  /* "In stock only" as a switch at its row's end. */
  .filters.is-sheet-open .filterbar .fpill-toggle {
    order: 5;
    justify-content: space-between;
  }

  .filters.is-sheet-open .fpill-switch {
    position: relative;
    display: block;
    flex-shrink: 0;
    width: 50px;
    height: 30px;
    border-radius: 15px;
    background: var(--surface3);
    transition: background var(--duration-medium) var(--ease);
  }

  .filters.is-sheet-open .fpill-switch::after {
    content: '';
    position: absolute;
    top: 3px;
    left: 3px;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgb(0 0 0 / 35%);
    transition: transform var(--duration-medium) var(--ease);
  }

  .filters.is-sheet-open .fpill-toggle:has(input:checked) .fpill-switch {
    background: var(--success);
  }

  .filters.is-sheet-open .fpill-toggle:has(input:checked) .fpill-switch::after {
    transform: translateX(20px);
  }

  .filters.is-sheet-open .filterbar .fpill-toggle:has(input:checked) {
    background: transparent;
    color: var(--text1);
  }

  .filters.is-sheet-open .filterbar .sheet-foot {
    position: sticky;
    bottom: 0;
    display: flex;
    order: 9;
    align-items: center;
    gap: 16px;
    margin-top: auto;
    padding: 12px 20px calc(12px + env(safe-area-inset-bottom));
    background: var(--surface1);
    border-top: 1px solid var(--border);
  }

  .filterbar .sheet-foot .btn {
    flex: 1;
    height: 50px;
    font-size: 15px;
  }

  @keyframes sheet-up {
    from {
      transform: translateY(32px);
      opacity: 0;
    }
  }

  @keyframes page-in {
    from {
      transform: translateX(40px);
      opacity: 0;
    }
  }

  /* On a phone the type chips wait in their sheet, wrapped, with room for a thumb. */
  .type-sheet .chips {
    flex-wrap: wrap;
    overflow: visible;
    margin: 0;
    padding: 4px 14px 14px;
    -webkit-mask-image: none;
    mask-image: none;
  }

  .type-sheet .chip span {
    height: 40px;
    padding: 0 16px;
    font-size: 14px;
  }

  .menu,
  .menu-end {
    position: fixed;
    top: auto;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 50;
    width: auto;
    max-height: 80vh;
    border-width: 2px 0 0;
    border-radius: 12px 12px 0 0;
    box-shadow: none;
    padding-bottom: env(safe-area-inset-bottom);
  }

  .menu::before {
    content: '';
    align-self: center;
    flex-shrink: 0;
    width: 40px;
    height: 4px;
    margin-top: 8px;
    border-radius: 2px;
    background: var(--surface3);
  }

  .menu-x {
    display: inline-flex;
  }

  .opt {
    min-height: 44px;
  }

  .menu-done {
    flex: 1;
    height: 44px;
  }

  /* Inside the filter sheet, an option page covers it exactly: same height, same place, a back
     arrow where the close was. */
  .filters.is-sheet-open .menu {
    z-index: 49;
    height: var(--sheet-h);
    max-height: none;
    border-radius: 16px 16px 0 0;
    animation: page-in var(--duration-medium) var(--ease);
  }

  .filters.is-sheet-open .menu::before,
  .filters.is-sheet-open .menu-head .menu-x {
    display: none;
  }

  .filters.is-sheet-open .menu-head {
    justify-content: flex-start;
    gap: 4px;
    min-height: 60px;
    padding: 0 20px 0 6px;
    border-bottom: 1px solid var(--border);
  }

  .filters.is-sheet-open .menu-head b {
    font-size: 18px;
  }

  .filters.is-sheet-open .menu-head .menu-back {
    display: grid;
    width: 44px;
    height: 44px;
    border: 0;
    background: transparent;
    font-size: 20px;
  }

  .filters.is-sheet-open .menu-list {
    padding: 6px 12px;
  }

  .filters.is-sheet-open .menu-foot {
    gap: 16px;
    padding: 12px 20px calc(12px + env(safe-area-inset-bottom));
  }

  .filters.is-sheet-open .menu-done {
    height: 50px;
    font-size: 15px;
  }

  .filters.is-sheet-open .type-sheet .chips {
    flex: 1;
    align-content: flex-start;
    padding: 16px 20px;
  }

  @media (prefers-reduced-motion: reduce) {
    .filters.is-sheet-open .filterbar,
    .filters.is-sheet-open .menu {
      animation: none;
    }
  }

  .menu-backdrop:not([hidden]) {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 45;
    background: color-mix(in srgb, var(--background) 80%, transparent);
  }

  body.sheet-open {
    overflow: hidden;
  }

  /* The sheets live inside the shell, which sits under the tab bar; lift it so a sheet's
     "Show results" button isn't hidden behind the tabs, and the backdrop dims them too. */
  body.sheet-open .radar-main {
    z-index: 45;
  }

  .toasts {
    right: 12px;
    left: 12px;
    width: auto;
    bottom: calc(76px + env(safe-area-inset-bottom));
  }

  .tabbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 30;
    display: flex;
    height: calc(64px + env(safe-area-inset-bottom));
    padding-bottom: env(safe-area-inset-bottom);
    background: var(--surface1);
    border-top: 2px solid var(--border);
  }

  .tabbar button {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    font-weight: 500;
    font-size: 11px;
    color: var(--text3);
  }

  .tabbar button i {
    font-size: 20px;
  }

  .tabbar button[aria-selected='true'] {
    color: var(--accent);
    box-shadow: inset 0 3px 0 var(--accent);
  }

  .icon-wrap {
    position: relative;
    display: inline-flex;
  }

  /* The Admin sheet lives in the radar bar: lifted over the page (and its backdrop) while open. */
  body.admin-open .radar-bar {
    position: relative;
    z-index: 46;
  }

  /* On a phone the Admin menu comes up from the bottom, over the tab bar. */
  .admin-menu {
    position: fixed;
    top: auto;
    left: 0 !important;
    right: 0;
    bottom: 0;
    max-height: 80vh;
    overflow-y: auto;
    padding: 0 10px calc(10px + env(safe-area-inset-bottom));
    border-width: 2px 0 0;
    border-radius: 12px 12px 0 0;
    box-shadow: none;
  }

  .admin-menu-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 4px 6px;
  }

  .admin-menu [data-tab] {
    min-height: 48px;
    font-size: 15px;
  }
}

@media (max-width: 600px) {
  /* Two cards side by side: the photo on top, the essentials under it. */
  .grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
  }

  .product {
    gap: 6px;
    padding: 8px;
  }

  .product .well-status {
    top: 6px;
    left: 6px;
  }

  .card-act {
    min-height: 32px;
    padding: 0 6px;
    font-size: 12px;
  }

  .product h3 {
    font-size: var(--text-body-sm);
  }

  .product-store {
    margin-top: -2px;
    font-size: 12px;
  }

  .product-where {
    margin-top: -2px;
    font-size: 12px;
  }

  .product .tag {
    max-width: 100%;
    height: 20px;
    padding: 0 6px;
    overflow: hidden;
    font-size: 11px;
    text-overflow: ellipsis;
  }

  .price {
    font-size: var(--price-md);
  }

  .product .price-was {
    font-size: 12px;
  }

  .product .stock-detail summary {
    font-size: 12px;
  }
}

@media (max-width: 460px) {
  .event {
    grid-template-columns: 40px minmax(0, 1fr);
  }

  .event-thumb {
    width: 40px;
    height: 40px;
  }

  /* The new price only: the old one beside it left the store's name a letter wide. */
  .event-price s {
    display: none;
  }
}

.row-status {
  display: none;
  flex-wrap: wrap;
  gap: 4px;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition-duration: 0ms !important;
  }
}

@media (max-width: 480px) {
  /* The browser's own dialog rule caps width at 100% - 2em; let it use the phone's width. */
  .modal {
    width: calc(100vw - 20px);
    max-width: calc(100vw - 20px);
  }

  .modal-head {
    padding: 16px 16px 10px;
  }

  .modal-head h2 {
    font-size: 20px;
  }

  .modal-body {
    padding: 0 16px 14px;
  }

  .modal-foot {
    padding: 12px 16px 16px;
  }
}

/* The welcome's one-line caveat about stock, quieter than a warning box. */
.modal-fine {
  margin: 4px 0 0;
  font-size: var(--text-body-sm);
  line-height: 1.5;
  color: var(--text3);
}

/* Under the grid: the next page of cards. Wide on a phone, where it's what the thumb lands on. */
.show-more {
  min-width: min(100%, 280px);
}

.show-more[hidden] {
  display: none;
}

/* ── Confirming and saying so ─────────────────────────── */

.modal-confirm {
  width: min(420px, calc(100vw - 32px));
}

.confirm-body {
  margin: 0;
  line-height: 1.55;
  color: var(--text2);
}

.confirm-body b {
  color: var(--text1);
}

.confirm-foot {
  gap: 10px;
}

.btn-danger {
  background: var(--error);
  border-color: var(--error);
  color: #fff;
}

.btn-danger:hover {
  filter: brightness(1.1);
}

.toast-ok {
  color: var(--success);
}

/* ── Alerts: one page (renderAlertsLayout in app.js) ─────────────────────────────────────────── */
/* Its heading and what it's for, the set-up, then Speed checkout and DM alerts, each a block. */
#watchlist-panel:not([hidden]) {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  gap: var(--space-lg);
}

/* A wide screen: Speed checkout and DM alerts side by side under the heading and the set-up. */
@media (min-width: 1100px) {
  #watchlist-panel:not([hidden]) {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  #watchlist-panel > .alerts-head,
  #watchlist-panel > .dm-gate,
  #watchlist-panel > .setup {
    grid-column: 1 / -1;
  }

  /* Without Speed checkout, DM alerts takes the width. */
  #speed-block[hidden] + #dm-block {
    grid-column: 1 / -1;
  }
}

.alerts-head h2 {
  margin: 0 0 6px;
  font-family: var(--font-display);
  font-size: var(--text-heading);
  font-weight: 400;
  letter-spacing: 0.02em;
}

.alert-block:not([hidden]) {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.block-head h2 {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: var(--text-subheading);
  font-weight: 700;
}

.block-head h2 i {
  color: var(--accent);
}

#speed-title i {
  color: var(--warning);
}

.block-head p {
  max-width: 640px;
  margin: 4px 0 0;
  color: var(--text2);
  font-size: var(--text-body-sm);
  line-height: 1.5;
}

.block-head .watch-sync {
  color: var(--text3);
}

/* Set-up: a step a row, a ring for each that's done, the next one marked; one line once all are. */
.setup {
  display: grid;
  gap: 12px;
  padding: 18px 20px;
  border-color: var(--accent);
}

.setup-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.setup-head h2 {
  margin: 0;
  font-size: var(--text-subheading);
  font-weight: 700;
}

.setup-count {
  color: var(--text3);
  font: 700 var(--text-label) / 1.3 var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.setup-steps {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--border);
}

.setup-step {
  border-bottom: 1px solid var(--border);
}

.setup-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 56px;
  padding: 8px 4px;
  color: var(--text1);
  text-align: left;
}

button.setup-row:hover {
  background: var(--surface2);
}

.setup-dot {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border: 2px solid var(--border-visible);
  border-radius: 50%;
}

.setup-step.is-next .setup-dot {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-subtle);
}

.setup-step.is-done .setup-dot {
  border-color: var(--success);
  background: var(--success);
}

.setup-step.is-done .setup-dot::after {
  content: '';
  width: 6px;
  height: 10px;
  margin-top: -2px;
  border: solid var(--bg, #0b0a14);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.setup-text {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.setup-text b {
  font-size: var(--text-body-sm);
}

.setup-text small {
  color: var(--text3);
  font-size: var(--text-caption);
  overflow-wrap: anywhere;
}

.setup-step.is-done .setup-text small {
  color: var(--text2);
}

.setup-go {
  flex: 0 0 auto;
  color: var(--accent);
  font: 700 var(--text-label) / 1 var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.setup-go::after {
  content: ' \25BE';
}

.setup-row[aria-expanded='true'] .setup-go::after {
  content: ' \25B4';
}

/* The next step's button is the one bright thing in the card. */
.setup-step.is-next .setup-go {
  padding: 8px 12px;
  border-radius: var(--radius-control);
  background: var(--accent);
  color: var(--on-accent);
}

.setup-panel {
  padding: 4px 0 18px 34px;
}

/* All done: the card is one line, each step a chip, still opening to manage it. */
.setup.is-complete {
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  column-gap: 20px;
  border-color: var(--border-visible);
}

.setup.is-complete .setup-head {
  display: block;
}

.setup.is-complete .setup-steps {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  border-top: 0;
}

.setup.is-complete .setup-step {
  border-bottom: 0;
}

.setup.is-complete .setup-step:has(.setup-panel:not([hidden])) {
  flex-basis: 100%;
}

.setup.is-complete .setup-row {
  min-height: 0;
  padding: 6px 12px 6px 8px;
  border: 2px solid var(--border-visible);
  border-radius: var(--radius-pill);
}

.setup.is-complete .setup-text small,
.setup.is-complete .setup-go {
  display: none;
}

.setup.is-complete .setup-dot {
  width: 18px;
  height: 18px;
}

.setup.is-complete .setup-panel {
  padding: 14px 0 4px;
}

/* A step opened, or a phone: the heading over the steps. */
.setup.is-complete:has(.setup-panel:not([hidden])) {
  grid-template-columns: minmax(0, 1fr);
}

@media (max-width: 600px) {
  .setup {
    padding: 16px;
  }

  .setup.is-complete {
    grid-template-columns: minmax(0, 1fr);
  }

  .setup-panel {
    padding-left: 0;
  }
}

.view-lead {
  max-width: 640px;
  margin: 0;
  color: var(--text2);
  font-size: var(--text-body-sm);
  line-height: 1.55;
}

.follow-card,
.watch-card {
  display: grid;
  gap: 16px;
  padding: 18px 20px;
}

/* A card's heading, what it counts beside it, and the one line under it. */
.alert-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.alert-card-head h2,
.alert-card-head h3 {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: var(--text-subheading);
  font-weight: 600;
}

.alert-card-head h2 i,
.alert-card-head h3 i {
  color: var(--accent);
}

.alert-card-count {
  color: var(--text3);
  font: 400 var(--text-caption) / 1.2 var(--font-mono);
}

.alert-card-sub {
  margin: -8px 0 0;
  color: var(--text2);
  font-size: var(--text-body-sm);
  line-height: 1.5;
}

.alert-card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.alert-empty {
  margin: 0;
  color: var(--text2);
  font-size: var(--text-body-sm);
  line-height: 1.5;
}

.alert-more {
  justify-self: start;
}

/* What's followed, at a glance: the sets, then the stores, as tags. */
.follow-facts {
  display: grid;
  gap: 10px;
  margin: 0;
}

.follow-facts > div {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr);
  gap: 10px;
  align-items: baseline;
}

.follow-facts dt {
  color: var(--text3);
  font: 700 var(--text-label) / 2 var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.follow-facts dd {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
}

.tag-quiet {
  border: 1px dashed var(--surface3);
  background: transparent;
  color: var(--text3);
}

.follow-areas {
  display: grid;
  gap: 6px;
  margin-top: 10px;
}

.follow-areas .follow-area-box {
  margin-top: 0;
}

/* Watched products: rows in one card, divided, the in-stock ones ringed. */
.watch-card .watch-list {
  gap: 0;
}

.watch-card .watch-row {
  padding: 14px 0;
  border-top: 2px solid var(--border);
}

.watch-card .watch-row:first-child {
  padding-top: 0;
  border-top: 0;
}

.watch-card .watch-row.is-in .watch-thumb {
  box-shadow: 0 0 0 2px var(--restock);
}

/* Its buttons in a line, beside the product (under it on a phone): a row is no taller than its text. */
.watch-card .watch-actions {
  flex-direction: row;
  align-items: center;
}

.watch-card .alert-more {
  margin-top: 12px;
}

.follow-intro h2 {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 20px;
}

.follow-intro p {
  margin-top: 6px;
  color: var(--text2);
  line-height: 1.5;
}

.follow-step h3,
.follow-now h3,
.follow-sub {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
  font-size: 16px;
}

.follow-num {
  width: 24px;
  height: 24px;
  display: inline-grid;
  place-items: center;
  border-radius: 50%;
  background: var(--accent);
  color: var(--background);
  font-size: 13px;
  font-weight: 700;
}

.follow-region {
  width: 100%;
  max-width: 360px;
}

.follow-hint {
  margin: 10px 0 8px;
  font-size: var(--text-body-sm);
  color: var(--text2);
}

.follow-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.follow-chips .chip i {
  margin-left: -8px;
  align-self: center;
}

.follow-area {
  margin: 14px 0 4px;
  font-size: var(--text-body-sm);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text2);
}

.follow-branches {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 2px 12px;
}

.follow-online {
  margin-top: 10px;
}

.follow-save {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.follow-summary,
.follow-note {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  font-size: var(--text-body-sm);
  line-height: 1.45;
}

.follow-summary {
  color: var(--success);
}

.follow-note {
  color: var(--warning);
}

.follow-now {
  display: grid;
  gap: 10px;
  padding-top: 14px;
  border-top: 2px solid var(--border);
}

.follow-now h3 {
  margin: 0;
}

.follow-now ul {
  list-style: none;
  display: grid;
  margin: 0;
  padding: 0;
}

.follow-now li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px 12px;
  padding: 10px 0;
  border-top: 1px solid var(--border);
}

.follow-now li:first-child {
  padding-top: 0;
  border-top: 0;
}

.follow-now li a {
  font-weight: 600;
  color: var(--text1);
}

.follow-where {
  grid-column: 1;
  font-size: var(--text-body-sm);
  color: var(--success);
}

.follow-now li .num {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  font-weight: 700;
}

.follow-empty {
  color: var(--text2);
  font-size: var(--text-body-sm);
}

.follow-sub {
  margin-top: 8px;
}

.follow-area-box {
  margin-top: 8px;
  border: 1px solid var(--border-visible);
  border-radius: var(--radius-control);
}

.follow-area-box summary {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  cursor: pointer;
  font-weight: 600;
}

.follow-area-box summary .num {
  font-weight: 400;
  color: var(--text2);
}

.follow-area-box .follow-branches {
  padding: 0 8px 8px;
}

.follow-count {
  margin-left: 6px;
  font-size: 11px;
  opacity: 0.75;
}

/* Sign in and membership: one centred card, Discord first, with the radar's arcade type, surfaces
   and hard shadows. What happens comes first, then the one button, then what membership gets you;
   billing terms sit small at the card's foot, beside the button they belong to. */
.membership-page { display: grid; gap: 16px; width: 100%; max-width: 460px; margin: 8px auto 0; }
.membership-card { display: grid; gap: 20px; padding: 28px; min-width: 0; }
.membership-main { border-top: 3px solid var(--accent); }

.auth-head { display: grid; gap: 8px; }
.auth-head h1,
.auth-head h2 { font: 400 clamp(28px, 7vw, 36px) / 1.1 var(--font-display); letter-spacing: -0.5px; text-wrap: balance; }
.auth-head p { margin: 0; color: var(--text2); font-size: 16px; line-height: 1.5; }

.membership-status { justify-self: start; padding: 4px 8px; border: 1px solid var(--border-visible); border-radius: var(--radius-control); color: var(--text2); font: 700 11px / 1.5 var(--font-body); letter-spacing: 0.04em; text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}
.membership-status.is-active { color: var(--success); border-color: var(--success); background: var(--success-bg); }
.membership-status.is-warning { color: var(--warning); border-color: var(--warning); background: var(--warning-bg); }

.membership-price { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px; margin: 0; }
.membership-price strong { color: var(--text1); font: 700 34px / 1 var(--font-mono); letter-spacing: -1px; }
.membership-price span { color: var(--text2); font-size: 15px; }

.membership-form { margin: 0; }
.membership-actions { display: grid; gap: 10px; }
.membership-actions .btn { width: 100%; min-height: 48px; height: auto; padding: 12px 16px; white-space: normal; text-align: center; }
.btn[aria-busy='true'] i { animation: auth-spin 0.9s linear infinite; }

.membership-fine { margin: 0; color: var(--text3); font-size: 12px; line-height: 1.55; }
.membership-fine time { white-space: nowrap; }
.auth-switch { margin: 0; color: var(--text2); font-size: 14px; text-align: center; }
.auth-switch a, .membership-message a { color: var(--accent); font-weight: 500; text-decoration: underline; text-underline-offset: 3px; }

.auth-perks { display: grid; gap: 12px; margin: 0; padding: 18px 0 0; border-top: 1px solid var(--border); list-style: none; }
.auth-perks li { display: flex; align-items: center; gap: 12px; color: var(--text2); font-size: 14px; line-height: 1.35; }
.auth-perks li > i { display: grid; place-items: center; flex-shrink: 0; width: 34px; height: 34px; border-radius: var(--radius-control); background: var(--surface2); color: var(--text2); font-size: 18px; }
.auth-perks li > div { display: grid; gap: 2px; min-width: 0; }
.auth-perks b { color: var(--text1); font-weight: 600; }
.auth-perks .is-lead b { font-size: 16px; }
.auth-perks .is-lead > i { background: var(--discord); color: var(--on-discord); }
.auth-perks .is-lead span { font-size: 13px; }

/* After paying: the three things that switch alerts on, numbered like the steps they are. */
.setup-steps { display: grid; gap: 12px; margin: 0; padding: 0; list-style: none; counter-reset: setup; }
.setup-steps li { display: grid; grid-template-columns: 30px 1fr; column-gap: 12px; row-gap: 2px; align-items: start; counter-increment: setup; color: var(--text2); font-size: 14px; line-height: 1.4; }
.setup-steps li::before { content: counter(setup); grid-row: span 2; display: grid; place-items: center; width: 30px; height: 30px; border-radius: var(--radius-control); background: var(--surface2); color: var(--text1); font: 700 14px / 1 var(--font-mono); }
.setup-steps b { color: var(--text1); font-weight: 600; }
.membership-price.is-trial strong { color: var(--accent); }
.membership-details { display: grid; gap: 8px; margin: 0; padding: 12px 14px; border-radius: var(--radius-control); background: var(--surface2); font-size: 14px; }
.membership-details > div { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 16px; min-width: 0; }
.membership-details dt { color: var(--text2); }
.membership-details dd { display: inline-flex; align-items: center; gap: 6px; min-width: 0; margin: 0; font-weight: 500; overflow-wrap: anywhere; }

.membership-message { display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; border-left: 3px solid var(--accent); border-radius: var(--radius-control); background: var(--accent-subtle); }
.membership-message > i { flex-shrink: 0; color: var(--accent); font-size: 20px; }
.membership-message p { margin: 0; color: var(--text1); font-size: 14px; line-height: 1.5; }
.membership-message.is-warning { border-color: var(--warning); background: var(--warning-bg); }
.membership-message.is-warning > i { color: var(--warning); }
.membership-message.is-pending > i { animation: auth-spin 0.9s linear infinite; }

.membership-help { display: grid; }
.membership-help details { border-top: 1px solid var(--border); }
.membership-help details:last-child { border-bottom: 1px solid var(--border); }
/* A disclosure list, as iOS Settings draws one: the question, and a chevron at the end that turns open. */
.membership-help summary { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 48px; padding: 12px 0; cursor: pointer; list-style: none; color: var(--text1); font-size: 15px; font-weight: 500; }
.membership-help summary::-webkit-details-marker { display: none; }
.membership-help summary::after { content: ''; flex-shrink: 0; width: 8px; height: 8px; margin-right: 4px; border-right: 2px solid var(--text3); border-bottom: 2px solid var(--text3); transform: rotate(45deg) translateY(-2px); transition: transform var(--duration-medium) var(--ease); }
.membership-help details[open] summary::after { transform: rotate(-135deg) translateY(-2px); }
.membership-help details p { margin: 0 0 14px; color: var(--text2); font-size: 14px; line-height: 1.55; }

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

@media (prefers-reduced-motion: reduce) {
  .btn[aria-busy='true'] i, .membership-message.is-pending > i { animation: none; }
}

@media (max-width: 520px) {
  .membership-page { margin-top: 0; }
  .membership-card { gap: 18px; padding: 20px; }
  .membership-price strong { font-size: 30px; }
}

/* ── Account panel: /join's card and the radar's pop-up (renderAccountPanel) ─────────────────── */

.account-panel {
  display: grid;
  gap: 20px;
  min-width: 0;
}

.account-settings {
  display: grid;
  gap: 2px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}

.account-panel .account-subhead {
  margin: 0 0 6px;
  font: 700 12px / 1.4 var(--font-body);
  text-transform: uppercase;
  color: var(--text3);
  font-variant-numeric: tabular-nums;
}

.account-settings .opt {
  align-items: flex-start;
  padding-left: 0;
}

.account-settings .opt input {
  margin-top: 1px;
}

.account-settings .opt-name {
  white-space: normal;
}

.account-settings .opt:has(input:disabled) {
  color: var(--text3);
  cursor: not-allowed;
}

.account-settings .opt input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.account-status {
  margin: 0;
  font: 400 var(--text-caption) var(--font-body);
  color: var(--success);
  font-variant-numeric: tabular-nums;
}

.account-status.is-bad {
  color: var(--error);
}

.account-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.account-danger {
  color: var(--error);
}

.account-quiet {
  color: var(--text2);
}

/* In the radar's pop-up the panel is the whole dialog, with its own close button in the corner. */
.modal.acct:has(.account-panel) .modal-body {
  padding: 24px;
}

.acct-x {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 1;
}

.modal .auth-head h2 {
  padding-right: 44px;
  font-size: 28px;
}

/* The "?" key: what each badge on a card means. */
.key-list {
  display: grid;
  gap: 12px;
  margin: 0 0 16px;
  padding: 0;
  list-style: none;
}

.key-list li {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr);
  align-items: center;
  gap: 12px;
  font-size: var(--text-body-sm);
  color: var(--text2);
}

.key-list .badge {
  justify-self: start;
}

/* A thumb, not a cursor: on touch screens every control on the radar is at least 44px to tap. */
@media (pointer: coarse) {
  .icon-btn {
    width: 44px;
    height: 44px;
  }

  .fpill,
  .filterbar .fpill {
    height: 44px;
  }

  /* The directions link fills its row's height, so the whole row-high name is the target. */
  a.loc.maps-link {
    margin: -6px 0;
    padding: 6px 0;
  }

  .card-act,
  .stock-detail summary,
  .stock-row {
    min-height: 44px;
  }
}
