/* ───────────────────────── tokens ───────────────────────── */
:root {
  color-scheme: dark;
  --bg: #0b0d12;
  --bg-2: #10131a;
  --bg-3: #161a23;
  --bg-4: #1c2130;
  /* The product-photo display plate (owner 2026-10-08, option C3): a dim warm grey the photos' baked-in white backgrounds
     multiply into, so a photo sits on a deliberate plate instead of a harsh white rectangle on the dark page. */
  --plate-hi: #d8d3c7;
  --plate-lo: #c4bfb2;
  --line: #242a3a;
  --line-2: #2e3548;
  --text: #ecEEF4;
  --text-2: #b4bccd;
  --muted: #7f889c;
  --gold: #f2c04b;
  --gold-2: #ffd97a;
  --green: #35d38f;
  --lime: #a3e635;
  --amber: #fbbf24;
  --red: #f0616b;
  --crimson: #b3202e;
  --blue: #6eb5ff;
  --violet: #b59cff;
  --foil: linear-gradient(120deg, #f2c04b 0%, #ff8fbf 30%, #7ad0ff 60%, #a6ff9c 100%);
  --shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
  --r-xs: 6px;
  --r-sm: 10px;
  --r: 14px;
  --r-lg: 20px;
  /* 'Manrope Fallback' (defined right below) is Arial / Liberation Sans re-scaled to Manrope's metrics, so the
     display=swap from the fallback to the web font barely moves any text (story W2-TOKENS, font CLS). Android has
     neither Arial nor Liberation Sans, so 'Manrope Fallback Android' (Roboto re-scaled the same way, W2-MOTION)
     follows it: where the first has no local face, the browser falls through to the second. */
  --font: 'Manrope', 'Manrope Fallback', 'Manrope Fallback Android', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --nav-h: 62px;
  --side-w: 236px;
  --gutter: 16px;
  /* Height reserved for the mobile/tablet top strip (story UX-SHELL): 0 by default (desktop has no top strip —
     the sidebar carries the brand and language switch instead), redeclared below 1024 px. */
  --topstrip-h: 0px;

  /* ── W2-TOKENS "Foiled Signal": one shared vocabulary for type, space, depth and motion. Nothing above is
     renamed; --shadow stays and is the middle elevation step (--shadow-md). ── */
  --fs-xs: 11px; --fs-sm: 13px; /* owner-facing readability: secondary text never below 13 px on phones (orchestrator, 2026-09-26) */ --fs-md: 15px; --fs-lg: 17px; --fs-xl: 20px; --fs-2xl: 24px; --fs-3xl: 28px; --fs-display: 34px;
  --lh-tight: 1.15; --lh-normal: 1.45;
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px; --sp-6: 24px; --sp-8: 32px; --sp-10: 40px;
  --shadow-sm: 0 2px 8px rgba(0,0,0,.35); --shadow-md: var(--shadow); --shadow-lg: 0 20px 60px -10px rgba(0,0,0,.55);
  --shadow-glow-gold: 0 0 0 1px rgba(242,192,75,.25), 0 8px 30px -6px rgba(242,192,75,.35);
  --dur-fast: 120ms; --dur-base: 180ms; --dur-slow: 280ms; --ease-standard: cubic-bezier(.2,.8,.2,1); --ease-pop: cubic-bezier(.34,1.56,.64,1);
  --glass-bg: rgba(22,26,35,.6); --glass-border: rgba(255,255,255,.08);
}
/* Metric-matched fallback for Manrope (story W2-TOKENS). Values measured in Chromium against the real Manrope
   (unitsPerEm 2000, ascent 2132, descent 600, line gap 0) on the app's own rendered text (HU + EN, ~17k chars
   from /privacy, /about, /, /deals, a product page, /account) at 100 px: size-adjust = Manrope advance width /
   Arial advance width at that weight; the overrides are Manrope's ascent/descent divided by size-adjust (they
   apply after the scaling). Liberation Sans is Arial metric-compatible (Linux). One face per weight band, so the
   bold text (most of the UI) matches too. */
@font-face { font-family: 'Manrope Fallback'; font-weight: 100 549; src: local('Arial'), local('ArialMT'), local('Liberation Sans'), local('LiberationSans'); size-adjust: 103.03%; ascent-override: 103.46%; descent-override: 29.12%; line-gap-override: 0%; }
@font-face { font-family: 'Manrope Fallback'; font-weight: 550 649; src: local('Arial'), local('ArialMT'), local('Liberation Sans'), local('LiberationSans'); size-adjust: 104.79%; ascent-override: 101.73%; descent-override: 28.63%; line-gap-override: 0%; }
@font-face { font-family: 'Manrope Fallback'; font-weight: 650 749; src: local('Arial Bold'), local('Arial-BoldMT'), local('Liberation Sans Bold'), local('LiberationSans-Bold'); size-adjust: 100.12%; ascent-override: 106.47%; descent-override: 29.96%; line-gap-override: 0%; }
@font-face { font-family: 'Manrope Fallback'; font-weight: 750 1000; src: local('Arial Bold'), local('Arial-BoldMT'), local('Liberation Sans Bold'), local('LiberationSans-Bold'); size-adjust: 101.58%; ascent-override: 104.94%; descent-override: 29.53%; line-gap-override: 0%; }
/* Android: the same trick on Roboto, the system face every Android has (story W2-MOTION). Measured in Chromium
   (scratchpad script, 2026-09-26): the real Manrope (Google Fonts v20 variable, latin + latin-ext) against Roboto
   (Google Fonts v51 variable = Android's Roboto design, at the static weights Android ships as Regular 400 /
   Medium 500 / Bold 700), both with the body's 'tnum'/'cv11' features, over the app's own rendered text (HU + EN,
   36 375 chars from /privacy, /about, /, /deals, a product page, /account) at 100 px. size-adjust = Manrope total
   advance ÷ Roboto total advance; ascent/descent = Manrope's 1.066 / 0.300 em ÷ size-adjust (applied after the
   scaling; Manrope's line box measured 137 px at 100 px = 1.366 em, confirming 2132 + 600 / 2000 upm). Band →
   Manrope weight rendered vs Roboto face: 100–549 → 500 vs Regular (104.95%); 550–649 → 600 vs Medium (105.84%);
   650–749 → 700 vs Bold (106.79%); 750–1000 → 800 vs Bold (108.57%). Method check: the same script on Liberation
   Sans gives 103.81% / 100.71% for the first/third band against W2-TOKENS' 103.03% / 100.12% (< 1% apart — a
   different text sample). The face's weight range covers the requested weight, so no synthetic bold is added. */
@font-face { font-family: 'Manrope Fallback Android'; font-weight: 100 549; src: local('Roboto'), local('Roboto-Regular'), local('Roboto Regular'); size-adjust: 104.95%; ascent-override: 101.58%; descent-override: 28.59%; line-gap-override: 0%; }
@font-face { font-family: 'Manrope Fallback Android'; font-weight: 550 649; src: local('Roboto Medium'), local('Roboto-Medium'); size-adjust: 105.84%; ascent-override: 100.71%; descent-override: 28.34%; line-gap-override: 0%; }
@font-face { font-family: 'Manrope Fallback Android'; font-weight: 650 749; src: local('Roboto Bold'), local('Roboto-Bold'); size-adjust: 106.79%; ascent-override: 99.83%; descent-override: 28.09%; line-gap-override: 0%; }
@font-face { font-family: 'Manrope Fallback Android'; font-weight: 750 1000; src: local('Roboto Bold'), local('Roboto-Bold'); size-adjust: 108.57%; ascent-override: 98.19%; descent-override: 27.63%; line-gap-override: 0%; }
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ───────────────────────── base ───────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: radial-gradient(1200px 600px at 80% -10%, rgba(242, 192, 75, 0.06), transparent 60%), radial-gradient(900px 500px at -10% 110%, rgba(110, 181, 255, 0.05), transparent 60%), var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--fs-md);
  line-height: var(--lh-normal);
  font-feature-settings: 'tnum' 1, 'cv11' 1;
  min-height: 100dvh;
}
body.no-scroll { overflow: hidden; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
h1, h2, h3, h4 { margin: 0; font-weight: 700; letter-spacing: -0.01em; }
p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
code { font-family: var(--mono); font-size: 0.85em; color: var(--text-2); }
/* W2-TOKENS: fields and the search box ease their focus border/ring in instead of snapping. */
input, select, textarea, .searchbox { transition: border-color var(--dur-fast) var(--ease-standard), box-shadow var(--dur-fast) var(--ease-standard), background-color var(--dur-fast) var(--ease-standard); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

/* Global keyboard focus ring (story S7 / U1): every interactive element gets a high-contrast ring on
   :focus-visible only, so a mouse click never shows it. --gold on the darkest and lightest surfaces in
   use (--bg 0.004 luminance, --bg-3 0.0103, --bg-4 0.0155) contrasts 9.5–11.5:1, comfortably above 3:1.
   Text-like inputs are excluded on purpose: they already swap outline: 0 for a gold box-shadow ring
   elsewhere in this file, which is its own visible indicator. */
a:focus-visible,
button:focus-visible,
[role='tab']:focus-visible,
[role='button']:focus-visible,
select:focus-visible,
summary:focus-visible,
input[type='checkbox']:focus-visible,
input[type='radio']:focus-visible,
.setchip:focus-visible,
.bottomnav-item:focus-visible,
.sidenav-item:focus-visible,
.iconbtn:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}
.muted { color: var(--muted); }
.small { font-size: var(--fs-sm); }
.warn { color: var(--amber); }
.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* W2-TOKENS: prices and counts never jitter on refresh — tabular figures on every list/table/card surface. */
.price, .pcard, .ptable, .mtable, .pro-table, .offer, .offers, .prerow, .wrow, .events, .users-list, .users-kpis, .kv dd, .facts dd,
.group-count, .setchip-meta, .chip, .badge, .btn-filter .count, .lastupdate, .dataage, .steps, .plan-price, .verdict-pct { font-variant-numeric: tabular-nums; }
.eyebrow { font-size: var(--fs-xs); letter-spacing: 0.12em; text-transform: uppercase; color: var(--gold); font-weight: 700; }
.h2 { font-size: var(--fs-md); font-weight: 700; color: var(--text-2); margin-bottom: 12px; letter-spacing: 0.01em; }

/* ───────────────────────── shell ───────────────────────── */
.shell { display: grid; grid-template-columns: minmax(0, 1fr); min-height: 100dvh; }
.sidebar { display: none; }
/* W2-POLISH: top padding is `--topstrip-h` (0 from 1024px, where the strip doesn't exist) rather than a bare 0 — see
   `.topstrip`'s own note below for why the strip is `position: fixed` and never a grid row. */
.main { padding: var(--topstrip-h) var(--gutter) calc(var(--nav-h) + 24px); max-width: 1280px; width: 100%; margin: 0 auto; min-width: 0; }
.view { display: flex; flex-direction: column; gap: var(--sp-4); padding-top: var(--sp-3); min-width: 0; }

/* Skip link (story UX-SHELL): the very first focusable element, invisible until it has keyboard focus. */
.skip-link {
  position: absolute; top: -60px; left: 12px; z-index: 100;
  padding: var(--sp-3) var(--sp-4); border-radius: 10px; background: var(--gold); color: #17120a; font-weight: 800;
  transition: top var(--dur-fast) var(--ease-standard);
}
.skip-link:focus-visible { top: 12px; }

/* Mobile/tablet top strip (< 1024 px, story UX-SHELL): brand + language switch on every route, since the sidebar
   that normally carries both is hidden at this width. Height reserved via --topstrip-h so .topbar (home.tsx's own
   sticky header) can stick right below it instead of underneath it. */
.topstrip { display: none; }
.topstrip-brand { display: flex; align-items: center; gap: var(--sp-2); }
.topstrip-name { font-weight: 800; font-size: var(--fs-md); }

/* W2-TOKENS: literal spacing kept on .brand, .sidenav-item and the desktop .sidebar — the boot skeleton (.boot-side) mirrors them px for px. */
.brand { display: flex; align-items: center; gap: 10px; padding: 6px 8px; }
.brand-mark { width: 38px; height: 38px; flex: none; display: inline-block; }
.topstrip-brand .brand-mark { width: 32px; height: 32px; }
.brand-text { font-weight: 800; font-size: 18px; display: flex; flex-direction: column; line-height: 1.1; } /* literal kept: the sidebar brand block is mirrored by the boot skeleton (.boot-brand) */
.brand-text small { font-weight: 600; font-size: var(--fs-xs); color: var(--muted); letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap; }

.bottomnav {
  position: fixed; left: 0; right: 0; bottom: 0; height: calc(var(--nav-h) + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  display: flex;
  background: rgba(16, 19, 26, 0.92); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--line); z-index: 30;
}
.bottomnav-item { flex: 1 1 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; font-size: var(--fs-xs); font-weight: 700; color: var(--muted); min-height: 48px; }
.bottomnav-item.on { color: var(--gold-2); }
.bottomnav-item.on svg { filter: drop-shadow(0 0 6px rgba(242, 192, 75, 0.5)); }

.sidenav { display: flex; flex-direction: column; gap: var(--sp-1); margin-top: 18px; }
.sidenav-item { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: var(--r-sm); font-weight: 700; color: var(--text-2); min-width: 0; }
/* UX-ACCOUNT-2: a long e-mail-derived name (no display name set) could overflow the sidebar's fixed width — the
   label shrinks and ellipses; the Pro badge (margin-left: auto, below) always stays visible. */
.sidenav-item > span:not(.probadge) { min-width: 0; flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidenav-item:hover { background: var(--bg-3); color: var(--text); }
.sidenav-item.on { background: linear-gradient(90deg, rgba(242, 192, 75, 0.14), transparent); color: var(--gold-2); box-shadow: inset 2px 0 0 var(--gold); }
.side-status { margin-top: auto; padding: var(--sp-4) var(--sp-3); border-top: 1px solid var(--line); font-size: var(--fs-sm); display: flex; flex-direction: column; gap: var(--sp-2); color: var(--text-2); }
/* W2-POLISH (CLS): a fixed line-box height so a row reads the same whether it holds real text or its loading
   skeleton line — the sidebar footer below never moves when `/api/summary` resolves. */
.side-status-row { display: flex; align-items: center; gap: var(--sp-2); min-height: calc(var(--fs-sm) * var(--lh-normal)); }
.side-status-row .skeleton-line { width: 100%; height: 10px; }
.side-status-row.scanning { color: var(--blue); }
.side-foot { padding: var(--sp-2) var(--sp-3) var(--sp-4); }
.storebadge { display: inline-flex; align-items: center; gap: var(--sp-1); vertical-align: middle; color: var(--muted); }
.storebadge-physical { color: var(--gold-2); }
.storebadge-text { font-size: var(--fs-sm); font-weight: 600; }
.offer-retailer-wrap { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); min-width: 0; }
.group { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: 6px; }
.group + .group { margin-top: 22px; padding-top: var(--sp-4); border-top: 1px solid var(--line); }
.group-head { display: flex; align-items: baseline; gap: var(--sp-2); font-size: var(--fs-md); font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-2); }
.group-count { font-size: var(--fs-sm); font-weight: 600; color: var(--muted); text-transform: none; letter-spacing: 0; }
.group-instant .group-label { color: var(--gold-2); }
.group-good .group-label { color: var(--green, #6fdc8c); }
.group-expensive .group-label { color: var(--red, #ff7b7b); }
.group-row td { padding: var(--sp-4) var(--sp-2) var(--sp-2); font-size: var(--fs-sm); font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-2); border-bottom: 1px solid var(--line); }
.group-row .group-count { margin-left: 8px; }
/* UX-HOME finding 1: the collapsed "Not available" segment's own toggle — same visual language as .oldersets-toggle
   (a caret that rotates open), always a 44px hit area on phones via the tap-targets media query below. */
.group-unavailable { margin-top: 6px; }
.group-toggle { display: inline-flex; align-items: center; gap: var(--sp-2); min-height: 44px; padding: var(--sp-2) 0; font-size: var(--fs-sm); font-weight: 700; color: var(--muted); }
.group-toggle:hover, .group-toggle.on { color: var(--gold-2); }
.group-toggle-caret { display: inline-block; transition: transform var(--dur-fast) var(--ease-standard); }
.group-toggle-caret.open { transform: rotate(90deg); }
.group-row .group-toggle { padding: 0; }
.langswitch { display: inline-flex; gap: 2px; padding: 2px; background: var(--bg-3); border: 1px solid var(--line); border-radius: 10px; }
.langswitch button { padding: var(--sp-1) var(--sp-2); border-radius: 8px; font-size: var(--fs-sm); font-weight: 800; letter-spacing: 0.04em; color: var(--muted); }
.langswitch button.on { background: var(--bg-4); color: var(--gold-2); }
.langswitch button:hover { color: var(--text); }
.langswitch-compact button { padding: var(--sp-1) var(--sp-2); font-size: var(--fs-xs); }
.viewhead-row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); }
.dot-ok { background: var(--green); box-shadow: 0 0 8px rgba(53, 211, 143, 0.6); }
.dot-warn { background: var(--amber); }
.dot-bad { background: var(--red); }

/* ───────────────────────── top bar ───────────────────────── */
.topbar { position: sticky; top: var(--topstrip-h); z-index: 20; display: flex; gap: var(--sp-2); align-items: center; padding: var(--sp-2) 0 var(--sp-2); margin: 0 calc(var(--gutter) * -1); padding-left: var(--gutter); padding-right: var(--gutter); background: linear-gradient(180deg, rgba(11, 13, 18, 0.98) 70%, rgba(11, 13, 18, 0)); }
.searchbox { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--sp-2); height: 44px; padding: 0 var(--sp-3); background: var(--bg-3); border: 1px solid var(--line); border-radius: 12px; color: var(--muted); }
.searchbox:focus-within { border-color: var(--gold); box-shadow: 0 0 0 3px rgba(242, 192, 75, 0.15); }
.searchbox input { flex: 1; background: none; border: 0; outline: 0; color: var(--text); font: inherit; min-width: 0; }
.searchbox input::placeholder { color: var(--muted); }
.searchbox input::-webkit-search-cancel-button { display: none; }
.iconbtn { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 10px; color: var(--text-2); }
.iconbtn:hover { background: var(--bg-4); color: var(--text); }
.iconbtn.on { background: var(--bg-4); color: var(--gold-2); }
/* WATCH-BELL (owner 2026-09-26): the "on" bell also carries a short "Watching" label, so it grows past the square. */
.watch-bell { gap: var(--sp-2); }
.watch-bell.on { width: auto; min-width: 40px; padding: 0 var(--sp-3); }
.watch-bell-text { font-size: var(--fs-sm); font-weight: 700; }
.best-cta { display: flex; align-items: center; gap: var(--sp-2); }
.viewtoggle { display: none; gap: 2px; padding: 2px; background: var(--bg-3); border: 1px solid var(--line); border-radius: 12px; }
/* min-height: a column flex container (e.g. the Users drawer when its content overflows) must never squeeze a button below the 44 px target. */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2); height: 44px; min-height: 44px; padding: 0 var(--sp-4); border-radius: 12px; font-weight: 700; white-space: nowrap; transition: transform var(--dur-fast) var(--ease-standard), background var(--dur-fast) var(--ease-standard), border-color var(--dur-fast) var(--ease-standard), color var(--dur-fast) var(--ease-standard), box-shadow var(--dur-base) var(--ease-standard); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.6; cursor: default; }
.btn-primary { background: linear-gradient(180deg, #ffd66b, #f0b52f); color: #17120a; box-shadow: 0 6px 18px rgba(242, 192, 75, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.4); }
/* W2-TOKENS: hover and keyboard focus lift the primary button 1 px and light its gold glow; pressing still pushes it
   down (the :active rule after it), disabled buttons never react. */
.btn-primary:not(:disabled, [aria-disabled='true']):hover,
.btn-primary:not(:disabled, [aria-disabled='true']):focus-visible { background: linear-gradient(180deg, #ffde86, #f5bd3c); box-shadow: var(--shadow-glow-gold), inset 0 1px 0 rgba(255, 255, 255, 0.4); transform: translateY(-1px); }
.btn-primary:not(:disabled, [aria-disabled='true']):active { transform: translateY(1px); }
.btn-ghost { background: var(--bg-3); border: 1px solid var(--line); color: var(--text-2); }
.btn-ghost:hover { background: var(--bg-4); border-color: var(--line-2); color: var(--text); }
.btn-filter { position: relative; padding: 0 var(--sp-3); }
.btn-filter .btn-label { display: none; }
.btn-filter .count { position: absolute; top: -5px; right: -5px; min-width: 18px; height: 18px; padding: 0 var(--sp-1); border-radius: 9px; background: var(--gold); color: #17120a; font-size: var(--fs-xs); display: grid; place-items: center; }
.linkbtn { color: var(--gold-2); font-weight: 700; padding: var(--sp-2) 0; }
.linkbtn:hover { text-decoration: underline; }

.um-toggle { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: 8px 0 12px; }

/* ───────────────────────── users screen (story U-ADMIN) ───────────────────────── */
.btn-sm { height: 34px; padding: 0 var(--sp-3); font-size: var(--fs-sm); border-radius: 10px; }
.when { white-space: nowrap; }
.check { display: inline-flex; align-items: center; gap: var(--sp-2); cursor: pointer; }
.check input { width: 18px; height: 18px; accent-color: var(--gold); }
.users { display: flex; flex-direction: column; gap: var(--sp-4); }
.users-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.users-head .h2 { margin: 0; font-size: var(--fs-lg); color: var(--text); }
.users-msg { font-size: var(--fs-sm); font-weight: 600; }
.users-msg-ok { color: var(--green); }
.users-msg-err { color: var(--red); }
/* KPI strip: every figure is a filter button. */
.users-kpis { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); }
.users-kpi { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-height: 76px; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm); background: var(--bg-3); border: 1px solid var(--line); text-align: left; transition: border-color var(--dur-fast) var(--ease-standard), background var(--dur-fast) var(--ease-standard); min-width: 0; }
.users-kpi:last-child:nth-child(odd) { grid-column: 1 / -1; }
.users-kpi:hover { border-color: var(--line-2); }
.users-kpi.on { background: linear-gradient(180deg, rgba(242, 192, 75, 0.16), rgba(242, 192, 75, 0.05)); border-color: rgba(242, 192, 75, 0.55); }
.users-kpi-value { font-size: var(--fs-3xl); font-weight: 800; line-height: var(--lh-tight); font-variant-numeric: tabular-nums; }
.users-kpi.on .users-kpi-value { color: var(--gold-2); }
.users-kpi-label { font-size: var(--fs-sm); font-weight: 700; color: var(--text-2); }
.users-kpi-sub { font-size: var(--fs-xs); color: var(--muted); }
/* Toolbar: search + sort, then the filter chips (one scrollable row on phones). */
.users-toolbar { display: flex; gap: var(--sp-2); align-items: center; }
.users-search { flex: 1 1 auto; }
.users-sort { flex: 0 0 auto; height: 44px; max-width: 46%; background: var(--bg-3); color: var(--text); border: 1px solid var(--line); border-radius: 12px; padding: 0 var(--sp-2); font: inherit; font-size: var(--fs-sm); }
.users-chips { display: flex; gap: var(--sp-2); overflow-x: auto; margin: -2px calc(var(--gutter) * -1) 0; padding: 2px var(--gutter) var(--sp-1); scrollbar-width: none; }
.users-chips::-webkit-scrollbar { display: none; }
.users-chips .chip { flex: 0 0 auto; min-height: 44px; }
.users-chip-n { font-size: var(--fs-xs); font-weight: 700; color: var(--muted); font-variant-numeric: tabular-nums; }
.users-chips .chip-on .users-chip-n { color: var(--gold-2); }
/* Invite form */
.users-invite { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3); background: var(--bg-3); border: 1px solid var(--line); border-radius: var(--r-sm); }
.users-invite-title { font-size: var(--fs-md); font-weight: 700; }
.users-invite-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-2); }
.users-invite-actions { display: flex; gap: var(--sp-2); justify-content: flex-end; }
.users-field { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.users-field > span { font-size: var(--fs-sm); font-weight: 600; color: var(--text-2); }
.users-field input, .users-field select { height: 44px; width: 100%; min-width: 0; padding: 0 var(--sp-3); background: var(--bg-2); color: var(--text); border: 1px solid var(--line); border-radius: 10px; font: inherit; font-size: var(--fs-md); }
.users-field input:focus { outline: 0; border-color: var(--gold); box-shadow: 0 0 0 3px rgba(242, 192, 75, 0.15); }
/* The list: one button per person, the same grid on every row so columns line up. */
.users-list { display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden; }
.users-list li + li { border-top: 1px solid var(--line); }
.users-row { display: grid; grid-template-columns: 40px minmax(0, 1fr) 20px; grid-template-areas: 'av main bell' 'av meta bell'; column-gap: var(--sp-3); row-gap: var(--sp-1); align-items: center; width: 100%; min-height: 72px; padding: var(--sp-3); text-align: left; background: var(--bg-2); transition: background var(--dur-fast) var(--ease-standard); }
.users-row:hover { background: var(--bg-3); }
.users-row.on { background: var(--bg-4); }
.users-row:focus-visible { outline-offset: -2px; }
.users-avatar { grid-area: av; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; font-size: var(--fs-md); font-weight: 800; letter-spacing: 0.02em; background: hsl(var(--av-h, 40) 42% 22%); color: hsl(var(--av-h, 40) 85% 80%); border: 1px solid hsl(var(--av-h, 40) 40% 34%); flex: none; }
.users-avatar-lg { width: 52px; height: 52px; font-size: var(--fs-lg); }
.users-avatar-pending { border-style: dashed; opacity: 0.85; }
.users-main { grid-area: main; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.users-nameline { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-2); min-width: 0; }
.users-name { font-weight: 800; font-size: var(--fs-md); color: var(--text); overflow-wrap: anywhere; }
.users-name-none { font-weight: 600; font-style: italic; color: var(--muted); }
.users-email { font-size: var(--fs-sm); color: var(--muted); overflow-wrap: anywhere; }
.users-badge-sub { font-weight: 600; opacity: 0.85; }
.users-meta { grid-area: meta; display: flex; flex-wrap: wrap; gap: 2px var(--sp-3); font-size: var(--fs-sm); color: var(--text-2); }
.users-bell { grid-area: bell; display: grid; place-items: center; color: var(--muted); }
.users-bell.on { color: var(--gold-2); }
/* Detail drawer: bottom sheet on phones, right-side panel from 1024 px. */
.users-drawer-backdrop { position: fixed; inset: 0; z-index: 50; background: rgba(0, 0, 0, 0.55); display: flex; align-items: flex-end; justify-content: center; animation: fade var(--dur-base) var(--ease-standard); }
.users-drawer { width: 100%; max-height: 90dvh; display: flex; flex-direction: column; background: var(--bg-2); border: 1px solid var(--line-2); border-radius: 20px 20px 0 0; animation: rise var(--dur-slow) var(--ease-standard); padding-bottom: env(safe-area-inset-bottom); }
.users-drawer-head { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--sp-3); align-items: start; padding: var(--sp-2) var(--sp-2) var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--line); }
.users-drawer-head .users-avatar { grid-area: auto; }
.users-drawer-id { display: flex; flex-direction: column; gap: 3px; min-width: 0; padding-top: 2px; }
.users-drawer-name { font-size: var(--fs-lg); font-weight: 800; overflow-wrap: anywhere; }
.users-drawer-badges { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-2); margin-top: 4px; }
.users-drawer-close { width: 44px; height: 44px; }
.users-drawer-body { overflow: auto; padding: var(--sp-4) var(--sp-4) var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-4); }
.users-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2) var(--sp-4); margin: 0; }
.users-facts dt { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.users-facts dd { margin: 2px 0 0; font-size: var(--fs-sm); color: var(--text); }
.users-facts-wrap { overflow-wrap: anywhere; }
.users-sec { display: flex; flex-direction: column; gap: var(--sp-2); padding-top: var(--sp-4); border-top: 1px solid var(--line); }
.users-sec-title { font-size: var(--fs-sm); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.users-seg { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 2px; padding: 3px; background: var(--bg-3); border: 1px solid var(--line); border-radius: 12px; }
.users-seg-4 { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.users-seg-btn { min-height: 44px; padding: 0 var(--sp-2); border-radius: 9px; font-size: var(--fs-sm); font-weight: 700; color: var(--text-2); }
.users-seg-btn:hover:not(:disabled) { color: var(--text); }
.users-seg-btn.on { background: var(--bg-4); color: var(--gold-2); box-shadow: inset 0 0 0 1px rgba(242, 192, 75, 0.45); }
.users-seg-btn:disabled { cursor: default; opacity: 0.6; }
.users-seg-btn.on:disabled { opacity: 0.85; }
.users-pro-state { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-2); font-size: var(--fs-md); }
.users-pro-gift { display: flex; flex-direction: column; gap: var(--sp-2); }
.users-pro-form { display: flex; flex-direction: column; gap: var(--sp-2); }
.users-pro-form .btn { align-self: flex-start; }
.users-btn-44 { height: 44px; }
.users-switch { display: flex; align-items: center; gap: var(--sp-2); min-height: 44px; cursor: pointer; font-weight: 600; }
.users-switch input { width: 20px; height: 20px; accent-color: var(--gold); }
.users-danger-btn { align-self: flex-start; background: rgba(240, 97, 107, 0.12); border: 1px solid rgba(240, 97, 107, 0.6); color: #ff9aa2; }
.users-danger-btn:hover:not(:disabled) { background: rgba(240, 97, 107, 0.2); }
@media (min-width: 640px) {
  .users-kpis { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }
  .users-kpi:last-child:nth-child(odd) { grid-column: auto; }
  .users-invite-grid { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr); }
  .users-chips { flex-wrap: wrap; overflow: visible; margin: 0; padding: 0; }
  .users-seg-4 { grid-auto-flow: column; grid-template-columns: none; }
  .users-sort { max-width: none; }
}
@media (min-width: 768px) {
  .users-row { grid-template-columns: 40px minmax(0, 1fr) 150px 20px; grid-template-areas: 'av main meta bell'; min-height: 68px; }
  .users-meta { flex-direction: column; align-items: flex-start; gap: 2px; }
}
@media (min-width: 1024px) {
  .users-row { grid-template-columns: 44px minmax(0, 1fr) 190px 24px; padding: var(--sp-3) var(--sp-4); }
  .users-drawer-backdrop { justify-content: flex-end; align-items: stretch; }
  .users-drawer { width: min(480px, 100%); max-height: none; height: 100dvh; border-radius: 0; border-width: 0 0 0 1px; animation: slidein var(--dur-slow) var(--ease-standard); }
  .users-drawer-handle { display: none; }
  .users-drawer-head { padding: var(--sp-4) var(--sp-3) var(--sp-4) var(--sp-5); }
  .users-drawer-body { padding: var(--sp-4) var(--sp-5) var(--sp-6); }
}
@keyframes slidein { from { transform: translateX(24px); opacity: 0; } to { transform: none; opacity: 1; } }

/* ───────────────────────── last update line ───────────────────────── */
/* min-height: 1lh — the loading placeholder (an 11px bar, no text) must reserve the real text line, or everything below
   drops ~8-11px when /api/summary lands after the products (measured on the release, 2026-09-27). */
.lastupdate { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--muted); min-width: 0; min-height: 1lh; }
.lastupdate .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); flex: none; }
.lastupdate.stale .dot { background: var(--amber); }
.lastupdate.running .dot { background: var(--gold); animation: pulse 1.2s ease-in-out infinite; }
.lastupdate span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

/* ───────────────────────── set chips ───────────────────────── */
.setchips { display: flex; gap: var(--sp-2); overflow-x: auto; padding: 2px 0 var(--sp-2); margin: 0 calc(var(--gutter) * -1); padding-left: var(--gutter); padding-right: var(--gutter); scrollbar-width: none; -webkit-overflow-scrolling: touch; scroll-snap-type: x proximity; }
.setchips::-webkit-scrollbar { display: none; }
.setchip { flex: 0 0 auto; scroll-snap-align: start; display: flex; flex-direction: column; align-items: flex-start; gap: 2px; padding: var(--sp-2) var(--sp-4); min-height: 52px; border-radius: 12px; background: var(--bg-3); border: 1px solid var(--line); text-align: left; transition: border-color var(--dur-fast) var(--ease-standard), background var(--dur-fast) var(--ease-standard), box-shadow var(--dur-base) var(--ease-standard); }
.setchip:hover { border-color: var(--line-2); }
.setchip.on { background: linear-gradient(180deg, rgba(242, 192, 75, 0.16), rgba(242, 192, 75, 0.06)); border-color: rgba(242, 192, 75, 0.55); box-shadow: var(--shadow-glow-gold); }
.setchip-name { font-weight: 800; font-size: var(--fs-md); }
.setchip.on .setchip-name { color: var(--gold-2); }
.setchip-meta { font-size: var(--fs-xs); color: var(--muted); }
.setchip-up { border-style: dashed; }
.oldersets { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
/* The loading placeholder for the collapsed "Older sets" toggle (same 44px as the toggle's min-height), reserved
   while back-catalog sets are switched on so the real row doesn't push the results down. If every back-catalog set
   is switched off again, remove this and its two uses (home.tsx SetChips, index.html boot markup). */
.oldersets-skel { height: 44px; }
.oldersets-toggle { align-self: flex-start; display: inline-flex; align-items: center; gap: var(--sp-2); min-height: 44px; padding: var(--sp-2) 0; font-size: var(--fs-sm); font-weight: 700; color: var(--muted); }
.oldersets-toggle:hover, .oldersets-toggle.on { color: var(--gold-2); }
.oldersets-caret { display: inline-block; transition: transform var(--dur-fast) var(--ease-standard); }
.oldersets-caret.open { transform: rotate(90deg); }
.oldersets-count { font-weight: 500; }
.cardmarket { margin-top: 12px; display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-2); }
.cardmarket-note { font-size: var(--fs-sm); color: var(--muted); }
/* CM-FALLBACK: the Cardmarket Price Guide line under the offers, and its admin section (System → Kereskedők) */
.cm-price { margin-top: 8px; }
.cm-line { margin: 0; font-size: var(--fs-md); line-height: 1.6; overflow-wrap: anywhere; }
.cm-link { font-weight: 700; display: inline-flex; align-items: center; gap: 3px; }
.cm-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.cm-runs { display: flex; flex-direction: column; gap: var(--sp-1); margin: 10px 0; font-size: var(--fs-sm); }
.cm-runs li { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-2); }
.cm-err { overflow-wrap: anywhere; }
.cm-url { font-size: var(--fs-sm); color: var(--muted); overflow-wrap: anywhere; }
/* phone: the candidate picker gets its own full-width row, so long Cardmarket names stay readable */
.cm-actions { flex-wrap: wrap; }
.cm-actions .select { flex: 1 1 100%; }
/* UX-HOME finding 6: matches the set-chips row's real rendered height (measured ~64–68px with the chip's two text
   lines) so the skeleton→real swap doesn't push the results below it down. */
.skeleton-row { height: 67.69px; }
/* W2-POLISH (CLS): from 1024px the chips wrap (styles.css `.setchips { flex-wrap: wrap }`) onto two rows instead of
   scrolling on one — the skeleton has to reserve that taller shape too, or the products below jump up when the real
   chips arrive and wrap. Measured ~130px for the wrapped two-row shape at desktop widths. */
@media (min-width: 1024px) {
  .skeleton-row { height: 133.38px; }
}
/* From the wide frame (1680px, content 1520px) today's chips fit on one row again. Both heights are measured for the
   current catalog (2026-09-27: 7 chips); more sets can wrap differently — an estimate, re-measure when sets are added. */
@media (min-width: 1680px) {
  .skeleton-row { height: 67.69px; }
}

.activefilters { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.chip { display: inline-flex; align-items: center; gap: var(--sp-2); min-height: 36px; padding: var(--sp-2) var(--sp-3); border-radius: 999px; background: var(--bg-3); border: 1px solid var(--line); font-size: var(--fs-sm); font-weight: 600; color: var(--text-2); }
.chip-on { background: rgba(242, 192, 75, 0.14); border-color: rgba(242, 192, 75, 0.5); color: var(--gold-2); box-shadow: inset 0 0 0 1px rgba(242, 192, 75, 0.3); }
button.chip:not(.chip-on):hover, a.chip:not(.chip-on):hover { border-color: var(--line-2); color: var(--text); }
.chip, .langswitch button, .users-seg-btn, .subnav a, .iconbtn, .sidenav-item, .linkbtn { transition: background-color var(--dur-fast) var(--ease-standard), color var(--dur-fast) var(--ease-standard), border-color var(--dur-fast) var(--ease-standard), box-shadow var(--dur-fast) var(--ease-standard); }
.chip-removable button { display: inline-flex; padding: 2px; border-radius: 50%; color: inherit; }
.chip-removable button:hover { background: rgba(255, 255, 255, 0.1); }

/* U2 / owner-proxy ruling (night 2026-09-25): the Ajánlatok segment row at the top of /deals and /preorders —
   real links, not local state, so deep links and the back button work. Mobile-only: the desktop sidebar already
   lists both as separate rows, so repeating them here would be chrome for its own sake. */
.segmentrow { display: flex; gap: var(--sp-2); margin-bottom: 2px; }
.segmentrow .chip { min-height: 44px; }

/* ───────────────────────── badges ───────────────────────── */
.badge { display: inline-flex; align-items: center; gap: var(--sp-1); height: 24px; padding: 0 var(--sp-2); border-radius: 999px; font-size: 12px; /* kept: sized for the fixed 24 px pill */ font-weight: 700; letter-spacing: 0.01em; white-space: nowrap; border: 1px solid transparent; }
.badge-sm { height: 21px; padding: 0 var(--sp-2); font-size: var(--fs-xs); }
.badge-pct { font-weight: 600; opacity: 0.85; font-variant-numeric: tabular-nums; }
/* Story S7 / U8: border alphas raised so every badge outline reaches >= 3:1 against every card surface it
   sits on (bg / bg-2 / bg-3 / bg-4, computed worst case 3.39:1 for badge-red); text colours are unchanged. */
.badge-green { background: rgba(53, 211, 143, 0.14); color: #7fe7b6; border-color: rgba(53, 211, 143, 0.55); }
.badge-lime { background: rgba(163, 230, 53, 0.12); color: #c7f56b; border-color: rgba(163, 230, 53, 0.5); }
.badge-amber { background: rgba(251, 191, 36, 0.14); color: #ffd36b; border-color: rgba(251, 191, 36, 0.5); }
.badge-red { background: rgba(240, 97, 107, 0.14); color: #ff9aa2; border-color: rgba(240, 97, 107, 0.75); }
.badge-crimson { background: rgba(179, 32, 46, 0.35); color: #ffb3b9; border-color: rgba(255, 90, 105, 0.75); }
.badge-grey { background: rgba(127, 136, 156, 0.14); color: var(--text-2); border-color: rgba(127, 136, 156, 0.8); }
.badge-blue { background: rgba(110, 181, 255, 0.14); color: #a9d3ff; border-color: rgba(110, 181, 255, 0.6); }
.badge-violet { background: rgba(181, 156, 255, 0.14); color: #cdbdff; border-color: rgba(181, 156, 255, 0.6); }
.badge-gold { background: rgba(245, 197, 66, 0.18); color: var(--gold); border-color: rgba(245, 197, 66, 0.55); font-weight: 800; letter-spacing: 0.02em; }
.pcard.pcard-instant { border-color: rgba(245, 197, 66, 0.55); box-shadow: var(--shadow-glow-gold); } /* .pcard. prefix: the later .pcard resting shadow used to win and hid the glow */
.pcard-instant:hover { border-color: var(--gold); }
.pcard-good { border-color: rgba(53, 211, 143, 0.4); }
.prow-instant td:first-child { box-shadow: inset 3px 0 0 var(--gold); }
.prow-good td:first-child { box-shadow: inset 3px 0 0 var(--green); }
.prow-badges { display: inline-flex; gap: var(--sp-2); flex-wrap: wrap; }
.badge-foil { position: relative; color: #17120a; background: var(--foil); background-size: 200% 200%; animation: foil 6s ease-in-out infinite; border-color: rgba(255, 255, 255, 0.35); }
@keyframes foil { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }

.fresh { font-size: var(--fs-sm); color: var(--muted); }
.price { font-variant-numeric: tabular-nums; font-weight: 800; letter-spacing: -0.02em; white-space: nowrap; display: inline-flex; align-items: baseline; gap: var(--sp-2); }
.price-sm { font-size: var(--fs-md); }
.price-md { font-size: var(--fs-lg); }
.price-lg { font-size: var(--fs-2xl); }
.price-xl { font-size: var(--fs-display); line-height: 1; }
.price-orig { font-size: 0.7em; font-weight: 600; color: var(--muted); }

/* ───────────────────────── product cards ───────────────────────── */
.grid { display: grid; grid-template-columns: 1fr; gap: var(--sp-2); }
/* UX-HOME finding 7: a subtle shadow at rest (so the card reads as a raised surface even before any interaction),
   a stronger lift on hover *and* keyboard focus (:focus-within — the card itself is never focusable, its title
   link is), and the artwork nudges forward with it. The fade-in on arrival (`pcard-fade`, defined further down
   next to the other skeleton keyframes) and this shadow/lift both respect the app-wide prefers-reduced-motion
   rule (styles.css:34), which already zeroes every transition/animation. */
.pcard { position: relative; display: grid; grid-template-columns: 96px 1fr; gap: var(--sp-3); padding: var(--sp-3); background: linear-gradient(180deg, var(--bg-3), var(--bg-2)); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow-sm); transition: transform var(--dur-base) var(--ease-standard), border-color var(--dur-fast) var(--ease-standard), box-shadow var(--dur-base) var(--ease-standard); animation: pcard-fade var(--dur-base) var(--ease-standard); }
.pcard::before { content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; background: linear-gradient(135deg, rgba(255, 255, 255, 0.04), transparent 40%); }
.pcard:hover, .pcard:focus-within { transform: translateY(-2px); border-color: var(--line-2); box-shadow: var(--shadow-md); }
/* An instant-buy card keeps its gold glow (and gold edge) while lifted, instead of trading it for the plain shadow. */
.pcard-instant:hover, .pcard-instant:focus-within { border-color: var(--gold); box-shadow: var(--shadow-glow-gold), var(--shadow-md); }
.pcard:hover .art img, .pcard:focus-within .art img { transform: scale(1.03); }
.pcard-quiet { opacity: 0.85; }
.art { border-radius: var(--r-sm); background: radial-gradient(120% 100% at 30% 20%, #2a3042, #131721); border: 1px solid var(--line); display: grid; place-items: center; overflow: hidden; aspect-ratio: 1 / 1; }
.art img { width: 100%; height: 100%; object-fit: contain; padding: var(--sp-2); background: transparent; transition: transform var(--dur-base) var(--ease-standard); }
/* With a photo: the plate (C3). `multiply` turns the photo's white background into the plate colour (the 265 catalog photos
   carry a baked-in white, no transparency); `isolation` keeps the blend inside the plate. A tile without a photo keeps the
   dark .art stage above, so the no-artwork initials never light up. */
.art-has-img {
  isolation: isolate; border-color: transparent;
  background: linear-gradient(165deg, var(--plate-hi) 0%, var(--plate-lo) 100%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.5), inset 0 -14px 22px -16px rgba(60, 40, 10, 0.28);
}
.art-has-img img { mix-blend-mode: multiply; }
.art-link { display: block; flex: 0 0 auto; }
.art-link:hover .art { border-color: var(--gold); }
.art-fallback { font-family: var(--mono); font-weight: 600; color: var(--muted); font-size: var(--fs-sm); letter-spacing: 0.1em; }
.art-sm { width: 44px; height: 44px; flex: 0 0 44px; }
.art-md { width: 96px; height: 96px; }
.art-lg { width: 120px; height: 120px; }
.art-xl { width: 128px; height: 128px; }
.pcard-body { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
/* UX-HOME finding 3: at most 3 badges live here now (price verdict, availability, trust) — everything else that
   used to be a pill (product type, language, catalog status, the MSRP-gap %, the shop marker) reads as plain text
   in .pcard-meta2, one line under the title. */
.pcard-badges { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.pcard-name { font-size: var(--fs-md); font-weight: 700; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
.pcard-meta2 { font-size: var(--fs-sm); line-height: 1.5; color: var(--muted); overflow-wrap: anywhere; }
/* U02: the "stretched link" pattern — .pcard-title-link stays a normal, unpositioned inline link (so its ::after's
   containing block is the nearest positioned ancestor, .pcard itself) whose ::after covers the full card, making
   the whole card clickable for a mouse without a second, nested anchor. Anything that must stay independently
   clickable above the stretch (the shop link) is raised with position + a higher z-index. */
.pcard-title-link::after { content: ''; position: absolute; inset: 0; z-index: 1; }
.pcard .shoplink { position: relative; z-index: 2; }
.pcard-offer { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: 2px; }
.pcard-price-row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); flex-wrap: wrap; }
.pcard-price-wrap { display: flex; flex-direction: column; gap: 1px; }
.pcard-shipnote { line-height: var(--lh-tight); }
.pcard-retailer { font-weight: 700; color: var(--text-2); font-size: var(--fs-sm); }
.pcard-foot { display: flex; justify-content: space-between; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--muted); }
.pcard-none { color: var(--muted); font-size: var(--fs-sm); }
.pcard-release { font-size: var(--fs-sm); color: var(--blue); }

/* table */
/* Story S7 / U3, U5: the wrapper always scrolls horizontally instead of clipping its last column, with a
   visible affordance (thin always-on scrollbar + a right-edge fade) and a sticky first column so the row's
   identity stays in view while scrolling. The fade's cover colour (--bg-2) matches every place .tablewrap
   actually renders a table (the desktop rule below, and every admin table's .panel ancestor). */
.tablewrap {
  position: relative;
  overflow-x: auto;
  margin: 0 calc(var(--gutter) * -1);
  padding: 0 var(--gutter);
  scrollbar-width: thin;
  scrollbar-color: var(--line-2) transparent;
}
.tablewrap::-webkit-scrollbar { height: 8px; }
.tablewrap::-webkit-scrollbar-track { background: transparent; }
.tablewrap::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 4px; }
.tablewrap::after {
  content: '';
  position: absolute;
  top: 0; right: 0; bottom: 0;
  width: 28px;
  pointer-events: none;
  background: linear-gradient(to right, transparent, var(--bg-2));
}
.ptable, .mtable { width: 100%; border-collapse: collapse; font-size: var(--fs-md); }
.ptable th, .mtable th { text-align: left; font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); padding: var(--sp-2) var(--sp-2); border-bottom: 1px solid var(--line); white-space: nowrap; }
.ptable td, .mtable td { padding: var(--sp-2); border-bottom: 1px solid var(--line); vertical-align: middle; }
.ptable tbody tr:hover { background: rgba(255, 255, 255, 0.025); }
.ptable thead th:first-child, .mtable thead th:first-child,
.ptable tbody tr:not(.group-row) td:first-child, .mtable tbody tr td:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--bg-2);
}
.ptable thead th, .mtable thead th { position: sticky; top: 0; z-index: 2; background: var(--bg-2); }
.ptable thead th:first-child, .mtable thead th:first-child { z-index: 3; }
.prow-name a { display: flex; align-items: center; gap: var(--sp-2); min-width: 260px; }
.prow-title { display: block; font-weight: 700; }
.prow-meta { display: block; font-size: var(--fs-sm); color: var(--muted); }
.row-dim { opacity: 0.55; }
.mtable code { font-size: var(--fs-sm); }
/* Privacy "what we store" table: a real table from tablet width; on phones each row is a stacked card (row heading,
   then each cell under its own column label) so nothing hides behind a sideways scroll (go-live UX review 2026-09-27). */
.mtable-stack tbody th { text-align: left; font-weight: 600; padding: var(--sp-2); border-bottom: 1px solid var(--line); vertical-align: top; }
.mtable-stack td { vertical-align: top; }
@media (max-width: 719px) {
  .mtable-stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .mtable-stack, .mtable-stack tbody, .mtable-stack tr, .mtable-stack tbody th, .mtable-stack td { display: block; width: auto; }
  .mtable-stack tr { padding: var(--sp-3) 0; border-bottom: 1px solid var(--line); }
  .mtable-stack tbody th, .mtable-stack td { border-bottom: 0; padding: var(--sp-1) 0; position: static; background: none; }
  .mtable-stack td::before { content: attr(data-label); display: block; font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); margin-bottom: 2px; }
}

/* ───────────────────────── product view ───────────────────────── */
.backrow { display: flex; }
.backlink { display: inline-flex; align-items: center; gap: var(--sp-1); color: var(--text-2); }
.phead { display: grid; grid-template-columns: 128px 1fr; gap: var(--sp-4); align-items: start; }
.ptitle { font-size: var(--fs-2xl); line-height: var(--lh-tight); margin: 4px 0 10px; }
/* WCAG 1.4.10 (go-live 2026-09-27): as many columns as fit, none narrower than a label — so at 320 px or 200% zoom the
   facts stack or wrap instead of sliding over each other (the fixed 2 / 3 / 5 columns squeezed "REFERENCIAÁR" below its width). */
.facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 8.5rem), 1fr)); gap: var(--sp-2) var(--sp-4); margin: 0; }
.facts div { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.facts dt { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); overflow-wrap: break-word; }
.facts dd { margin: 0; font-weight: 600; font-size: var(--fs-md); overflow-wrap: anywhere; }
.facts-adv { grid-template-columns: 1fr; margin-top: 10px; }
.fact-why { margin-top: var(--sp-2); font-size: var(--fs-xs); color: var(--muted); }
.fact-why summary { cursor: pointer; text-decoration: underline dotted; }
.fact-why span { display: block; margin-top: 2px; }
.panel { background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--r); padding: 14px; min-width: 0; }
/* .panel padding stays 14px (story W2-TOKENS: .panel itself unchanged). */
.panel .tablewrap { margin: 0; padding: 0; }
/* W2-TOKENS: opt-in frosted glass — ONLY the product page's best-offer hero and the /about card (never lists or
   tables: blur behind scrolling content is costly and hurts legibility). */
.panel-glass { background: var(--glass-bg); border-color: var(--glass-border); -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px); box-shadow: var(--shadow-lg); }
.panel-advanced { background: transparent; }
.best { position: relative; background: linear-gradient(180deg, var(--bg-3), var(--bg-2)); border-color: rgba(242, 192, 75, 0.35); overflow: hidden; }
.best.panel-glass { background: linear-gradient(180deg, rgba(28, 33, 48, 0.72), var(--glass-bg)); }
.best::after { content: ''; position: absolute; inset: -40% -20% auto auto; width: 60%; height: 120%; background: radial-gradient(closest-side, rgba(242, 192, 75, 0.14), transparent); pointer-events: none; }
.best-head { display: flex; justify-content: space-between; align-items: center; gap: var(--sp-2); margin-bottom: 10px; }
.best-row { display: flex; flex-direction: column; gap: var(--sp-3); }
.best-sub { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: 8px; }
.best-retailer { font-weight: 800; }
.best-foot { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; margin-top: 12px; }
.bench-note { margin-top: 10px; font-size: var(--fs-sm); color: var(--muted); line-height: var(--lh-normal); }
/* UX-PRODUCT finding 5: the desktop hero copy of the verdict badge (best-sub) and the phone copy (best-foot)
   are never both visible — exactly one badge, never two adjacent "good" badges. See product.tsx `bestShown`. */
.best-verdict-inline { display: none; }
.best-pct { white-space: nowrap; }
/* UX-PRODUCT finding 9 (owner 2026-09-26, "wow" on desktop, compact order unchanged on phone): the buy box reads
   as the hero from 1024px — a larger price, the verdict/shop/stock line above, and a faint gold glow when the
   verdict is a buy. The entrance is a single 0.18s fade + rise (within the 0.1–0.3s "finom" budget) and is
   switched off globally under prefers-reduced-motion (see the `*` rule at the top of this file). */
@media (min-width: 1024px) {
  .best { animation: best-rise var(--dur-base) var(--ease-standard); }
  .best .price-xl { font-size: 40px; } /* literal kept: hero price sits above the type scale on purpose (finding 9, ≥ 40 px) */
  .best-verdict-foot { display: none; }
  .best-verdict-inline { display: inline-flex; }
  .best-buy { box-shadow: var(--shadow-glow-gold), var(--shadow-lg); }
}
@keyframes best-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.offers { display: flex; flex-direction: column; gap: var(--sp-2); }
.offer { display: flex; gap: var(--sp-3); align-items: flex-start; padding: var(--sp-3); border-radius: var(--r-sm); background: var(--bg-3); border: 1px solid var(--line); }
.offer-main { flex: 1 1 auto; min-width: 0; }
.offer-best { border-color: rgba(242, 192, 75, 0.5); box-shadow: inset 3px 0 0 var(--gold); }
/* UX-PRODUCT finding 3: opacity on the whole row crushed its muted text to ~2.6:1 (opacity compounds with the
   panel background behind it). Dimming the background/border only keeps every row's own text at its normal
   contrast — muted text vs --bg-2 computes 5.22:1, ≥ the 4.5:1 floor. Admin-only row (not orderable), fixed anyway. */
.offer-dim { background: var(--bg-2); border-style: dashed; border-color: var(--line); }
.offer-dim .art { opacity: 0.55; }
/* UX-PRODUCT findings 4 & 7: one link per row (no separate thumbnail link, no nested anchors), sized to a
   comfortable tap target — see the phone rule further down. */
.offer-top.offer-link { display: flex; justify-content: space-between; align-items: center; gap: var(--sp-2); }
.offer-retailer { font-weight: 800; display: inline-flex; align-items: center; gap: var(--sp-1); }
.offer-link:hover .offer-retailer, .offer-link:focus-visible .offer-retailer { color: var(--gold-2); }
.offer-title { font-size: var(--fs-sm); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin: 4px 0 6px; }
.offer-badges { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.offer-foot { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: 8px; font-size: var(--fs-sm); }
.offers-sep { display: flex; flex-direction: column; gap: 2px; padding: var(--sp-2) 2px 2px; font-size: var(--fs-sm); font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); }
.offers-sep small { font-weight: 500; text-transform: none; letter-spacing: 0; }
.offers-more { padding: var(--sp-1) 2px; }

.events { display: flex; flex-direction: column; }
.events li { display: grid; grid-template-columns: 110px 1fr; gap: var(--sp-1) var(--sp-2); padding: var(--sp-2) 0; border-bottom: 1px solid var(--line); font-size: var(--fs-sm); }
.events li:last-child { border-bottom: 0; }
.ev-time { color: var(--muted); font-variant-numeric: tabular-nums; font-size: var(--fs-sm); grid-row: span 2; }
.ev-retailer { font-weight: 700; }
.ev-label { color: var(--text-2); }
.ev-up .ev-label { color: #7fe7b6; }
.ev-down .ev-label { color: #ff9aa2; }

/* chart */
.chart { display: flex; flex-direction: column; gap: var(--sp-2); }
.chart-ranges { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.chart-ranges .chip { min-height: 30px; padding: var(--sp-1) var(--sp-2); font-size: var(--fs-sm); }
.chart-legend { margin-left: auto; font-size: var(--fs-xs); color: var(--muted); display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
.lg { display: inline-block; width: 14px; height: 3px; border-radius: 2px; }
.lg-best { background: var(--gold); }
.lg-ref { background: var(--blue); }
.lg-mkt { background: var(--violet); }
.chart-svg { width: 100%; height: auto; display: block; touch-action: pan-y; }
/* UX-PRODUCT finding 6: the svg is a keyboard target (Left/Right move the readout point) — it needs its own
   visible ring, since the shared a/button focus-visible rule does not select bare svg elements. */
.chart-svg:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.chart-grid { stroke: var(--line); stroke-width: 1; }
/* literal kept: 10 px SVG labels are sized to the chart's fixed viewBox, below the UI type scale on purpose. */
.chart-tick { fill: var(--muted); font-size: 10px; font-family: var(--font); }
.chart-line { fill: none; stroke: var(--gold); stroke-width: 2.5; stroke-linejoin: round; filter: drop-shadow(0 0 6px rgba(242, 192, 75, 0.35)); }
.chart-dot { fill: var(--bg-2); stroke: var(--gold); stroke-width: 2; }
.chart-ref { stroke: var(--blue); stroke-dasharray: 4 4; stroke-width: 1.5; }
.chart-mkt { stroke: var(--violet); stroke-dasharray: 2 4; stroke-width: 1.5; }
.chart-cursor { stroke: var(--text-2); stroke-width: 1; stroke-dasharray: 2 2; }
.chart-tip { fill: var(--bg-4); stroke: var(--line-2); }
.chart-tip-text { fill: var(--text); font-size: var(--fs-xs); font-weight: 700; font-family: var(--font); }
.chart-tip-sub { fill: var(--muted); font-size: 10px; font-family: var(--font); }
.chart-empty { color: var(--muted); font-size: var(--fs-sm); padding: var(--sp-5); text-align: center; border: 1px dashed var(--line); border-radius: var(--r-sm); }

/* ───────────────────────── lists (deals, preorders) ───────────────────────── */
/* W2-TOKENS: one page-header pattern on every view — optional .eyebrow → h1 (24 px phone / 28 px desktop) →
   optional .viewhead-lead → optional action slot, right-aligned on the title's row via .viewhead-row. */
.viewhead { display: flex; flex-direction: column; gap: var(--sp-1); }
.viewhead h1 { font-size: var(--fs-2xl); line-height: var(--lh-tight); }
.viewhead .eyebrow { display: block; }
.viewhead-lead { color: var(--text-2); font-size: var(--fs-sm); }
.prelist { display: flex; flex-direction: column; gap: var(--sp-2); }
.prerow { background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--r); }
.prerow-hot { border-color: rgba(242, 192, 75, 0.5); background: linear-gradient(180deg, rgba(242, 192, 75, 0.08), var(--bg-2)); }
.prerow-link { display: flex; gap: var(--sp-3); padding: var(--sp-3); align-items: flex-start; }
.prerow-body { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; flex: 1; }
.prerow-title { display: flex; gap: var(--sp-2); align-items: center; font-weight: 700; flex-wrap: wrap; }
.prerow-meta { display: flex; gap: var(--sp-2); flex-wrap: wrap; font-size: var(--fs-sm); color: var(--muted); align-items: center; }
.prerow-offer { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; margin-top: 4px; font-size: var(--fs-sm); }

/* ───────────────────────── system ───────────────────────── */
.subnav { display: flex; gap: var(--sp-1); overflow-x: auto; }
.subnav a { padding: var(--sp-2) var(--sp-3); border-radius: 10px; font-weight: 700; color: var(--muted); white-space: nowrap; }
.subnav a.on { background: var(--bg-3); color: var(--gold-2); }
.kv { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); margin: 0 0 12px; }
.kv div { display: flex; flex-direction: column; }
.kv dt { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); }
.kv dd { margin: 0; font-weight: 800; font-size: var(--fs-lg); }
.notes { display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--fs-sm); color: var(--text-2); margin-bottom: 12px; padding-left: var(--sp-4); list-style: disc; }
.scanbox { border-color: rgba(110, 181, 255, 0.3); }
.scan-row { display: flex; flex-direction: column; gap: var(--sp-3); }
.scan-actions { display: flex; gap: var(--sp-2); }
.progress { position: relative; margin-top: 12px; height: 34px; border-radius: 10px; background: var(--bg-4); overflow: hidden; border: 1px solid var(--line); }
.progress-bar { position: absolute; inset: 0 auto 0 0; background: linear-gradient(90deg, rgba(110, 181, 255, 0.5), rgba(110, 181, 255, 0.85)); transition: width var(--dur-slow) var(--ease-standard); }
.progress-label { position: relative; display: flex; align-items: center; height: 100%; padding: 0 var(--sp-3); font-size: var(--fs-sm); font-weight: 700; }
.steps { margin-top: 10px; display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--fs-sm); max-height: 260px; overflow: auto; }
.steps li { display: flex; gap: var(--sp-2); flex-wrap: wrap; padding: var(--sp-2) var(--sp-2); border-radius: 8px; background: var(--bg-3); }
.step-r { font-weight: 700; min-width: 110px; }
.unmapped { display: flex; flex-direction: column; gap: var(--sp-2); }
.unmapped li { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3); border-radius: var(--r-sm); background: var(--bg-3); border: 1px solid var(--line); }
.um-main { display: flex; flex-direction: column; gap: 2px; font-size: var(--fs-md); }
.um-main a { font-weight: 700; }
.um-actions { display: flex; gap: var(--sp-2); }
.select { flex: 1; height: 40px; padding: 0 var(--sp-2); background: var(--bg-2); color: var(--text); border: 1px solid var(--line); border-radius: 10px; font: inherit; min-width: 0; }

/* ───────────────────────── states ───────────────────────── */
.empty { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); text-align: center; padding: var(--sp-8) var(--sp-4); border: 1px dashed var(--line); border-radius: var(--r); color: var(--muted); }
.empty h3 { color: var(--text-2); font-size: var(--fs-md); }
.empty p { font-size: var(--fs-sm); max-width: 420px; }
.empty-orb { width: 44px; height: 44px; border-radius: 50%; background: var(--foil); opacity: 0.35; filter: blur(2px); margin-bottom: 4px; }
.errorbox { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); border-radius: var(--r-sm); background: rgba(240, 97, 107, 0.1); border: 1px solid rgba(240, 97, 107, 0.4); font-size: var(--fs-md); }
.skeleton { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3); }
.skeleton-card { background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--r); min-height: 120px; }
.skeleton-line { height: 12px; border-radius: 6px; background: linear-gradient(90deg, var(--bg-3), var(--bg-4), var(--bg-3)); background-size: 200% 100%; animation: shimmer 1.4s linear infinite; }
@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
/* UX-HOME finding 6: the home loading skeleton reuses .pcard itself (same grid columns, border, radius) so its
   width and shape already match; only the height needs pinning to what real cards on this page measure (~230–300px
   — see product-card.tsx's HomeSkeleton). .skeleton-block replaces .art's own background with the same shimmer used
   by every other skeleton line, so the artwork placeholder doesn't look like a broken image. */
.pcard-skeleton { min-height: 256px; }
.skeleton-block { background: linear-gradient(90deg, var(--bg-3), var(--bg-4), var(--bg-3)); background-size: 200% 100%; animation: shimmer 1.4s linear infinite; }
/* UX-HOME finding 7: every card fades in over ~150ms as it mounts (applied on .pcard itself, above; reduced-motion
   strips this like every other animation, styles.css:34). */
@keyframes pcard-fade { from { opacity: 0; } to { opacity: 1; } }

/* ───────────────────────── filter sheet ───────────────────────── */
.sheet-backdrop { position: fixed; inset: 0; z-index: 40; background: rgba(0, 0, 0, 0.55); display: flex; align-items: flex-end; justify-content: center; animation: fade var(--dur-base) var(--ease-standard); }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
.sheet { width: 100%; max-height: 88dvh; display: flex; flex-direction: column; background: var(--bg-2); border: 1px solid var(--line-2); border-radius: 20px 20px 0 0; animation: rise var(--dur-slow) var(--ease-standard); padding-bottom: env(safe-area-inset-bottom); }
@keyframes rise { from { transform: translateY(24px); opacity: 0.5; } to { transform: none; opacity: 1; } }
.sheet-handle { width: 40px; height: 4px; border-radius: 2px; background: var(--line-2); margin: 8px auto 0; }
.sheet-head { display: flex; justify-content: space-between; align-items: center; padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-4); }
.sheet-head h2 { font-size: var(--fs-lg); }
.sheet-body { overflow: auto; padding: var(--sp-1) var(--sp-4) var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-4); }
.sheet-body h4 { font-size: var(--fs-sm); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); margin-bottom: 8px; }
.sheet-foot { display: flex; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--line); }
.sheet-foot .btn { flex: 1; }
.switch { display: flex; gap: var(--sp-2); align-items: center; padding: var(--sp-2) 0; font-size: var(--fs-md); }
.switch input { width: 20px; height: 20px; accent-color: var(--gold); }
/* push settings (app): the switches look as unavailable as they are while the phone or the e-mail alert is off */
.switch-off { opacity: 0.55; cursor: not-allowed; }
.switch-off input { cursor: not-allowed; }

/* ───────────────────────── tablet ───────────────────────── */
@media (min-width: 640px) {
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .btn-filter .btn-label { display: inline; }
  .scan-row { flex-direction: row; justify-content: space-between; align-items: flex-start; }
  .best-row { flex-direction: row; justify-content: space-between; align-items: flex-end; }
  .kv { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .unmapped li { flex-direction: row; align-items: center; justify-content: space-between; }
  .um-actions { flex: 0 0 auto; }
  .select { min-width: 260px; }
  .cm-actions { flex-wrap: nowrap; }
  .cm-actions .select { flex: 1 1 auto; max-width: 420px; }
  .sheet { max-width: 560px; border-radius: 20px; margin-bottom: 24px; max-height: 80dvh; }
  .sheet-backdrop { align-items: center; }
  /* WATCH-BELL (owner 2026-09-26): a small popover-sized dialog for the one-field watch sheet, not the full-width filter sheet. */
  .sheet.sheet-narrow { max-width: 360px; }
}

/* ── mobile/tablet top strip (story UX-SHELL, isolated UX review): below 1024 px the sidebar (brand + language
   switch) is hidden, so this strip carries both instead, on every route. Guarded by tests/ui/ux-shell.spec.ts. ── */
@media (max-width: 1023px) {
  :root { --topstrip-h: 60px; }
  /* W2-POLISH (CLS): was `position: sticky` with a `height` built from `env(safe-area-inset-top)` — a CSS Grid row
     whose one item is a sticky box sized off an `env()`-based dimension measured, in this exact Chromium build, an
     intrinsic row size of ~215–230px for a few frames before `window.load` (confirmed on the unmodified base commit
     too — a pre-existing engine quirk, not something this change introduced), before correcting itself to the real
     60px — a ~0.17–0.31 CLS hit on every mobile load, dwarfing everything else on the page. Two changes were needed,
     proven one at a time by removing each and re-measuring: `position: fixed` removes the strip from grid sizing
     entirely (a fixed box's size is never a track-sizing input) — `.main`'s own padding-top (`var(--topstrip-h)`)
     reserves the space instead; and `--topstrip-h` itself drops `env(safe-area-inset-top)` from the shared value (it
     was the unstable part even outside a grid — the same jump reappeared sized off `min-height` once the grid was
     out of the picture) in favour of a plain 60px used everywhere layout math depends on it. The safe-area inset
     still applies, just directly and only on the strip's own padding-top below (min-height, not height, so a real
     notch still grows the box instead of squeezing its content) — never through the property this bug lived in. */
  .topstrip {
    display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
    position: fixed; top: 0; left: 0; right: 0; z-index: 25; min-height: var(--topstrip-h); box-sizing: border-box;
    padding: env(safe-area-inset-top) var(--gutter) 0;
    background: rgba(16, 19, 26, 0.92); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--line);
  }
  .topstrip .langswitch button { min-height: 44px; min-width: 44px; }
}

/* ───────────────────────── desktop ───────────────────────── */
@media (min-width: 1024px) {
  :root { --gutter: 28px; }
  .shell { grid-template-columns: var(--side-w) minmax(0, 1fr); }
  .sidebar { display: flex; flex-direction: column; position: sticky; top: 0; height: 100dvh; padding: 18px 12px; border-right: 1px solid var(--line); background: var(--bg-2); }
  .bottomnav { display: none; }
  /* The sidebar already lists deals/preorders and System as separate rows — no need to repeat either here. */
  .segmentrow { display: none; }
  .account-system-link { display: none; }
  .main { padding-bottom: var(--sp-10); max-width: none; }
  .view { max-width: 1240px; gap: var(--sp-4); padding-top: var(--sp-4); }
  .topbar { margin: 0; padding-left: 0; padding-right: 0; }
  .art-xl { width: 220px; height: 220px; }
  .phead { grid-template-columns: 220px 1fr; gap: var(--sp-6); }
  .art-sm { width: 56px; height: 56px; flex-basis: 56px; }
  .viewtoggle { display: inline-flex; }
  /* W2-CARDS: the desktop card grid and the image-first card live in the W2-CARDS block at the end of this file. */
  .lastupdate { font-size: var(--fs-md); }
  .setchips { margin: 0; padding-left: 0; padding-right: 0; flex-wrap: wrap; overflow: visible; }
  .tablewrap { margin: 0; padding: 0; background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--r); }
  .ptable th:first-child, .ptable td:first-child { padding-left: var(--sp-4); }
  .art-lg { width: 160px; height: 160px; }
  .ptitle { font-size: var(--fs-3xl); }
  .viewhead h1 { font-size: var(--fs-3xl); }
  .view-product { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-auto-rows: max-content; column-gap: var(--sp-4); }
  .view-product > .backrow, .view-product > .phead, .view-product > .best, .view-product > .panel-advanced, .view-product > [data-testid='events-panel'] { grid-column: 1 / -1; }
  .kv { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .events li { grid-template-columns: 130px 140px 1fr; }
  .ev-time { grid-row: auto; }
}
@media (min-width: 1440px) {
  .view { max-width: 1360px; }
}

/* ── sidebar foot, listed-only shops, last-update strip ── */
.side-foot { display: flex; flex-direction: column; gap: var(--sp-2); align-items: flex-start; }
.listed { margin-top: 8px; }
.listed-list { list-style: none; margin: 4px 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.listed-list li { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); padding: var(--sp-2) 2px; border-top: 1px dashed var(--line); }
.lastupdate { align-items: center; }

/* System → Alerts */
.alerts-settings { display: grid; gap: var(--sp-4); margin-top: 16px; padding-top: var(--sp-4); border-top: 1px solid var(--line); }
.alerts-settings .chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); border: 0; padding: 0; margin: 0; }
.alerts-settings .chips legend { width: 100%; font-size: var(--fs-sm); color: var(--text-2); margin-bottom: 6px; }
.alerts-settings .field { display: grid; gap: var(--sp-1); max-width: 320px; }
.alerts-settings .field > span:first-child { font-size: var(--fs-sm); color: var(--text-2); }
.alerts-settings .actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.plain { list-style: none; margin: 0; padding: 0; }
/* Alerts panel key-values: the channel badge and the recipient list are text, not numbers — they wrap and span the row. */
.kv-alerts .kv-wide { grid-column: 1 / -1; }
.kv-alerts .kv-wide dd { font-size: var(--fs-md); font-weight: 600; }
.kv-alerts .kv-wide .badge { height: auto; min-height: 24px; padding: 3px var(--sp-2); white-space: normal; overflow-wrap: anywhere; line-height: 1.3; }
.kv-alerts .plain li { font-weight: 600; }
/* Release follow-up 2026-09-28: the Patreon tier role control (System → Működés). */
.ops-tier-list li { margin-bottom: var(--sp-3); overflow-wrap: anywhere; }
.ops-tier-role { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: 6px; }
.ops-tier-role select { height: 44px; min-width: 0; max-width: 100%; padding: 0 var(--sp-3); background: var(--bg-2); color: var(--text); border: 1px solid var(--line); border-radius: 10px; font: inherit; }
/* ── ADMIN-OVERVIEW (admin refresh Slice 1, owner 2026-09-27): the System landing — one column on phones, 44px rows,
   no tables; the four lights go 2-up from 640px and 4-up from 1024px. ── */
.overview { display: flex; flex-direction: column; gap: var(--sp-4); }
.overview .panel .h2 { margin-bottom: var(--sp-3); }
.ov-lights { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-2); }
.ov-light { display: flex; align-items: flex-start; gap: var(--sp-3); min-height: 44px; padding: var(--sp-2) var(--sp-3); border-radius: 12px; background: var(--bg-3); border: 1px solid var(--line); }
.ov-light .dot { flex: none; width: 12px; height: 12px; margin-top: 4px; }
.ov-light-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; overflow-wrap: anywhere; }
.ov-light-line { font-size: var(--fs-sm); }
.ov-tone-red { border-color: rgba(240, 97, 107, 0.45); }
.ov-tone-amber { border-color: rgba(251, 191, 36, 0.35); }
.dot-off { background: var(--muted); opacity: 0.6; }
.ov-todos { display: flex; flex-direction: column; gap: var(--sp-2); }
.ov-todo { display: flex; align-items: center; gap: var(--sp-3); min-height: 48px; padding: var(--sp-2) var(--sp-3); border-radius: 12px; background: var(--bg-3); border: 1px solid var(--line); color: var(--text); font-weight: 600; }
.ov-todo:hover, .ov-todo:focus-visible { background: var(--bg-4); border-color: var(--line-2); }
.ov-todo-label { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.ov-count { flex: none; min-width: 32px; height: 28px; padding: 0 var(--sp-2); border-radius: 999px; display: inline-grid; place-items: center; background: var(--gold); color: #17120a; font-weight: 800; font-size: var(--fs-sm); }
.ov-chev { flex: none; color: var(--muted); font-size: var(--fs-lg); }
.ov-allclear { display: flex; align-items: center; gap: var(--sp-2); min-height: 44px; margin: 0; color: var(--green); font-weight: 700; }
.ov-partial { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.ov-updated { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: 0; }
@media (min-width: 640px) { .ov-lights { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .ov-lights { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
/* Részletek (bottom of System → Üzemeltetés): a closed disclosure; the summary is a 44px target. */
.ops-details > summary { cursor: pointer; min-height: 44px; padding: var(--sp-1) 0; }
.ops-details > summary .h2 { display: inline; margin: 0; }
.ops-details > summary .ops-details-lead { display: block; margin-top: 2px; }
.ops-details[open] > summary { margin-bottom: var(--sp-3); }

/* ───────────── Admin refresh Slice 2 (owner 2026-09-27): System grouped by the owner's jobs ─────────────
   Section nav: below 768 px a 3-column grid — every section visible at once, 44 px tall, no sideways scroll hiding
   a tab. From 768 px one row (the old subnav). Részletek is a quiet link on the title row, not a tab. */
.sysnav { overflow-x: visible; }
@media (max-width: 767px) {
  .sysnav { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-1); }
  .sysnav a { display: flex; align-items: center; justify-content: center; min-height: 44px; padding: var(--sp-2) var(--sp-1); text-align: center; white-space: normal; overflow-wrap: anywhere; line-height: 1.2; background: rgba(255, 255, 255, 0.03); }
}
@media (min-width: 768px) { .sysnav { flex-wrap: wrap; } }
.sys-details-link { display: inline-flex; align-items: center; min-height: 44px; padding: 0 var(--sp-2); border-radius: 10px; font-weight: 700; color: var(--muted); white-space: nowrap; }
.sys-details-link:hover, .sys-details-link:focus-visible { color: var(--text); }
.sys-details-link.on { color: var(--gold-2); background: var(--bg-3); }
.sys-page-title { font-size: var(--fs-lg); font-weight: 800; margin: 0; }
.sys-segs { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.sys-segs .chip { display: inline-flex; align-items: center; min-height: 44px; }
.ov-alarms .ops-details-lead.warn { color: var(--amber); font-weight: 700; }

/* Boltok: one list for every shop. The row IS the <details> summary, so the whole row is the tap target. Phones:
   a card (name + badge, the reason, then last success · failures). From 768 px: a compact table — the same rows
   laid out on shared column tracks under one header row. */
.shops { display: flex; flex-direction: column; gap: var(--sp-2); margin: var(--sp-3) 0 0; }
.shop { border: 1px solid var(--line); border-radius: 12px; background: var(--bg-3); min-width: 0; }
.shop > details > summary { list-style: none; cursor: pointer; display: grid; grid-template-columns: minmax(0, 1fr) auto 16px; grid-template-areas: "name status chev" "reason reason chev" "meta meta chev"; align-items: center; gap: var(--sp-1) var(--sp-2); min-height: 44px; padding: var(--sp-2) var(--sp-3); border-radius: 12px; }
.shop > details > summary::-webkit-details-marker { display: none; }
.shop > details > summary:hover { background: var(--bg-4); }
.shop-name { grid-area: name; font-weight: 700; overflow-wrap: anywhere; min-width: 0; }
.shop-status { grid-area: status; justify-self: end; }
.shop-reason { grid-area: reason; font-size: var(--fs-sm); overflow-wrap: anywhere; min-width: 0; }
.shop-meta { grid-area: meta; display: flex; flex-wrap: wrap; gap: 0 var(--sp-3); font-size: var(--fs-sm); color: var(--muted); min-width: 0; }
.shop-fails-none { display: none; }
.shop-reason-none { display: none; }
.shop-chev { grid-area: chev; color: var(--muted); font-size: var(--fs-lg); transition: transform var(--dur-fast) var(--ease-standard); }
.shop > details[open] .shop-chev { transform: rotate(90deg); }
.shop-detail { padding: 0 var(--sp-3) var(--sp-3); min-width: 0; }
.shop-detail .shop-h { margin: var(--sp-3) 0 var(--sp-2); }
.shop-detail .kv dd { font-size: var(--fs-sm); font-weight: 600; }
.shop-error { overflow-wrap: anywhere; font-family: var(--font-mono, ui-monospace, monospace); }
.shops-head { display: none; }
.shops-legend { margin-top: var(--sp-3); }
@media (min-width: 768px) {
  .shops { gap: 0; border-top: 1px solid var(--line); margin-top: 0; }
  .shop { border-width: 0 0 1px; border-radius: 0; background: transparent; }
  .shops-head, .shop > details > summary { grid-template-columns: minmax(0, 1.3fr) 120px minmax(0, 2fr) 120px 130px 16px; grid-template-areas: "name status reason success fails chev"; gap: var(--sp-2); }
  .shops-head { display: grid; margin-top: var(--sp-3); padding: 0 var(--sp-3) var(--sp-2); font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); }
  .shop > details > summary { border-radius: 0; }
  .shop-status { justify-self: start; }
  .shop-meta { display: contents; }
  .shop-success { grid-area: success; }
  .shop-fails, .shop-fails-none { grid-area: fails; display: block; }
  .shop-reason-none { display: block; }
  .shop-lbl { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .shop-detail { padding: 0 var(--sp-3) var(--sp-4); }
}
/* A to-do link lands on an Üzemeltetés section by its #anchor: keep it clear of the fixed phone top strip. */
.ops [id] { scroll-margin-top: calc(var(--topstrip-h) + 12px); }
/* The admin-only Rendszer icon in the phone top strip (a 44px target beside the language switch). */
.topstrip-actions { display: flex; align-items: center; gap: var(--sp-1); }
.topstrip-icon { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; border-radius: 12px; color: var(--text-2); }
.topstrip-icon:hover, .topstrip-icon:focus-visible { background: var(--bg-3); color: var(--text); }
.topstrip-icon.on { color: var(--gold); }

/* Public preview banner (time-boxed anonymous read mode) */
.public-banner { margin: 8px 0 12px; padding: var(--sp-2) var(--sp-3); border-radius: 10px; background: rgba(242, 192, 75, 0.12); border: 1px solid rgba(242, 192, 75, 0.4); color: var(--gold-2); font-size: var(--fs-sm); font-weight: 600; }

/* profile */
/* W2-POLISH (CLS): `/api/me` resolves after first paint, so this banner used to be inserted above already-painted
   content — a +64px shift the moment it appeared. Anchored at the bottom-right as a narrow corner toast, never a
   full-width bar: an earlier attempt spanned the whole width right under the topbar and visually covered the search
   box and the Filters/view-toggle buttons there; a later attempt spanned the whole width at the bottom instead, and
   on a short page (few results) covered the "Not available now" toggle. Both were invisible to the CLS metric
   (nothing it overlaps actually moves) but very real to a person or a test trying to click through it (measured: it
   silently ate clicks on `open-filters` and `unavailable-toggle` in the existing suite, in each version
   respectively). Two independent measures now keep this from ever blocking a control or shifting layout regardless
   of page or content length: `position: fixed` takes it out of document flow entirely, so its arrival can never move
   the search box or anything else; the box itself is corner-sized, not a bar spanning the content; and the box is
   `pointer-events: none`, re-enabled only on its own link and dismiss button — so even the sliver of any page it
   does sit over stays fully clickable underneath it, everywhere but those two small controls. */
.nameprompt-banner {
  position: fixed; z-index: 32; display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  pointer-events: none; left: auto; right: var(--gutter); bottom: calc(var(--nav-h) + env(safe-area-inset-bottom) + var(--sp-3));
  max-width: calc(100vw - 2 * var(--gutter)); width: max-content; margin: 0;
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm); background: var(--bg-3); border: 1px solid var(--line-2);
  box-shadow: var(--shadow-lg); font-size: var(--fs-sm); color: var(--text-2);
  animation: nameprompt-in var(--dur-slow) var(--ease-standard);
}
@keyframes nameprompt-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.nameprompt-banner a, .nameprompt-banner button { pointer-events: auto; }
.nameprompt-banner a { color: var(--gold-2); font-weight: 700; display: inline-flex; align-items: center; min-height: 24px; } /* 5.2: ≥ 24 px everywhere, 44 px ≤ 600px (block below) */
.nameprompt-banner button { margin-left: auto; display: inline-flex; padding: var(--sp-1); border-radius: 6px; color: var(--muted); }
.nameprompt-banner button:hover { background: var(--bg-4); color: var(--text); }
/* Release review 2026-09-27: on phones the toast sat on top of the watch sheet's lower half (both hug the bottom
   edge). While any sheet or dialog is open the toast steps aside; it comes back when the sheet closes. */
body:has(.sheet-backdrop) .nameprompt-banner { display: none; }
/* Go-live UX review 2026-09-27: while the toast is up, the page reserves room for it at the end, so the last
   lines of any page scroll clear of it instead of ending underneath it. */
body:has(.nameprompt-banner) .main { padding-bottom: calc(var(--nav-h) + 24px + 72px); }
@media (min-width: 1024px) { body:has(.nameprompt-banner) .main { padding-bottom: calc(var(--nav-h) + 24px + 64px); } }
@media (min-width: 1024px) {
  /* Desktop has no bottom tab bar: the same corner toast just sits lower, clear of the sidebar's own footer (a
     separate column) and of anything the main column puts near its bottom. */
  .nameprompt-banner { bottom: var(--sp-4); max-width: min(380px, calc(100vw - var(--side-w) - 2 * var(--gutter))); }
}
.profile-identity { display: flex; align-items: center; gap: var(--sp-2); color: var(--text-2); }
.profile-identity input[disabled] { flex: 1; min-width: 0; height: 40px; padding: 0 var(--sp-3); background: var(--bg-3); color: var(--text-2); border: 1px solid var(--line); border-radius: 10px; font: inherit; opacity: 0.9; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.profile-note { font-size: var(--fs-sm); color: var(--muted); margin-top: 6px; }
/* 5.2: a note that is only a link (the privacy links) — the link itself is the tap target */
.profile-note-link a { display: inline-flex; align-items: center; min-height: 24px; }
.profile-field { display: grid; gap: var(--sp-2); max-width: 420px; margin-top: 8px; }
.profile-field input[type='text'] { height: 40px; padding: 0 var(--sp-3); background: var(--bg-2); color: var(--text); border: 1px solid var(--line); border-radius: 10px; font: inherit; font-size: var(--fs-md); }
.profile-field input:focus { outline: 0; border-color: var(--gold); box-shadow: 0 0 0 3px rgba(242, 192, 75, 0.15); }
.profile-row { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin-top: 10px; }
.profile-row select { height: 40px; padding: 0 var(--sp-2); background: var(--bg-2); color: var(--text); border: 1px solid var(--line); border-radius: 10px; font: inherit; font-size: var(--fs-md); }
.profile-err { color: var(--red); font-size: var(--fs-sm); margin-top: 6px; }
.profile-notify { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: 12px; padding-top: var(--sp-3); border-top: 1px solid var(--line); }
.profile-spinner { display: inline-block; width: 14px; height: 14px; margin-left: 6px; border: 2px solid var(--line-2); border-top-color: var(--gold); border-radius: 50%; vertical-align: middle; animation: profile-spin 0.7s linear infinite; }
@keyframes profile-spin { to { transform: rotate(360deg); } }
@media (max-width: 767px) {
  .profile-row { flex-direction: column; align-items: stretch; }
}

/* shop links */
.shoplink { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-sm); font-weight: 700; color: var(--gold-2); max-width: 100%; overflow-wrap: anywhere; }
.shoplink:hover { text-decoration: underline; }
.shoplink svg { flex: none; }
.shoplink-sm { font-size: var(--fs-xs); min-height: 24px; }
.shoplink-tap { min-height: 24px; } /* the product page's Cardmarket link (verifier W-tap-1: was 18.8 px); 44px on phones below */ /* 5.2: WCAG 2.2 target size — 44px on phones (≤ 600px block below); it sits above the card's stretched link, a near miss used to open the product */

/* watchlist */
.bottomnav-item { min-width: 0; }
.bottomnav-item span { max-width: 100%; padding: 0 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.watch-editor { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.watch-field { display: grid; gap: var(--sp-2); max-width: 260px; }
.watch-field input { height: 40px; padding: 0 var(--sp-3); background: var(--bg-2); color: var(--text); border: 1px solid var(--line); border-radius: 10px; font: inherit; font-size: var(--fs-md); font-variant-numeric: tabular-nums; }
.watch-field input:focus { outline: 0; border-color: var(--gold); box-shadow: 0 0 0 3px rgba(242, 192, 75, 0.15); }
.watch-label { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); font-weight: 700; }
.watch-editor .profile-note { margin-top: 0; }
.watch-group { border: 0; margin: 0; padding: var(--sp-2) 0 0; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.watch-group legend { padding: 0; margin-bottom: 8px; float: left; width: 100%; }
.watch-actions { margin-top: 4px; }
.watch-saved { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-sm); font-weight: 700; color: var(--green); }
.watchlist-top .switch { padding: 0; }
.wlist { display: flex; flex-direction: column; }
.wrow { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-2); padding: var(--sp-3) 0; border-bottom: 1px solid var(--line); min-width: 0; }
.wrow:last-child { border-bottom: 0; }
.wrow-name { font-weight: 800; color: var(--text); overflow-wrap: anywhere; }
.wrow-name:hover { color: var(--gold-2); }
.wrow-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: 4px; }
.wrow-offer { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-2); min-width: 0; }
.wrow-retailer { font-weight: 700; font-size: var(--fs-sm); overflow-wrap: anywhere; }
.wrow-badges { display: inline-flex; flex-wrap: wrap; gap: var(--sp-2); }
.wrow-limit { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); font-weight: 700; color: var(--text-2); }
.wrow-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
@media (min-width: 1024px) {
  .wrow { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1.6fr) minmax(0, 0.9fr) auto; align-items: center; column-gap: var(--sp-4); }
  .wrow-actions { justify-content: flex-end; }
}

/* privacy */
/* Story UX-SHELL: was 12px --muted, read as disabled. Still secondary (below the nav items' full --text), but
   legible and clearly interactive on hover. */
.side-privacy-link { font-size: var(--fs-md); color: var(--text-2); text-decoration: none; }
.side-privacy-link:hover { color: var(--text); text-decoration: underline; }
.privacy-page { max-width: 760px; }
.privacy-updated { font-variant-numeric: tabular-nums; }
.privacy-list { margin: 6px 0 0 18px; padding: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.privacy-page .panel p + p { margin-top: 8px; }

/* ───────── public UI (release pro-2026-09, R6): landing, Free vs Pro, account, data age ───────── */
.btn-wrap { white-space: normal; height: auto; min-height: 44px; padding-top: var(--sp-2); padding-bottom: var(--sp-2); text-align: center; line-height: 1.25; }
.btn[aria-disabled='true'] { opacity: 0.7; cursor: default; }
/* the scoped .landing/.pro-page/.account-page focus-visible rule this replaced is now covered by the
   global a/button:focus-visible rule above (base). */
.linklike { color: var(--gold-2); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; display: inline-flex; align-items: center; min-height: 44px; }
/* literal kept: the Pro badge family (9–10 px text, 15/18/24 px pill heights) is tuned to sit inside nav rows and on an icon. */
.probadge { display: inline-flex; align-items: center; height: 18px; padding: 0 6px; border-radius: 999px; font-size: 10px; font-weight: 800; letter-spacing: 0.04em; color: #17120a; background: var(--foil); flex: none; }
.probadge-lg { height: 24px; padding: 0 10px; font-size: var(--fs-sm); }
.sidenav-item .probadge { margin-left: auto; }
.bottomnav-icon { position: relative; display: inline-flex; }
.bottomnav-icon .probadge { position: absolute; top: -6px; right: -18px; height: 15px; padding: 0 4px; font-size: 9px; }
.lastupdate .lastupdate-age { white-space: normal; overflow: visible; text-overflow: clip; min-width: 0; }
.dataage { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--muted); }
.dataage .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); flex: none; }
.dataage.stale .dot { background: var(--amber); }

.landing { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); padding: var(--sp-4); margin-top: 4px; border: 1px solid var(--line); border-radius: var(--r-lg); background: linear-gradient(160deg, rgba(242, 192, 75, 0.08), transparent 55%), var(--bg-2); min-width: 0; }
.landing.panel-glass { background: linear-gradient(160deg, rgba(242, 192, 75, 0.08), transparent 55%), var(--glass-bg); border-color: var(--glass-border); }
.landing-main { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.landing-title { font-size: var(--fs-xl); line-height: var(--lh-tight); overflow-wrap: anywhere; }
.landing-lead { color: var(--text-2); }
.landing-cta { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.landing-cta .btn { flex: 1 1 200px; }
.landing-h2 { margin: 6px 0 0; }
.landing-steps { list-style: decimal; padding-left: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2); color: var(--text-2); font-size: var(--fs-md); }
.landing-disclaimer { font-size: var(--fs-sm); color: var(--muted); border-top: 1px solid var(--line); padding-top: var(--sp-2); }
@media (min-width: 1024px) {
  /* Story UX-SHELL: was a 1.6fr/1fr two-column grid whose second column nothing ever filled — the owner's lean
     copy (title, lead, CTA, 3 steps, disclaimer) reads better as one generous, centered column than stretched
     across a mostly-empty row. */
  .landing { grid-template-columns: minmax(0, 1fr); max-width: 720px; margin-left: auto; margin-right: auto; padding: var(--sp-8); gap: var(--sp-5); }
  .landing-title { font-size: var(--fs-3xl); }
  .landing-disclaimer { grid-column: 1 / -1; }
  .landing-cta .btn { flex: 0 1 auto; }
}

.pro-page { max-width: 860px; }
/* Owner 2026-09-27: the support message is the point of Pro — it reads as a message, not as fine print. */
.pro-page .viewhead-lead { font-size: var(--fs-lg, 17px); line-height: var(--lh-normal); color: var(--text); max-width: 62ch; margin-top: var(--sp-2); }
.pro-tablewrap { overflow-x: visible; }
.pro-table { width: 100%; border-collapse: collapse; font-size: var(--fs-md); table-layout: fixed; }
.pro-table th, .pro-table td { text-align: left; padding: var(--sp-2) var(--sp-2); border-bottom: 1px solid var(--line); vertical-align: top; overflow-wrap: break-word; hyphens: auto; }
.pro-table thead th { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); }
.pro-table tbody th { font-weight: 700; color: var(--text-2); }
.pro-table .pro-col { color: var(--gold-2); }
.pro-table tbody tr:last-child th, .pro-table tbody tr:last-child td { border-bottom: 0; }
/* Release review 2026-09-27: on a phone three equal columns split long Hungarian words mid-word ("előrendelése|k");
   the label column gets the room it needs and a slightly smaller face instead. */
@media (max-width: 600px) {
  .pro-table thead th:first-child { width: 40%; }
  .pro-table tbody th, .pro-table tbody td { font-size: var(--fs-sm); }
}
.pro-limits { list-style: disc; padding-left: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2); color: var(--text-2); font-size: var(--fs-md); }
.plan-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-2); }
.plan-card { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-4); border: 1px solid var(--line-2); border-radius: var(--r); background: var(--bg-3); min-width: 0; }
.plan-name { font-size: var(--fs-lg); }
.plan-price strong { font-size: var(--fs-2xl); }
.plan-reason { margin-top: 10px; font-weight: 700; color: var(--amber); }
@media (min-width: 640px) {
  .plan-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.account-visitor-note { color: var(--text-2); }
.account-cap { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); font-size: var(--fs-md); color: var(--text-2); margin-bottom: 8px; }
.account-thanks { color: var(--gold-2); font-weight: 700; margin: 0 0 var(--sp-2); }
.account-sync { margin-top: 10px; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm); background: rgba(110, 181, 255, 0.1); border: 1px solid rgba(110, 181, 255, 0.3); color: #a9d3ff; font-size: var(--fs-sm); }

/* ── UX-ACCOUNT (owner 2026-09-26): identity/plan/notifications/sign-out/danger-zone cards, laid out with named grid
   areas so the visual order can differ from the DOM/tab order between phone and desktop without reordering either. */
.account-system-link { margin-bottom: 10px; }
.account-grid {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: 'identity' 'plan' 'notifications' 'signout' 'danger';
}
.account-grid > .account-identity { grid-area: identity; }
.account-grid > .account-plan { grid-area: plan; }
.account-grid > .account-notifications { grid-area: notifications; }
.account-grid > .account-signout { grid-area: signout; }
.account-grid > .account-danger { grid-area: danger; }
/* The plan card borrows `.landing`'s gold wash only: on desktop `.landing` is a centred 720px column with 32px
   padding, which shrank this card into the middle of its grid cell (release review 2026-09-27). */
.account-grid > .account-plan { max-width: none; margin-left: 0; margin-right: 0; padding: var(--sp-4); }
/* Desktop: the notifications card spans all four rows; the last row is flexible, so its height is absorbed there
   (spanning items contribute to flexible tracks only) and the left cards stack tightly at the top. */
@media (min-width: 1024px) {
  .account-grid {
    grid-template-columns: minmax(320px, 400px) minmax(0, 1fr);
    grid-template-rows: auto auto auto 1fr;
    grid-template-areas: 'identity notifications' 'plan notifications' 'signout notifications' 'danger notifications';
    align-items: start;
  }
}

.account-id-row { display: flex; gap: var(--sp-4); align-items: flex-start; }
.avatar-ring { display: inline-flex; border-radius: 50%; flex: none; }
.avatar-ring-pro { padding: 2px; background: var(--foil); }
.avatar { width: 52px; height: 52px; border-radius: 50%; background: var(--bg-3); color: var(--gold-2); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: var(--fs-lg); flex: none; }
.account-id-main { min-width: 0; flex: 1; }
.account-name-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); min-height: 28px; }
.account-name-text { font-size: var(--fs-lg); font-weight: 800; overflow-wrap: anywhere; }
/* Quiet, but the ≥44 px tap target stays (inherited from .linklike — story R16 guard, tests/ui/tap-targets.spec.ts):
   only the text shrinks, never the hit area. */
.account-name-edit { font-size: var(--fs-sm); }
.account-name-field { margin-top: 6px; max-width: 320px; }
.account-plan-chip { flex: none; }
.account-id-email { margin-top: 8px; }
.account-signout { display: flex; flex-direction: column; align-items: flex-start; gap: 0; }

/* Disclosures (notifications, danger zone): a native <details> so keyboard/AT support and the global focus ring
   come for free; the summary carries the heading plus (notifications only) an always-visible one-line state, placed
   under the title (not beside it, story UX-ACCOUNT-2) so a long summary ("Figyelőlista-értesítők: ki · Kiemelt
   akciók: be") wraps instead of being squeezed or clipped on desktop. */
.acct-disclosure summary { cursor: pointer; list-style: revert; }
.acct-disclosure-summary { display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 2px; min-height: 44px; }
.acct-disclosure-summary .h2 { margin: 0; }
.acct-disclosure-state { font-size: var(--fs-sm); overflow-wrap: anywhere; white-space: normal; }
.acct-disclosure-body { margin-top: 10px; padding-top: var(--sp-2); border-top: 1px solid var(--line); }
.account-danger { border-color: rgba(240, 97, 107, 0.35); }

/* ── Apps' account tab (2026-10-07, views/account-app.tsx): one column on every width — a list hub, not the website's
   two-column grid — with Delete account set clearly apart at the end. ── */
.app-account { max-width: 640px; margin-left: auto; margin-right: auto; }
.app-hub { display: flex; flex-direction: column; gap: var(--sp-4); }
.app-hub .account-danger { margin-top: var(--sp-6); }
.app-hub h2.h2 { margin: 0 0 var(--sp-2); }
.app-signin { display: flex; flex-direction: column; gap: var(--sp-3); }
.app-signin-value { color: var(--text-2); font-size: var(--fs-md); margin: 0; }
.app-signin .profile-note { margin-top: 0; }
.app-legal { display: flex; flex-wrap: wrap; gap: 0 var(--sp-4); margin-top: var(--sp-4); }
.app-hub .app-legal { margin-top: 0; flex-direction: column; }
.push-status { color: var(--text-2); }

/* UX-ACCOUNT-2: the notifications card's own "Haladó beállítások" disclosure (rule defaults, per-check summary,
   quiet hours, daily cap, account-mail line, unsubscribe-all) — collapsed by default, nested inside the outer
   notifications disclosure. */
.notify-advanced { margin-top: 4px; }
.notify-advanced > summary { min-height: 40px; }
.notify-advanced-body { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: 8px; padding-top: var(--sp-2); border-top: 1px solid var(--line); }
.notify-advanced-state { font-size: var(--fs-sm); color: var(--amber); }

/* ── Watch rules + notification settings (release pro-2026-09, story R7) ── */
.notice { padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm); background: var(--bg-3); border: 1px solid var(--line); color: var(--text-2); font-size: var(--fs-sm); line-height: var(--lh-normal); overflow-wrap: anywhere; }
.notice a { color: var(--gold-2); font-weight: 700; text-decoration: underline; }
.notice-pro { background: rgba(242, 192, 75, 0.1); border-color: rgba(242, 192, 75, 0.4); }
.notice-warn { background: rgba(240, 97, 107, 0.1); border-color: rgba(240, 97, 107, 0.35); color: #ff9aa2; }
#notifications .notice { margin-bottom: 10px; }
.check-hint { align-items: flex-start; }
.check-hint input { flex: none; margin-top: 1px; }
.check-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; overflow-wrap: anywhere; }
.check-sub { font-size: var(--fs-sm); color: var(--muted); font-weight: 400; }
.watch-le { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.watch-le input { flex: 1; min-width: 0; }
.watch-le-sign { font-size: var(--fs-lg); font-weight: 800; color: var(--text-2); }
.watch-after-check { display: flex; align-items: center; gap: var(--sp-2); }
.wrow-rules { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.rule-chip { min-width: 24px; justify-content: center; cursor: help; }
.rule-chip-on { background: rgba(242, 192, 75, 0.14); color: var(--gold-2); border-color: rgba(242, 192, 75, 0.5); }
.rule-chip-off { background: transparent; color: var(--muted); border-color: var(--line); text-decoration: line-through; }
.notify-title { display: block; margin-top: 18px; padding-top: var(--sp-4); border-top: 1px solid var(--line); }
.notify-prefs { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: 8px; min-width: 0; }
.notify-group { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.notify-group .profile-note { margin-top: 0; }
/* STD-DEALS: the top deals switch (Pro/admin) sits apart from the watchlist switch below it — two independent choices. */
.deal-alerts-group { padding-bottom: var(--sp-3); margin-bottom: 12px; border-bottom: 1px solid var(--line); }
.notify-field { display: grid; gap: var(--sp-2); min-width: 0; }
.notify-inline { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-2); min-width: 0; }
.notify-prefs select, .notify-prefs input[type='number'] { height: 40px; padding: 0 var(--sp-2); background: var(--bg-2); color: var(--text); border: 1px solid var(--line); border-radius: 10px; font: inherit; font-size: var(--fs-md); max-width: 100%; }
.notify-prefs input[type='number'] { width: 150px; font-variant-numeric: tabular-nums; }
.notify-prefs select:focus, .notify-prefs input:focus { outline: 0; border-color: var(--gold); box-shadow: 0 0 0 3px rgba(242, 192, 75, 0.15); }
.notify-account { color: var(--text-2); }

/* ───────────────────────── advertising (R8; simple ads 2026-09-28) ───────────────────────── */
/* The public slot: its own bordered, labelled box — visually apart from every organic list. A calm card (owner
   2026-09-27, "ads must be discreet"): thin border on the muted surface, a small plain "Hirdetés" label, a small image,
   no gradient or colour accent. Rotation (2026-09-28): every card sits in the same grid cell, only the current one
   visible — the slot keeps the tallest card's height, so a change never moves the page; the change fades in unless the
   person prefers reduced motion. */
.adslot { display: flex; flex-direction: column; gap: var(--sp-2); margin: 4px 0 14px; min-width: 0; }
.adslot-stack { display: grid; min-width: 0; }
.adslot-stack > .adcard { grid-area: 1 / 1; }
.adcard { position: relative; min-width: 0; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--bg-2); padding: var(--sp-2) var(--sp-3); box-shadow: none; transition: none; animation: none; }
.adcard-queued { visibility: hidden; }
@keyframes adfade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: no-preference) { .adslot-stack > .adcard-in { animation: adfade var(--dur-base, 0.2s) ease-out; } }
.adcard-head { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: 4px; }
.adcard-label { font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.02em; color: var(--muted); }
.adcard-link { display: flex; gap: var(--sp-3); align-items: flex-start; min-width: 0; color: inherit; text-decoration: none; }
a.adcard-link:hover .adcard-title, a.adcard-link:focus-visible .adcard-title { text-decoration: underline; text-underline-offset: 2px; }
.adcard-imgbox { flex: 0 0 auto; width: 56px; height: 56px; border-radius: 8px; overflow: hidden; background: var(--bg-3); display: grid; place-items: center; }
.adcard-imgbox img { width: 100%; height: 100%; object-fit: cover; display: block; }
.adcard-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.adcard-title { font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
.adcard-desc { font-size: var(--fs-sm); color: var(--text-2); overflow-wrap: anywhere; }
.adcard-merchant { font-size: var(--fs-xs); color: var(--muted); overflow-wrap: anywhere; }
.adcard-open { display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-xs); color: var(--gold); font-weight: 600; }
.adcard-imgbox-empty { color: var(--muted); }
@media (min-width: 640px) { .adcard-imgbox { width: 72px; height: 72px; } }
.adreport { max-width: 520px; }
@media (min-width: 640px) { .sheet-backdrop:has(.adreport) { align-items: center; } .adreport { border-radius: 20px; } }

/* The advertising page (one screen) and System → Hirdetések */
.adv-page { display: flex; flex-direction: column; gap: var(--sp-4); }
.adv-form { display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0; }
.adv-field { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; max-width: 560px; font-size: var(--fs-sm); font-weight: 700; color: var(--text-2); }
.adv-field input, .adv-field select, .adv-field textarea { width: 100%; min-height: 42px; padding: var(--sp-2) var(--sp-3); background: var(--bg-3); color: var(--text); border: 1px solid var(--line); border-radius: 10px; font: inherit; font-size: var(--fs-md); font-weight: 500; }
.adv-field input[type='file'] { padding: var(--sp-2); }
.adv-field textarea { resize: vertical; }
.adv-field input:focus, .adv-field select:focus, .adv-field textarea:focus { outline: 0; border-color: var(--gold); box-shadow: 0 0 0 3px rgba(242, 192, 75, 0.15); }
.adv-field .profile-note, .adv-field .profile-err { font-weight: 500; margin-top: 0; }
.adv-field .btn { align-self: flex-start; }
.adv-field-inline { flex-direction: row; align-items: center; gap: var(--sp-2); }
/* Start + end: stacked on phones, side by side from 640 px (UX review 2026-09-28). */
.adv-dates { display: grid; grid-template-columns: 1fr; gap: var(--sp-3); max-width: 560px; }
@media (min-width: 640px) { .adv-dates { grid-template-columns: 1fr 1fr; } }
/* "+ Új hirdetés": full width on phones, its own width from 640 px, right under the list. */
.adv-new .btn { width: 100%; }
@media (min-width: 640px) { .adv-new .btn { width: auto; } }
.adv-field input[aria-invalid='true'] { border-color: var(--red); }
.adv-field-inline select { width: auto; max-width: 100%; }
.adv-preview { display: flex; flex-direction: column; gap: var(--sp-2); max-width: 560px; }
.adv-preview .adslot { margin: 0; }
.adv-radios { border: 0; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.adv-radios legend { font-size: var(--fs-sm); font-weight: 700; color: var(--text-2); margin-bottom: 4px; }
.adv-radio { display: flex; align-items: center; gap: var(--sp-2); min-height: 36px; }
.adv-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.adv-panelhead { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-2); margin-bottom: 4px; }
.adv-panelhead .h2 { margin-bottom: 0; }
.adv-notice { color: var(--green); font-size: var(--fs-sm); font-weight: 600; }
.adv-page code, .sysads code { overflow-wrap: anywhere; word-break: break-all; }
.adv-contact { text-align: center; }
.adv-rejection { display: flex; flex-direction: column; gap: var(--sp-1); padding: var(--sp-2) var(--sp-3); border: 1px solid rgba(255, 154, 162, 0.45); border-radius: var(--r-sm); background: rgba(255, 154, 162, 0.06); font-size: var(--fs-sm); min-width: 0; overflow-wrap: anywhere; }
.adv-rejection-note { white-space: pre-line; color: var(--text); }
.sysads { display: flex; flex-direction: column; gap: var(--sp-4); }
.adm-list { display: flex; flex-direction: column; gap: var(--sp-3); }
/* UX review 2026-09-28: on a wide screen the ad queue (and the ad lists) use the width — cards side by side. */
@media (min-width: 1024px) { .adm-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 420px), 1fr)); align-items: start; } }
.adm-item { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3); border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--bg-3); min-width: 0; overflow-wrap: anywhere; }
.adm-item-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.adm-preview { margin: 0; }
.adm-week { overflow-wrap: anywhere; }
.adm-change-label { font-weight: 700; color: var(--text-2); }
/* System → Hirdetések sections (owner 2026-09-28): the ended ads fold away; the summary is a full-size tap target. */
.sysads details > summary { display: flex; align-items: center; gap: var(--sp-2); min-height: 44px; margin-bottom: 0; cursor: pointer; }
.sysads details[open] > summary { margin-bottom: var(--sp-3); }
.ov-adsline { margin: var(--sp-2) 0 0; }
.ov-adsline a { display: inline-flex; align-items: center; min-height: 44px; }
/* Account menu (below 1024 px the sidebar is hidden): Fiók · Hirdetés as tabs above the page. */
.acctnav { margin: 0 0 8px; }
@media (min-width: 1024px) { .acctnav { display: none; } }
.sidenav-sub { padding-left: var(--sp-6); font-size: var(--fs-md); }

/* ── Tap targets on phones (story R16, R11 accessibility finding): every standalone control — buttons, tabs, the
   language toggle, dismiss buttons, form fields, and the label row wrapping a checkbox or radio — offers at
   least a 44 × 44 px hit area at ≤ 600 px. Sizes grow through min-height/min-width only; no visual redesign.
   Inline links inside running text are exempt (WCAG 2.5.5). Guarded by tests/ui/tap-targets.spec.ts. ── */
@media (max-width: 600px) {
  .btn, .btn-sm { min-height: 44px; min-width: 44px; }
  /* UX-HOME finding 5: the filter sheet's chips (Availability, Price class, Type, Language) were the app's own bar
     at 36px against the rest of the phone UI's 44px. */
  .chip { min-height: 44px; }
  .langswitch button, .langswitch-compact button { min-height: 44px; min-width: 44px; }
  .nameprompt-banner button { min-width: 44px; min-height: 44px; align-items: center; justify-content: center; }
  /* One row on phones: the question wraps inside its own box, so the 44px close button no longer drops to a second
     line and doubles the toast's height. */
  .nameprompt-banner { flex-wrap: nowrap; }
  .nameprompt-banner span { flex: 1 1 auto; min-width: 0; }
  .nameprompt-banner a { white-space: nowrap; }
  .subnav a { display: inline-flex; align-items: center; min-height: 44px; }
  .iconbtn { width: 44px; height: 44px; }
  .watch-bell.on { width: auto; min-width: 44px; padding: 0 var(--sp-4); }
  .searchbox { height: auto; min-height: 44px; }
  .searchbox input { align-self: stretch; min-height: 44px; }
  /* :is() lends every field the specificity of its longest argument, so component rules (.adv-field select …) yield. */
  :is(input:not([type='checkbox']):not([type='radio']):not([type='hidden']), select, textarea) { min-height: 44px; }
  .check, .switch, .adv-radio { min-height: 44px; }
  /* 5.2 (390 px): the three links that measured 16–19 px */
  .shoplink-sm { min-height: 44px; }
  .shoplink-tap { min-height: 44px; }
  .nameprompt-banner a { min-height: 44px; }
  .profile-note-link a { min-height: 44px; }
}

/* UX-PRODUCT finding 7: the offer row's one link (shop name + price) is a comfortable tap target on phone —
   the row itself stays the same visual height, only the link's own hit area grows. */
@media (max-width: 600px) {
  .offer-link { min-height: 44px; }
}

/* ── OPS-SHOPS (owner brief 2026-09-26): per-shop scan results under Üzemeltetés → Szkennelések. ── */
.ops-run-picker { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin: 10px 0; }
.ops-run-picker select { min-height: 36px; }
.ops-shop-reason summary { cursor: pointer; }
.ops-shop-reason summary::-webkit-details-marker { color: var(--text-2); }
.ops-shop-reason p { margin: 4px 0 0; }
@media (max-width: 600px) {
  .ops-run-picker select { min-height: 44px; }
}

/* ── boot skeleton (story UX-SHELL): static markup shipped inside #app in index.html — pure HTML/CSS, no JS —
   shown until Preact's first render replaces it (main.tsx clears #app right before mounting). Sized to match the
   real shell (sidebar width, top strip height, card height) so there is no layout shift when it is swapped out.
   Guarded by tests/ui/ux-shell.spec.ts. ── */
/* W2-TOKENS: every literal below is kept on purpose — it must match the real shell's geometry, not the token scale. */
.boot { display: flex; flex-direction: column; min-height: 100dvh; }
.boot-side { display: none; }
.boot-top .boot-mark { width: 32px; height: 32px; }
.boot-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; height: var(--topstrip-h); box-sizing: border-box; padding: env(safe-area-inset-top) var(--gutter) 0; border-bottom: 1px solid var(--line); }
.boot-brand { display: flex; align-items: center; gap: 8px; }
.boot-mark { width: 38px; height: 38px; border-radius: 9px; background: var(--bg-4); flex: none; }
.boot-bar { border-radius: 999px; background: var(--bg-3); position: relative; overflow: hidden; }
.boot-bar::after { content: ''; position: absolute; inset: 0; transform: translateX(-100%); background: linear-gradient(90deg, transparent, rgba(180, 188, 205, 0.14), transparent); animation: boot-shimmer 1.6s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .boot-bar::after { animation: none; } }
@keyframes boot-shimmer { to { transform: translateX(100%); } }
.boot-name { width: 96px; height: 14px; }
.boot-lang { width: 72px; height: 32px; border-radius: 10px; }
/* W2-POLISH (CLS): `.boot-main` now holds real Radar markup (.topbar/.searchbox, .lastupdate, .setchips.skeleton-row,
   .home-skeleton — see index.html) instead of its own boot-only shapes, so it keeps the Radar's own column layout
   and spacing (var(--sp-4) gap, matching `.view`'s) at every width — including desktop, where those same classes'
   own responsive rules (the 1024px `.grid`/`.pcard` breakpoints below) already reshape it correctly with no extra
   overrides needed here. */
.boot-main { flex: 1; display: flex; flex-direction: column; gap: var(--sp-4); padding: var(--sp-3) var(--gutter) 90px; box-sizing: border-box; }
@media (min-width: 1024px) {
  .boot { flex-direction: row; }
  .boot-top { display: none; }
  .boot-side { display: flex; flex-direction: column; gap: 8px; width: var(--side-w); flex: none; box-sizing: border-box; padding: 18px 12px; border-right: 1px solid var(--line); background: var(--bg-2); }
  .boot-side .boot-brand { padding: 6px 8px 18px; }
  .boot-navrow { height: 40px; border-radius: 10px; }
  .boot-main { padding-top: var(--sp-4); }
}

/* UX-HOME: the deal's size beside the merged verdict badge — plain text, not a second pill. */
.verdict-pct { font-size: var(--fs-sm); font-weight: 700; color: var(--green); font-variant-numeric: tabular-nums; margin-left: 6px; white-space: nowrap; }

/* ═══════════════ W2-CARDS — "on desktop the products are the show" (owner 2026-09-26: "Asztalin nagy kép, mobilon
   kompakt"). Phones keep the compact row defined in the "product cards" section above (thumbnail left, text right —
   density unchanged); from 1024 px the card turns image-first: the artwork is a 4:3 hero on a radial stage, then
   badges, a 2-line title, the meta line and the price block pinned to the bottom so prices line up across a row.
   Grid: 1 col < 640, 2 compact cols 640–1023, 3 image-first cols 1024–1439, 4 at 1440–1679, 5 at ≥ 1680 (content
   grows to 1520 px there — set on the Radar/Deals view, never on the shell's .main). Motion is "finom": the lift and
   the artwork zoom use --dur-base / --ease-standard and are removed under prefers-reduced-motion. ═══════════════ */

/* Keyboard focus: the title link is the card's one link and its ::after already covers the card (U02), so that
   overlay carries the ring too — the whole card reads as the focused target, not just the title text. */
.pcard-title-link:focus-visible::after { outline: 2px solid var(--gold); outline-offset: 2px; border-radius: var(--r); }

/* Loading placeholders: one card-shaped skeleton for the Radar and Deals (ProductCardSkeleton). `.home-skeleton`
   drops the generic `.skeleton` padding and gap — the real results container has neither. */
.home-skeleton { display: block; padding: 0; }
.sk-group-head { display: flex; align-items: center; height: calc(var(--fs-md) * var(--lh-normal)); }
.sk-badges { height: 20px; }
.sk-title { height: 16px; }
.sk-meta { height: 12px; }
.sk-price { height: 24px; margin-top: 6px; }
.sk-foot { height: 12px; }
.sk-shop { height: 14px; }

@media (min-width: 1024px) {
  .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4); }
  .pcard { display: flex; flex-direction: column; gap: 0; padding: 0; }
  /* The hero: full card width, 4:3, rounded top corners (card radius minus its 1 px border). The photo box is fixed
     from the first paint (no layout shift when it loads) and the photo is contained in it at its own aspect ratio,
     so tall booster boxes, wide collection boxes and square tins all float on the same stage; drop-shadow follows the
     painted photo, not the letterboxed box. */
  .pcard > .art {
    position: relative; width: 100%; height: auto; aspect-ratio: 4 / 3; border: 0; border-bottom: 1px solid var(--line);
    border-radius: calc(var(--r) - 1px) calc(var(--r) - 1px) 0 0;
    background: radial-gradient(70% 65% at 50% 42%, #2a3042 0%, var(--bg-3) 62%, var(--bg-2) 100%);
  }
  .pcard > .art img {
    position: absolute; inset: var(--sp-5); width: calc(100% - 2 * var(--sp-5)); height: calc(100% - 2 * var(--sp-5));
    object-fit: contain; padding: 0; background: none; filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.45)); /* = --shadow-md as a drop-shadow */
  }
  /* With a photo (C3): the hero becomes an inset rounded plate; no drop-shadow (it outlined the photo's white rectangle). */
  .pcard > .art.art-has-img {
    margin: var(--sp-3) var(--sp-3) 0; width: calc(100% - 2 * var(--sp-3)); border: 0; border-radius: 12px;
    background: radial-gradient(75% 70% at 50% 45%, #dcd7cb 0%, #cdc8bb 70%, #bfbaad 100%);
  }
  .pcard > .art.art-has-img img { filter: none; mix-blend-mode: multiply; }
  .pcard:hover > .art img, .pcard:focus-within > .art img { transform: scale(1.04); }
  /* No photo: the product-type initials, scaled up inside a quiet ring on the same stage — intentional, not broken. */
  .pcard > .art .art-fallback {
    display: grid; place-items: center; width: 40%; aspect-ratio: 1 / 1; border-radius: 50%;
    border: 1px solid var(--line-2); background: rgba(255, 255, 255, 0.03); box-shadow: inset 0 0 24px rgba(242, 192, 75, 0.06);
    font-size: var(--fs-2xl); color: var(--text-2); letter-spacing: 0.08em;
    transition: transform var(--dur-base) var(--ease-standard);
  }
  .pcard:hover > .art .art-fallback, .pcard:focus-within > .art .art-fallback { transform: scale(1.04); }
  .pcard-body { flex: 1 1 auto; padding: var(--sp-3) var(--sp-4) var(--sp-4); }
  .pcard-name { -webkit-line-clamp: 2; }
  /* Price block pinned to the bottom: grid rows stretch every card in a row to the same height, so prices align. */
  .pcard-offer { margin-top: auto; padding-top: var(--sp-1); }
  .pcard-price-row { flex-direction: column; align-items: flex-start; justify-content: flex-start; }
  /* The foot always reserves two lines (freshness, then the reference price), so a card without a reference line
     does not sit its price lower than its neighbours. */
  .pcard-foot { flex-direction: column; gap: 0; min-height: calc(2 * var(--fs-sm) * var(--lh-normal)); }
  .pcard-skeleton { min-height: 0; }
  .pcard-skeleton > .art { border-bottom-color: transparent; }
  .sk-badges { height: 21px; }
  .sk-title { height: 38px; }
  .sk-meta { height: 38px; }
  .sk-price { height: 50px; margin-top: 0; }
  .sk-foot { height: 38px; }
  .sk-shop { height: 28px; }
}
@media (min-width: 1440px) {
  .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (min-width: 1680px) {
  .grid { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .view-home, .view-deals { max-width: 1520px; }
}
/* W2-POLISH: a 6th grid column and a wider Radar/Deals measure at ≥2200px — see the frame's own note in the
   W2-MOTION block below, where the equivalent `.main` widening lives. */
@media (min-width: 2200px) {
  .grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .view-home, .view-deals { max-width: 1760px; }
}
/* Last in the block on purpose: it must win over the desktop zoom rules above (same specificity, so order decides).
   The global rule already zeroes the durations; this removes the movement itself (lift + artwork zoom). */
@media (prefers-reduced-motion: reduce) {
  .pcard:hover, .pcard:focus-within { transform: none; }
  .pcard:hover .art img, .pcard:focus-within .art img,
  .pcard:hover > .art .art-fallback, .pcard:focus-within > .art .art-fallback { transform: none; }
}

/* ═════════════════════ W2-MOTION — "finom" motion and a frame that fills big screens (story W2-MOTION) ═════════════════════
   Owner 2026-09-26: short 0.1–0.3 s transitions, nothing bouncy or long, everything off under prefers-reduced-motion.
   Every transition in this block is switched off by the global `*` kill rule near the top of this file; the two
   JS-driven motions (the route fade and the price count-up, src/web/lib/motion.ts) ask the media query themselves.
   Nothing here delays content or shifts layout: indicators are absolutely positioned and move by transform only. */

/* Sliding indicators — the sidebar's active row, the System subnav, the phone account menu, the Deals/Preorders
   segment row. One <span class="slide-ind"> per row, moved onto the active item by useSlidingIndicator (transform;
   width/height only change between differently sized tabs, on an out-of-flow element). The track gets .has-ind once
   the indicator is placed, which drops the item's own instant "on" background; without placement (hidden row,
   nothing active, no JS) the instant state is what shows. None of these rows wrap (the subnav scrolls sideways and
   the indicator scrolls with it), so no row needs the instant fallback on phones. */
.sidenav, .subnav, .segmentrow { position: relative; isolation: isolate; }
.slide-ind { position: absolute; top: 0; left: 0; z-index: -1; width: 0; height: 0; opacity: 0; pointer-events: none; border-radius: var(--r-sm); }
.slide-ind[data-anim] { transition: transform var(--dur-base) var(--ease-standard), width var(--dur-base) var(--ease-standard), height var(--dur-base) var(--ease-standard); }
.sidenav .slide-ind { background: linear-gradient(90deg, rgba(242, 192, 75, 0.14), transparent); box-shadow: inset 2px 0 0 var(--gold); }
.sidenav.has-ind .sidenav-item.on { background: transparent; box-shadow: none; }
.subnav .slide-ind { background: var(--bg-3); border-radius: 10px; }
.subnav.has-ind a.on { background: transparent; }
.segmentrow .slide-ind { border-radius: 999px; background: rgba(242, 192, 75, 0.14); box-shadow: inset 0 0 0 1px rgba(242, 192, 75, 0.5), inset 0 0 0 2px rgba(242, 192, 75, 0.3); }
/* The off chip turns see-through (≈ the same tone as --bg-3 on --bg) so the pill stays visible while it slides under it. */
.segmentrow.has-ind .chip { background: rgba(255, 255, 255, 0.035); }
.segmentrow.has-ind .chip-on { background: transparent; border-color: transparent; box-shadow: none; }

/* Micro-interaction: the phone tab bar's active icon grows a touch (1 → 1.08; transform, so nothing reflows). */
.bottomnav-item svg { transition: transform var(--dur-base) var(--ease-standard); }
.bottomnav-item.on svg { transform: scale(1.08); }

/* Wide desktop (≥ 1680 px): a wider sidebar with a slightly taller brand block, and the shell's content frame grows
   to 1520 px, centred in the space beside the sidebar — 1920 × 1080 reads as a designed frame, not a stretched 1440
   with a dead strip. The generic page frame (.view) follows the shell; the two reading pages keep their own measure
   (listed because this block sits after their rules). The boot skeleton mirrors the sidebar geometry (no shift). */
@media (min-width: 1680px) {
  :root { --side-w: 264px; }
  .sidebar { padding: 22px 14px; }
  .brand { gap: 12px; padding: 10px 8px; }
  .brand-mark { width: 42px; height: 42px; }
  .brand-text { font-size: 19px; }
  .main { max-width: calc(1520px + 2 * var(--gutter)); margin-left: auto; margin-right: auto; }
  .view:where(:not(.privacy-page, .pro-page)) { max-width: none; }
  .boot-side { padding: 22px 14px; }
  .boot-side .boot-brand { gap: 12px; padding: 10px 8px 18px; }
  .boot-side .boot-mark { width: 42px; height: 42px; border-radius: 10px; }
}
/* W2-POLISH (2560+): the 1520px frame still left ~388px gutters either side at 2560×1440 (≈15.2% of the viewport,
   just over the 15% guideline this file's own 1680px test holds everything else to), and its 5-column Radar/Deals
   grid wrapped a 6th deal alone onto an otherwise-empty second row. Screenshot comparison (scratchpad, 2026-09-26)
   on /deals with 6 live deals: the 5-col/1520px frame wraps that 6th card onto a near-empty row; the 6-col/1760px
   frame fits all six on one line and reads as a deliberate step, not a stretch — so it ships, widening `.main` for
   every page (the same relationship the 1680px step already has) and the grid for Radar/Deals specifically.
   Gutters drop from ≈388px (≈15.2%) to ≈240px (≈9.4%). */
@media (min-width: 2200px) {
  .main { max-width: calc(1760px + 2 * var(--gutter)); }
}

/* Boot-skeleton sizes as classes, never style="" — the CSP (style-src 'self', no unsafe-inline) drops inline style
   attributes in static HTML (isolated verifier, W2-POLISH). Values mirror the JS-rendered skeleton. */
.sk-boot-lastupdate { width: 140px; height: 11px; }
.sk-boot-grouphead { width: 120px; height: 14px; }
.skw-40 { width: 40%; } .skw-45 { width: 45%; } .skw-60 { width: 60%; } .skw-70 { width: 70%; } .skw-85 { width: 85%; }

/* ───────────────────────── Brand: holo radar card + foil wordmark (owner 2026-09-27) ─────────────────────────
   Static first: everything below reads well with no motion at all. Motion lives only inside the no-preference block,
   so "reduce motion" users get the finished, still logo. Auto motion ends within ~3.5 s of first paint (WCAG 2.2.2);
   after that the mark moves only on hover / keyboard focus and once per newly published price snapshot (.is-pinging). */
.bm-svg { width: 100%; height: 100%; display: block; overflow: visible; filter: drop-shadow(0 4px 12px rgba(242, 192, 75, 0.32)) drop-shadow(0 0 1px rgba(255, 255, 255, 0.25)); }
.bm-sweep { transform-box: view-box; transform-origin: 24px 25px; }
.bm-sheen { mix-blend-mode: screen; }
.bm-ping { opacity: 0; transform-box: fill-box; transform-origin: center; }
.bm-blip { filter: drop-shadow(0 0 1.6px #ffe27a); }
.bm-glare { opacity: 0; }
.bm-spark { transform-box: fill-box; transform-origin: center; opacity: 0.9; }
.bw { display: inline-flex; align-items: baseline; gap: 0.28em; letter-spacing: -0.015em; white-space: nowrap; }
.bw-tcg {
  font-weight: 900; background: linear-gradient(100deg, #f2c04b 0%, #ffe9a8 18%, #ff8fbf 38%, #7ad0ff 62%, #a6ff9c 82%, #f2c04b 100%);
  background-size: 220% 100%; background-position: 0% 50%; -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 1px 6px rgba(242, 192, 75, 0.28));
}
.bw-radar { font-weight: 800; color: var(--text); }

@media (prefers-reduced-motion: no-preference) {
  /* First paint: the card flips in like a card dealt onto the table, the foil catches the light, the radar sweeps. */
  /* The 3D moves go on the wrapper, the glow filter stays on the SVG: a filter on the 3D-transformed element itself
     is rasterised once and scaled, which blurs the vector edges on hover. */
  .brand-mark { transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1); }
  .bm-svg { transition: filter 0.35s ease; }
  .brand-mark.is-intro { animation: bm-deal 0.75s var(--ease-out, cubic-bezier(0.2, 0.8, 0.2, 1)) backwards; }
  .brand-mark.is-intro .bm-glare { animation: bm-glare 0.9s ease-out 0.45s 1 both; }
  .brand-mark.is-intro .bm-sweep { animation: bm-sweep 1.3s linear 0.55s 2 both; }
  .brand-mark.is-intro .bm-ping { animation: bm-ping 1.3s ease-out 1.05s 2 both; }
  .brand-mark.is-intro .bm-spark { animation: bm-spark 0.9s ease-in-out 1.6s 1 both; }
  .bw.is-intro .bw-tcg { animation: bw-shine 1.8s ease-in-out 0.3s 1 both; }

  /* Hover / keyboard focus: the card is picked up (a springy lift — 2D, so the vector stays sharp; a 3D tilt
     rasterised blurry in Chromium), the foil flashes, the radar takes one more turn. */
  .brand:hover .brand-mark, .brand:focus-visible .brand-mark, .topstrip-brand:hover .brand-mark, .topstrip-brand:focus-visible .brand-mark {
    transform: translateY(-2px) rotate(7deg) scale(1.08);
  }
  .brand:hover .bm-svg, .brand:focus-visible .bm-svg, .topstrip-brand:hover .bm-svg, .topstrip-brand:focus-visible .bm-svg {
    filter: drop-shadow(0 8px 18px rgba(242, 192, 75, 0.5)) drop-shadow(0 0 2px rgba(255, 255, 255, 0.35));
  }
  .brand:hover .bm-glare, .brand:focus-visible .bm-glare, .topstrip-brand:hover .bm-glare, .topstrip-brand:focus-visible .bm-glare { animation: bm-glare-hover 0.8s ease-out 1 both; }
  .brand:hover .bm-sweep, .brand:focus-visible .bm-sweep, .topstrip-brand:hover .bm-sweep, .topstrip-brand:focus-visible .bm-sweep { animation: bm-sweep-hover 1.1s linear 1 both; }
  .brand:hover .bw-tcg, .brand:focus-visible .bw-tcg, .topstrip-brand:hover .bw-tcg, .topstrip-brand:focus-visible .bw-tcg { animation: bw-shine-hover 1.2s ease-in-out 1 both; }

  /* Fresh prices just landed: one sweep and a double ping. */
  .brand-mark.is-pinging .bm-sweep { animation: bm-sweep-hover 1.1s linear 1 both; }
  .brand-mark.is-pinging .bm-ping { animation: bm-ping-again 1.2s ease-out 0.2s 2 both; }
}
@keyframes bm-deal {
  0% { transform: perspective(220px) rotateY(-100deg) rotateZ(-12deg) scale(0.55); opacity: 0; }
  55% { transform: perspective(220px) rotateY(14deg) rotateZ(3deg) scale(1.08); opacity: 1; }
  80% { transform: perspective(220px) rotateY(-5deg) rotateZ(-1deg) scale(0.98); }
  100% { transform: none; opacity: 1; }
}
@keyframes bm-glare { from { opacity: 1; transform: skewX(-20deg) translateX(0); } to { opacity: 1; transform: skewX(-20deg) translateX(72px); } }
@keyframes bm-glare-hover { from { opacity: 1; transform: skewX(-20deg) translateX(0); } to { opacity: 1; transform: skewX(-20deg) translateX(72px); } }
@keyframes bm-sweep { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes bm-sweep-hover { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes bm-ping { 0% { opacity: 0.95; transform: scale(1); } 100% { opacity: 0; transform: scale(3.6); } }
@keyframes bm-ping-again { 0% { opacity: 0.95; transform: scale(1); } 100% { opacity: 0; transform: scale(3.6); } }
@keyframes bm-spark { 0% { transform: scale(0.9) rotate(0deg); opacity: 0.9; } 45% { transform: scale(1.9) rotate(45deg); opacity: 1; } 100% { transform: scale(0.9) rotate(90deg); opacity: 0.9; } }
@keyframes bw-shine { from { background-position: 100% 50%; } to { background-position: 0% 50%; } }
@keyframes bw-shine-hover { from { background-position: 100% 50%; } to { background-position: 0% 50%; } }

/* Legal pages and the phone/tablet legal footer (go-live B3, 2026-09-27). The desktop sidebar footer carries the same
   links, so the footer under the content only shows below 1024px. */
.legal-facts { display: grid; gap: var(--sp-3); margin: 0 0 var(--sp-3); }
.legal-facts dt { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); }
.legal-facts dd { margin: 2px 0 0; overflow-wrap: anywhere; }
.site-foot { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); justify-content: center; padding: var(--sp-5) var(--gutter) var(--sp-3); font-size: var(--fs-sm); }
.site-foot a { color: var(--muted); display: inline-flex; align-items: center; min-height: 44px; }
.site-foot a:hover { color: var(--text); }
@media (min-width: 1024px) { .site-foot { display: none; } }

/* Support entry 2 of 2 (SUPPORT-HOME): the block at the end of the radar list — a hairline separator, no box (support-block.tsx). */
.supportblock { margin-top: var(--sp-8); margin-bottom: var(--sp-4); padding: var(--sp-4) 0 0; border-top: 1px solid var(--line); max-width: 720px; display: grid; gap: var(--sp-2); }
.supportblock-main { display: grid; gap: var(--sp-3); justify-items: start; }
.supportblock .h2 { margin: 0; }
.supportblock-lead { margin: 0; color: var(--text-2); font-size: var(--fs-md); line-height: 1.5; }
.supportblock .btn { width: 100%; justify-content: center; }
.supportblock-more summary { list-style: none; cursor: pointer; }
.supportblock-more summary::-webkit-details-marker { display: none; }
.supportblock-more summary::before { content: '▸'; display: inline-block; transition: transform var(--dur-fast, .15s); }
.supportblock-more[open] summary::before { transform: rotate(90deg); }
.supportblock-more[open] summary { color: var(--gold-2); }
.supportblock-list { list-style: disc; margin: 0 0 var(--sp-2); padding-left: 1.4em; color: var(--text-2); display: grid; gap: var(--sp-2); line-height: 1.45; }
@media (min-width: 1024px) {
  .supportblock { grid-template-columns: 1fr 1fr; column-gap: var(--sp-6, 24px); align-items: start; }
  .supportblock .btn { width: auto; }
}
.supportblock-list li::marker { color: var(--gold); }

/* Support entry 1 of 2 (SUPPORT-HOME): the quiet link in the update line. The no-wrap guarantee is structural, whatever font
   is on screen at any paint: the link is the ONLY part of the row that gives way (it shrinks and truncates with an ellipsis),
   and the age/status text keeps its natural one-line width (it wraps only if it alone is wider than the row — exactly as
   without a link). The script in shell.tsx only chooses the nicest label (full, short, none). */
.lastupdate-pro { display: block; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; margin: -14px 0 -14px var(--sp-2); padding: 14px 0; /* 44 px touch target, zero layout height */ color: var(--gold-2); font-weight: 700; white-space: nowrap; text-decoration: none; }
.lastupdate-pro:hover { text-decoration: underline; }
.lastupdate-linked .lastupdate-age { flex: 0 0 auto; max-width: calc(100% - 8px - 3 * var(--sp-2)); /* the dot, the gaps, the link's margin */ }

/* ───────────── Analytics slice 2 (owner 2026-10-01): System → Statisztika ─────────────
   Chart marks use two validated data colors (OKLCH L 0.48–0.67 on the dark surface, CVD ΔE ≥ 22 — dataviz validator,
   2026-10-02); text stays in text tokens. Each daily chart has one axis; the previous period is a muted dashed line. */
:root { --st-views: #c08a1e; --st-clicks: #3d8ad6; }
@media (max-width: 767px) {
  .sysnav-7 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .sysnav-7 a { font-size: var(--fs-sm); padding-left: 2px; padding-right: 2px; overflow-wrap: normal; word-break: keep-all; hyphens: none; }
}
.stats .h3 { font-size: var(--fs-md); font-weight: 800; color: var(--text); margin: 0; }
.stats .h4 { font-size: var(--fs-sm); font-weight: 700; color: var(--text-2); margin: 0 0 var(--sp-2); }
.stats-head { display: flex; justify-content: space-between; align-items: flex-end; gap: var(--sp-3) var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-4); }
.stats-head .h2 { margin: 0 0 2px; font-size: var(--fs-xl); color: var(--text); }
.stats-head p { margin: 0; max-width: 60ch; }
.stats-controls { display: flex; align-items: center; gap: var(--sp-2) var(--sp-4); flex-wrap: wrap; }
.stats-chips { display: inline-flex; gap: var(--sp-2); }
.stats-chips .chip { min-height: 40px; padding: 0 var(--sp-4); cursor: pointer; }
.stats-compare { display: inline-flex; align-items: center; gap: var(--sp-2); min-height: 44px; font-size: var(--fs-sm); font-weight: 600; color: var(--text-2); cursor: pointer; }
.stats-compare input { width: 18px; height: 18px; accent-color: var(--gold); }
.stats-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); }
.stats-grid > .panel, .stats-grid > .stats-kpis, .stats-grid > .stats-foot { min-width: 0; }
.stats-insights, .stats-kpis, .stats-locked, .stats-trends, .stats-products, .stats-foot { grid-column: 1 / -1; }
.stats .panel { padding: var(--sp-4) var(--sp-5); }
.stats .panel-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-3); flex-wrap: wrap; }
.stats-insights { position: relative; overflow: hidden; border-color: rgba(242, 192, 75, 0.28); background: linear-gradient(180deg, rgba(242, 192, 75, 0.07), rgba(242, 192, 75, 0) 60%), var(--bg-2); }
.stats-insights::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--gold); }
.stats-insight-list { margin: 0; padding-left: 1.1em; display: grid; gap: var(--sp-2); font-size: var(--fs-md); line-height: 1.5; color: var(--text); }
.stats-kpis { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--sp-3); }
.stats .kpi { background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--r); padding: var(--sp-4) var(--sp-4) 0; display: flex; flex-direction: column; min-width: 0; overflow: hidden; }
.stats .kpi-hero { border-color: rgba(242, 192, 75, 0.4); box-shadow: 0 0 0 1px rgba(242, 192, 75, 0.1), 0 10px 34px -12px rgba(242, 192, 75, 0.28); }
.stats .kpi-label { font-size: var(--fs-sm); font-weight: 700; color: var(--text-2); min-height: 2.6em; line-height: 1.3; }
.stats .kpi-main { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; margin-top: 4px; }
.stats .kpi-value { font-size: 30px; font-weight: 800; letter-spacing: -0.03em; line-height: 1.1; color: var(--text); font-variant-numeric: tabular-nums; }
.stats .kpi-hero .kpi-value { color: var(--gold-2); }
.stats .delta { display: inline-flex; align-items: center; gap: 4px; height: 24px; padding: 0 8px; border-radius: 999px; font-size: var(--fs-sm); font-weight: 800; border: 1px solid; white-space: nowrap; }
.stats .delta-good { color: #7fe7b6; background: rgba(53, 211, 143, 0.12); border-color: rgba(53, 211, 143, 0.5); }
.stats .delta-bad { color: #ff9aa2; background: rgba(240, 97, 107, 0.12); border-color: rgba(240, 97, 107, 0.65); }
.stats .delta-flat { color: var(--text-2); background: var(--bg-3); border-color: var(--line-2); }
.stats .kpi-prev { min-height: 20px; margin: 6px 0 10px; font-size: var(--fs-sm); color: var(--muted); }
.stats .spark { display: block; width: calc(100% + 2 * var(--sp-4)); margin: auto calc(-1 * var(--sp-4)) 0; height: 40px; flex: none; }
.stats .spark-empty { height: 40px; }
.stats-locked { font-size: var(--fs-sm); color: var(--text-2); background: var(--bg-2); border-style: dashed; }
.stats-legend { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-sm); color: var(--text-2); }
.stats-legend .lg-cur { width: 12px; height: 10px; border-radius: 3px; background: linear-gradient(90deg, var(--st-views) 50%, var(--st-clicks) 50%); display: inline-block; }
.stats-legend .lg-prev { width: 16px; height: 0; border-top: 2px dashed var(--muted); display: inline-block; margin-left: var(--sp-2); }
.stats-chart { margin: 0 0 var(--sp-4); }
.stats-chart-title { font-size: var(--fs-sm); font-weight: 700; color: var(--text-2); margin-bottom: 4px; }
.stats-chart-box { position: relative; }
.stats-chart svg { display: block; max-width: 100%; overflow: visible; }
.stats-chart .grid { stroke: var(--line); stroke-width: 1; }
.stats-chart .axis { fill: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.stats-chart .unmeasured { fill: rgba(255, 255, 255, 0.05); }
.stats-chart .unmeasured-label { font-size: 12px; font-style: italic; }
.stats-table .unmeasured-row td { text-align: left; font-style: italic; }
.stats-chart .prevline { stroke: var(--muted); stroke-width: 2; stroke-dasharray: 5 4; vector-effect: non-scaling-stroke; }
.stats-tip { position: absolute; top: 0; transform: translateX(-50%); display: grid; gap: 2px; padding: 6px 10px; border-radius: var(--r-xs); background: var(--bg-4); border: 1px solid var(--line-2); box-shadow: var(--shadow-sm); font-size: var(--fs-sm); white-space: nowrap; pointer-events: none; z-index: 2; }
.stats-table summary { cursor: pointer; font-size: var(--fs-sm); font-weight: 700; color: var(--text-2); min-height: 44px; display: flex; align-items: center; }
.stats-table table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.stats-table th, .stats-table td { padding: 6px 8px; border-bottom: 1px solid var(--line); text-align: right; white-space: nowrap; }
.stats-table thead th { white-space: normal; vertical-align: bottom; }
.stats-table th:last-child, .stats-table td:last-child { padding-right: 12px; }
.stats-table th:first-child, .stats-table thead th:first-child { text-align: left; }
.stats-rows { list-style: none; margin: 0; padding: 0; }
.stats-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: 'r n v' 'b b b'; gap: 4px var(--sp-3); align-items: baseline; padding: 8px 0 10px; border-bottom: 1px solid rgba(36, 42, 58, 0.7); }
.stats-row:last-child { border-bottom: 0; }
.stats-row .rank { grid-area: r; color: var(--muted); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; min-width: 1.2em; }
.stats-row .name { grid-area: n; font-weight: 700; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stats-row .val { grid-area: v; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap; }
.stats-row .bar { grid-area: b; }
.stats-row:not(:has(.rank)) { grid-template-areas: 'n n v' 'b b b'; }
.stats .bar { display: block; height: 8px; border-radius: 999px; background: var(--bg-4); overflow: hidden; }
.stats .bar i { display: block; height: 100%; border-radius: 999px; background: var(--st-views); min-width: 2px; }
.stats .bar-blue i { background: var(--st-clicks); }
.stats-two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-5); }
.stats-plist { list-style: none; margin: 0; padding: 0; }
.stats-prow { display: grid; gap: 2px; padding: 8px 0; border-bottom: 1px solid rgba(36, 42, 58, 0.7); }
.stats-prow:last-child { border-bottom: 0; }
.stats-prow .name { font-weight: 700; color: var(--text); text-decoration: none; overflow-wrap: anywhere; }
.stats-prow .name:hover { color: var(--gold-2); }
.stats-prow .val { color: var(--text-2); font-variant-numeric: tabular-nums; }
.stats-foot { padding: var(--sp-2) 0 0; }
.stats-foot .dq { display: flex; gap: 4px 18px; flex-wrap: wrap; font-weight: 700; color: var(--text); margin: 0 0 4px; }
.stats-foot p { max-width: 90ch; }
.stats-empty p { margin: 0; color: var(--text-2); }
@media (max-width: 1100px) { .stats-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 767px) {
  .stats-grid { grid-template-columns: minmax(0, 1fr); gap: var(--sp-3); }
  .stats .panel { padding: var(--sp-3) var(--sp-4); }
  .stats-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); }
  .stats .kpi { padding: var(--sp-3) var(--sp-3) 0; }
  .stats .kpi-value { font-size: 24px; }
  .stats .spark { width: calc(100% + 2 * var(--sp-3)); margin: auto calc(-1 * var(--sp-3)) 0; height: 34px; }
  .stats-controls, .stats-chips { width: 100%; }
  .stats-chips { display: grid; grid-template-columns: repeat(4, 1fr); }
  .stats-chips .chip { justify-content: center; padding: 0 4px; }
  .stats-two { grid-template-columns: minmax(0, 1fr); gap: var(--sp-3); }
}
.stats-kpis-note { grid-column: 1 / -1; margin: 0 0 calc(-1 * var(--sp-1)); }

/* ── App Store download on the website (owner 2026-10-04; components/app-download.tsx) ──
   Phone/tablet: a closable card at the end of the radar list. Desktop: a small QR card at the foot of the sidebar
   (the home card is hidden there — the sidebar already offers it). Never rendered in the apps or on Android. */
.appdl-card { position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-3) 14px; align-items: center; margin-top: var(--sp-8); padding: var(--sp-4); max-width: 720px; border-radius: var(--r); border: 1px solid rgba(242, 192, 75, 0.32); background: radial-gradient(120% 140% at 0% 0%, rgba(242, 192, 75, 0.14), rgba(242, 192, 75, 0) 55%), var(--bg-2); overflow: hidden; }
.appdl-card::before, .appdl-side::before { content: ''; position: absolute; inset: 0 auto 0 0; width: 3px; background: var(--foil, var(--gold)); }
.appdl-icon { width: 64px; height: 64px; border-radius: 15px; box-shadow: 0 8px 22px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.06); }
.appdl-text { min-width: 0; padding-right: 28px; }
.appdl-title { margin: 0 0 4px; font-size: var(--fs-lg, 16px); font-weight: 800; }
.appdl-lead { margin: 0; font-size: var(--fs-sm, 13px); line-height: 1.45; color: var(--text-2); }
.appdl-row { grid-column: 1 / -1; display: flex; align-items: center; }
.appdl-close { position: absolute; right: 4px; top: 4px; width: 44px; height: 44px; display: grid; place-items: center; border: 0; background: none; color: var(--muted); border-radius: 999px; cursor: pointer; }
.appdl-close:hover { color: var(--text); background: var(--bg-3); }
.appdl-badge { display: inline-flex; border-radius: 9px; line-height: 0; }
.appdl-badge img { height: 40px; width: auto; display: block; }
.appdl-side { position: relative; flex-shrink: 0; margin: var(--sp-3) 0; padding: var(--sp-3); border-radius: var(--r); border: 1px solid rgba(242, 192, 75, 0.3); background: radial-gradient(120% 120% at 0% 0%, rgba(242, 192, 75, 0.12), rgba(242, 192, 75, 0) 60%), var(--bg-2); overflow: hidden; display: grid; gap: var(--sp-2); justify-items: center; }
.appdl-side-head { display: flex; gap: 10px; align-items: center; justify-self: stretch; }
.appdl-side-head img { width: 36px; height: 36px; border-radius: 9px; }
.appdl-side-title { margin: 0; font-size: var(--fs-md, 14px); font-weight: 800; line-height: 1.25; }
@media (min-width: 1024px) { .appdl-card { display: none; } }
/* Desktop toolbar button (UX option A, owner 2026-10-04): the toolbar's one coloured control, same 44 px height as
   "Szűrők"; the QR popover opens on hover or keyboard focus and is decorative (the link works without it). */
.appdl-top-wrap { display: none; position: relative; flex: 0 0 auto; }
@media (min-width: 1024px) { .appdl-top-wrap { display: block; } }
.appdl-top { display: inline-flex; align-items: center; gap: 9px; height: 44px; padding: 0 14px 0 8px; border-radius: var(--r); border: 1px solid rgba(242, 192, 75, 0.45); background: linear-gradient(180deg, rgba(242, 192, 75, 0.14), rgba(242, 192, 75, 0.04)), var(--bg-2); color: var(--text); text-decoration: none; white-space: nowrap; }
.appdl-top:hover, .appdl-top:focus-visible { border-color: var(--gold); box-shadow: 0 0 0 1px rgba(242, 192, 75, 0.25), 0 8px 26px -10px rgba(242, 192, 75, 0.45); }
.appdl-top img { width: 28px; height: 28px; border-radius: 7px; }
.appdl-top-text { display: grid; line-height: 1.15; }
.appdl-top-l1 { font-size: var(--fs-sm, 13px); font-weight: 800; }
.appdl-top-l2 { font-size: var(--fs-xs, 12px); color: var(--gold-2, var(--gold)); font-weight: 700; }
.appdl-pop { position: absolute; right: 0; top: calc(100% + 8px); z-index: 30; width: 210px; padding: 14px; border-radius: var(--r); border: 1px solid rgba(242, 192, 75, 0.35); background: var(--bg-2); box-shadow: 0 18px 48px -12px rgba(0, 0, 0, 0.7); display: grid; justify-items: center; gap: 10px; opacity: 0; visibility: hidden; transform: translateY(-4px); transition: opacity .15s, transform .15s, visibility .15s; }
.appdl-top-wrap:hover .appdl-pop, .appdl-top-wrap:focus-within .appdl-pop { opacity: 1; visibility: visible; transform: none; }
.appdl-qr { width: 150px; height: 150px; border-radius: 10px; background: #fff; padding: 6px; box-sizing: border-box; }
.appdl-scan { margin: 0; font-size: var(--fs-xs, 12px); line-height: 1.4; color: var(--text-2); text-align: center; }
@media (prefers-reduced-motion: reduce) { .appdl-pop { transition: none; } }

/* iOS (Safari and the iOS app's WKWebView) zooms the whole page into any text field whose font is under 16 px when it
   is focused, and stays zoomed: the watch sheet's 15 px price field blew the layout past the screen edge — close
   button, Save and the HU/EN switch cut off, the sheet collapsing under the keyboard (owner, iOS app, 2026-10-07).
   Touch screens get 16 px fields; placed last and more specific than `.watch-field input` & co., so it wins. */
@media (pointer: coarse) {
  input:not([type='checkbox']):not([type='radio']):not([type='range']), select, textarea { font-size: 16px; }
}
