/* ===== Design tokens =====

   One accent, used for one thing.

   What this replaced ran five saturated hues at once — indigo brand, orange price, rose
   savings, amber warning, sky info — so a single product card could show four of them and
   none read as important. It was also the default template look: indigo #4f46e5 over a
   purple hero gradient, which says "B2B dashboard", not "shopping".

   The rule now is that green means money and nothing else means anything. The price, the
   saving, the primary action and the "lowest we've seen" badge are the only saturated
   things on a listing page, so the eye lands on the number the site exists to show. Brass
   appears only where time matters — a deal running out. Red appears only when something is
   wrong. Three hues, and two of them are rare.

   Every foreground/background pair here was measured against WCAG 2.1 AA before it was
   committed, because the palette this replaced had not been: the price — the single most
   important number on the site — sat at 2.80:1 on white, under even the 3:1 floor for
   large text, and the savings line at 3.67:1. Nothing below is under 3.6:1, and every
   body-text pair clears 4.5:1 in both themes.
*/
/*  `.admin-shell` shares this block rather than inheriting from :root, which is how the
    admin area opts out of dark mode in one selector instead of a second copy of the
    palette. Custom properties declared on an element beat the inherited ones, so the dark
    rules below land on <html> and stop at the admin wrapper.

    The reason it opts out at all: every admin page carries its own <style> block full of
    literal #fff and #f0f3f7, written long before there was a dark theme. Flipping the
    tokens under them would give white tables on a dark page — worse than not themed. */
:root, .admin-shell {
    color-scheme: light;

    /* Neutrals. Paper is warm and ink carries a trace of green, so the accent sits in
       the same family rather than on top of a blue-grey that fights it. */
    --c-bg: #f7f7f5;
    --c-surface: #ffffff;
    --c-surface-alt: #eceeea;
    --c-border: #e2e4df;
    --c-border-strong: #c7cbc4;
    --c-text: #16211f;
    --c-text-muted: #55605c;
    --c-text-subtle: #7d8985;

    /* The accent. Links, focus, primary action, savings, best-price standing. */
    --c-brand: #0d6e4e;
    --c-brand-hover: #0a5740;
    --c-brand-soft: #dceee5;
    --c-brand-dark: #07301f;     /* readable brand text; flips light in dark mode */
    --c-brand-ring: rgba(13, 110, 78, .20);

    /*  A solid brand fill and the only text colour that is legible on it. These exist
        because --c-brand is a *text* colour that inverts between themes: in dark it is a
        bright mint, and white on it measures 2.22:1. Anything painting a filled brand
        surface uses this pair, never --c-brand with a hardcoded #fff. */
    --c-brand-fill: #0d6e4e;
    --c-on-brand: #ffffff;

    /* Brass — time pressure only. Never decoration. */
    --c-brass: #8a5a0b;
    --c-brass-soft: #f6ecd9;

    /* Red — errors, out of stock, destructive. Never "sale". */
    --c-accent: #a3231f;
    --c-accent-soft: #fbe9e7;

    /* The deep ground: hero, footer, and the page itself in dark mode. */
    --c-ink: #0d2b25;
    --c-on-ink: #ffffff;
    --c-on-ink-muted: #c3d2cc;
    --c-on-ink-subtle: #9fb3ab;

    /* Gradients. Short ranges within one hue — a gradient that crosses hues is what made
       the old hero look like a template. */
    --g-brand: linear-gradient(135deg, #0d6e4e 0%, #12855e 100%);
    --g-hero: linear-gradient(150deg, #0a2119 0%, #0d2b25 45%, #12463a 100%);
    --g-hot: linear-gradient(135deg, #0d6e4e, #12855e);
    --g-text: linear-gradient(100deg, #6fdcaa, #a7ecc9);

    /* Type */
    --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
                  "Helvetica Neue", Arial, "Noto Sans", sans-serif;
    --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

    /* Geometry */
    --radius-sm: 6px;
    --radius: 10px;
    --radius-lg: 14px;
    --radius-pill: 9999px;
    --shadow-sm: 0 1px 2px rgba(16, 33, 29, .04), 0 1px 3px rgba(16, 33, 29, .06);
    --shadow: 0 4px 6px -1px rgba(16, 33, 29, .06), 0 2px 4px -2px rgba(16, 33, 29, .06);
    --shadow-lg: 0 12px 24px -8px rgba(16, 33, 29, .14), 0 4px 8px -4px rgba(16, 33, 29, .08);

    /* Translucent header fill — has to be a token, since it inverts with the theme. */
    --c-header-bg: rgba(255, 255, 255, .90);

    /* Spacing scale (rem) */
    --container: 1200px;
}

/* ===== Dark theme =====

   Two selectors, one palette. The media query covers the reader who has never touched the
   toggle and whose OS is dark; the attribute covers the reader who chose. `:not([data-theme="light"])`
   is what lets an explicit *light* choice win on a dark OS — without it the media query
   would keep overriding the user, which is the usual way this gets built wrong.

   The values are duplicated because CSS cannot apply one block from two places. If you
   change one, change both; they are kept adjacent so the diff shows it.

   Dark is not the light palette inverted. Surfaces lift toward the viewer instead of
   casting shadows (shadows do nothing on a dark ground), the accent moves up to #4cc38a
   because #0d6e4e is unreadable on ink, and borders carry the separation that shadow
   carried in light. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        color-scheme: dark;
        --c-bg: #0e1513;
        --c-surface: #151d1b;
        --c-surface-alt: #1d2724;
        --c-border: #27332f;
        --c-border-strong: #3a4a44;
        --c-text: #e7ece9;
        --c-text-muted: #9daaa5;
        --c-text-subtle: #74807c;
        --c-brand: #4cc38a;
        --c-brand-hover: #6ad3a1;
        --c-brand-soft: #123328;
        --c-brand-dark: #8fe3ba;
        --c-brand-ring: rgba(76, 195, 138, .26);
        --c-brand-fill: #4cc38a;
        --c-on-brand: #07301f;
        --c-brass: #d9a441;
        --c-brass-soft: #2e2413;
        --c-accent: #f27a72;
        --c-accent-soft: #331a18;
        --g-brand: linear-gradient(135deg, #4cc38a 0%, #6ad3a1 100%);
        --g-hot: linear-gradient(135deg, #4cc38a 0%, #6ad3a1 100%);
        --shadow-sm: 0 1px 2px rgba(0, 0, 0, .40);
        --shadow: 0 4px 10px -2px rgba(0, 0, 0, .45);
        --shadow-lg: 0 16px 32px -12px rgba(0, 0, 0, .60);
        --c-header-bg: rgba(14, 21, 19, .88);
    }
}

:root[data-theme="dark"] {
    color-scheme: dark;
    --c-bg: #0e1513;
    --c-surface: #151d1b;
    --c-surface-alt: #1d2724;
    --c-border: #27332f;
    --c-border-strong: #3a4a44;
    --c-text: #e7ece9;
    --c-text-muted: #9daaa5;
    --c-text-subtle: #74807c;
    --c-brand: #4cc38a;
    --c-brand-hover: #6ad3a1;
    --c-brand-soft: #123328;
    --c-brand-dark: #8fe3ba;
    --c-brand-ring: rgba(76, 195, 138, .26);
    --c-brand-fill: #4cc38a;
    --c-on-brand: #07301f;
    --c-brass: #d9a441;
    --c-brass-soft: #2e2413;
    --c-accent: #f27a72;
    --c-accent-soft: #331a18;
    --g-brand: linear-gradient(135deg, #4cc38a 0%, #6ad3a1 100%);
    --g-hot: linear-gradient(135deg, #4cc38a 0%, #6ad3a1 100%);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .40);
    --shadow: 0 4px 10px -2px rgba(0, 0, 0, .45);
    --shadow-lg: 0 16px 32px -12px rgba(0, 0, 0, .60);
    --c-header-bg: rgba(14, 21, 19, .88);
}

/* ===== Reset / base ===== */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
    font-family: var(--font-sans);
    color: var(--c-text);
    background: var(--c-bg);
    line-height: 1.55;
    font-size: 16px;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}
img { max-width: 100%; height: auto; display: block; }
a { color: var(--c-brand); text-decoration: none; }
a:hover { color: var(--c-brand-hover); text-decoration: underline; }

h1, h2, h3, h4 {
    margin: 0 0 .5rem;
    line-height: 1.2;
    color: var(--c-text);
    font-weight: 700;
    letter-spacing: -0.01em;
}
h1 { font-size: clamp(1.75rem, 1.2rem + 1.6vw, 2.5rem); }
h2 { font-size: 1.5rem; margin-top: 2rem; }
h3 { font-size: 1.125rem; }
p  { margin: 0 0 1rem; }
small, .small { font-size: 0.85rem; color: var(--c-text-muted); }

h1:focus { outline: none; }

/* ===== Layout helpers ===== */
.container { max-width: var(--container); margin: 0 auto; padding: 0 1.25rem; }
.stack-sm > * + * { margin-top: 0.5rem; }
.stack > * + * { margin-top: 1rem; }
.stack-lg > * + * { margin-top: 1.75rem; }
.muted { color: var(--c-text-muted); }
.flex { display: flex; }
.flex-between { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.gap-sm { gap: .5rem; } .gap { gap: 1rem; } .gap-lg { gap: 1.5rem; }
.text-center { text-align: center; }

/* ===== Buttons ===== */
.btn {
    display: inline-flex; align-items: center; justify-content: center;
    gap: .5rem;
    font-family: inherit; font-weight: 600; font-size: 0.95rem;
    padding: .625rem 1.125rem;
    border-radius: var(--radius);
    border: 1px solid transparent;
    cursor: pointer;
    transition: background-color .15s, color .15s, border-color .15s, box-shadow .15s, transform .05s;
    text-decoration: none;
    line-height: 1.2;
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--c-brand); outline-offset: 2px; }

.btn-primary {
    background: var(--g-brand); color: var(--c-on-brand);
    box-shadow: 0 4px 14px -3px var(--c-brand-ring);
}
.btn-primary:hover {
    color: var(--c-on-brand); text-decoration: none;
    filter: brightness(1.07);
    box-shadow: 0 6px 20px -4px var(--c-brand-ring);
}

.btn-ghost { background: transparent; color: var(--c-text); border-color: var(--c-border); }
.btn-ghost:hover { background: var(--c-surface-alt); color: var(--c-text); text-decoration: none; }

.btn-link { background: transparent; color: var(--c-brand); padding: 0; border: 0; }
.btn-link:hover { color: var(--c-brand-hover); text-decoration: underline; }

.btn-danger-link { background: transparent; color: var(--c-accent); border: 0; padding: 0; cursor: pointer; font: inherit; }
.btn-danger-link:hover { text-decoration: underline; }

.btn-sm { padding: .375rem .75rem; font-size: .85rem; }
.btn-lg { padding: .875rem 1.5rem; font-size: 1rem; }

/* ===== Cards ===== */
.card {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}
.card-body { padding: 1.25rem; }
.card-hover { transition: transform .2s cubic-bezier(.2,.8,.3,1.2), box-shadow .2s, border-color .2s; }
.card-hover:hover {
    transform: translateY(-5px);
    box-shadow: var(--shadow-lg);
    border-color: var(--c-brand);
}

/* ===== Badges / pills ===== */
.badge {
    display: inline-flex; align-items: center;
    font-size: .75rem; font-weight: 700; letter-spacing: .02em;
    padding: .2rem .55rem;
    border-radius: var(--radius-pill);
    background: var(--c-surface-alt);
    color: var(--c-text-muted);
    text-transform: uppercase;
}
/* A saving is good news, so the sale badge is the accent rather than the old hot-rose
   gradient — which competed with the orange price directly beneath it. */
.badge-sale {
    background: var(--g-hot); color: var(--c-on-brand);
    box-shadow: 0 4px 12px -3px var(--c-brand-ring);
}
.badge-low  { background: var(--c-brand-soft); color: var(--c-brand-dark); }
.badge-stock { background: var(--c-brand-soft); color: var(--c-brand-dark); }
.badge-out  { background: var(--c-accent-soft); color: var(--c-accent); }
.badge-ends { background: var(--c-brass-soft); color: var(--c-brass); }

/* ===== Forms ===== */
.input, input[type=text], input[type=email], input[type=password], input[type=number], input[type=search],
select, textarea {
    font-family: inherit; font-size: 1rem;
    width: 100%;
    padding: .625rem .85rem;
    background: var(--c-surface);
    color: var(--c-text);
    border: 1px solid var(--c-border-strong);
    border-radius: var(--radius);
    transition: border-color .15s, box-shadow .15s;
}
.input:focus, input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--c-brand);
    box-shadow: 0 0 0 3px var(--c-brand-ring);
}
label.field { display: block; margin-bottom: 1rem; }
label.field > span { display: block; font-weight: 600; font-size: .9rem; margin-bottom: .35rem; color: var(--c-text); }

.valid.modified:not([type=checkbox]) { outline: none; border-color: var(--c-brand); }
.invalid { border-color: var(--c-accent); }
.validation-message { color: var(--c-accent); font-size: .85rem; margin-top: .25rem; }

/* ===== Tables ===== */
.table {
    width: 100%; border-collapse: collapse;
    background: var(--c-surface);
    border-radius: var(--radius-lg);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
    border: 1px solid var(--c-border);
}
.table th, .table td { padding: .85rem 1rem; text-align: left; border-bottom: 1px solid var(--c-border); }
.table th { background: var(--c-surface-alt); font-size: .8rem; text-transform: uppercase; letter-spacing: .05em; color: var(--c-text-muted); font-weight: 600; }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr.is-best { background: var(--c-brand-soft); }
.table tbody tr.is-best td { font-weight: 600; }

/* ===== Alerts ===== */
.alert { padding: .85rem 1rem; border-radius: var(--radius); border: 1px solid; }
.alert-success { background: var(--c-brand-soft); border-color: var(--c-brand); color: var(--c-brand-dark); }
.alert-error { background: var(--c-accent-soft); border-color: var(--c-accent); color: var(--c-accent); }

/* ===== Hero ===== */
/*  The hero used to be a purple gradient that animated its background position forever,
    with four fake sparkle dots and a floating lavender blob. Three separate tells of a
    template, two of them running animation frames on every visit for no information.

    What it is now: a ledger. Ruled lines on deep ink, one soft green glow where the
    headline sits, and nothing moving. The ruling is drawn with repeating-linear-gradient
    rather than an image, so it costs no request and scales with the box. */
.hero {
    position: relative;
    background: var(--g-hero);
    color: var(--c-on-ink);
    border-radius: 20px;
    padding: clamp(2.5rem, 5vw, 4.5rem) clamp(1.5rem, 4vw, 3.5rem);
    margin: 1.5rem 0 2.25rem;
    overflow: hidden;
    box-shadow: 0 24px 48px -16px rgba(6, 22, 18, .55);
}
.hero::before {
    content: ""; position: absolute; inset: 0;
    background-image:
        /* the glow, behind the headline */
        radial-gradient(720px circle at 18% 8%, rgba(76, 195, 138, .22) 0, transparent 55%),
        /* ruled lines, horizontal then vertical */
        repeating-linear-gradient(to bottom, rgba(255,255,255,.05) 0 1px, transparent 1px 34px),
        repeating-linear-gradient(to right, rgba(255,255,255,.035) 0 1px, transparent 1px 34px);
    pointer-events: none;
}
/*  A single hairline rule down the left, the way a ledger column is ruled off. Sits inside
    the padding so it reads as part of the page, not as a border on the box. */
.hero::after {
    content: "";
    position: absolute; left: clamp(.75rem, 2vw, 1.75rem); top: 0; bottom: 0;
    width: 2px;
    background: linear-gradient(to bottom, transparent, rgba(76, 195, 138, .55) 20%,
                                rgba(76, 195, 138, .55) 80%, transparent);
    pointer-events: none;
}
.hero h1 {
    color: #fff; max-width: 22ch;
    font-size: clamp(2.4rem, 1.2rem + 4vw, 4rem);
    font-weight: 800; letter-spacing: -0.03em; line-height: 1.05;
    margin-bottom: .75rem;
}
.hero h1 .grad {
    background: var(--g-text);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
}
.hero p { color: var(--c-on-ink-muted); max-width: 56ch; font-size: 1.15rem; }
.hero .hero-form { display: flex; gap: .6rem; max-width: 520px; margin-top: 1.75rem; position: relative; }
.hero .hero-form input {
    background: #fff; color: #16211f; border-color: transparent;
    padding: .8rem 1.1rem; border-radius: 12px; font-size: 1rem;
}
/*  This button was a lavender-to-pink gradient with near-black green text and an orange
    drop shadow — three unrelated hues on one control. It is the same primary button as
    everywhere else now, just sized for the hero. */
.hero .hero-form .btn-primary {
    border-radius: 12px;
    padding: .8rem 1.4rem; font-weight: 700; white-space: nowrap;
    box-shadow: 0 8px 24px -6px rgba(6, 22, 18, .5);
}
.hero .hero-form .btn-primary:hover { filter: brightness(1.08); }
.hero .hero-msg { margin-top: .85rem; color: #a7ecc9; font-size: .95rem; font-weight: 600; }
.hero .hero-msg.err { color: #ffc4bf; }
.hero-stats {
    display: flex; gap: 2.5rem; margin-top: 2.25rem; position: relative; flex-wrap: wrap;
}
.hero-stats .stat .num {
    display: block; font-size: 1.9rem; font-weight: 800; letter-spacing: -.02em;
    background: var(--g-text);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
}
.hero-stats .stat .lbl { color: var(--c-on-ink-subtle); font-size: .85rem; text-transform: uppercase; letter-spacing: .08em; }

/* ===== Product grid ===== */
.product-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 1.25rem;
}

.product-card { display: flex; flex-direction: column; }
.product-card .thumb {
    aspect-ratio: 1;
    background: radial-gradient(120% 100% at 50% 0%, var(--c-surface) 0%, var(--c-surface-alt) 100%);
    display: flex;
    align-items: center; justify-content: center; padding: 1rem;
    position: relative; overflow: hidden;
}
/* max-width/height:auto keep the image fluid despite its width/height attributes,
   which are there to reserve layout space and avoid CLS. */
.product-card .thumb img { max-width: 100%; height: auto; max-height: 100%; object-fit: contain; transition: transform .3s ease; }
.product-card:hover .thumb img { transform: scale(1.06); }
.product-card .thumb .badge { position: absolute; top: .75rem; left: .75rem; }
.product-card .body { padding: 1rem 1.25rem 1.25rem; flex: 1; display: flex; flex-direction: column; }
.product-card .brand { font-size: .75rem; text-transform: uppercase; letter-spacing: .05em; color: var(--c-text-muted); }
/* Amazon titles are SEO strings, not names — "Amazon Fire TV Stick 4K Plus (newest model)
   with AI-powered Fire TV Search, Wi-Fi 6, stream hundreds of thousands of movies and
   shows, free & live TV, find shows faster with Alexa+". Left unclamped, one card runs to
   six lines while its neighbour runs to two and the grid loses its baseline. Clamped for
   display only: the product page still shows the full title, which is what a shopper
   checking they have the right item actually needs. */
.product-card .title { font-size: 1rem; font-weight: 600; margin: .25rem 0 .75rem; line-height: 1.35;
    display: -webkit-box; -webkit-line-clamp: 3; line-clamp: 3; -webkit-box-orient: vertical;
    overflow: hidden; }
.product-card .title a { color: inherit; }
/* Amazon gives every colour and size its own ASIN, so one product legitimately occupies
   several catalogue rows. The listing pages show one card and say how many it stands for —
   without this the grid reads as duplicated rather than as one product in five colours. */
.product-card .variants { display: inline-block; margin: -.5rem 0 .6rem; font-size: .72rem;
    font-weight: 600; color: var(--c-text-muted); background: var(--c-surface-alt);
    border: 1px solid var(--c-border); border-radius: var(--radius-pill); padding: .1rem .5rem; }
.product-card .title a:hover { color: var(--c-brand); text-decoration: none; }
.product-card .price-row { display: flex; align-items: baseline; gap: .5rem; margin-top: auto; padding-top: .5rem; }
/*  The price carries its weight through type, not hue. It was orange (#f97316), which is
    2.80:1 on white — the least legible thing on the card was the number the card exists
    to show, and it failed AA even at large-text size. Ink puts it at 16.5:1 and leaves
    green free for the saving, which is the part a shopper is actually pleased about. */
.product-card .price { font-size: 1.45rem; font-weight: 800; color: var(--c-text); letter-spacing: -.025em; }
.product-card .was-price { font-size: .95rem; color: var(--c-text-subtle); text-decoration: line-through; }
.product-card .retailer { font-size: .85rem; color: var(--c-text-muted); }
.product-card .savings { margin: .3rem 0 0; font-size: .82rem; font-weight: 700; color: var(--c-brand); }
.product-card .cta { margin-top: 1rem; width: 100%; }

/* ===== Footer ===== */
/*  The footer keeps the ink ground in both themes — it is the same surface as the hero,
    which is what ties the top and bottom of the page together. In dark mode it sits a
    shade above the page rather than below it. */
.site-footer {
    margin-top: 4rem;
    padding: 2.5rem 0 2rem;
    background: var(--c-ink);
    color: var(--c-on-ink-muted);
}
.site-footer a { color: var(--c-on-ink-muted); }
.site-footer a:hover { color: var(--c-on-ink); }
.site-footer h4 { color: var(--c-on-ink); font-size: .9rem; text-transform: uppercase; letter-spacing: .05em; margin-bottom: .75rem; }
.footer-grid { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 2rem; margin-bottom: 2rem; }
.footer-brand { font-size: 1.25rem; font-weight: 700; color: var(--c-on-ink); margin-bottom: .5rem; }
.footer-tagline { color: var(--c-on-ink-subtle); font-size: .9rem; max-width: 32ch; }
.footer-bottom { border-top: 1px solid rgba(255,255,255,.1); padding-top: 1.25rem; font-size: .85rem; color: var(--c-on-ink-subtle); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 1rem; }
@media (max-width: 720px) {
    .footer-grid { grid-template-columns: 1fr 1fr; }
    .footer-grid > :first-child { grid-column: 1 / -1; }
}

/* ===== Section header ===== */
.section-head { display: flex; align-items: end; justify-content: space-between; gap: 1rem; margin: 2.5rem 0 1.15rem; }
.section-head h2 {
    margin: 0; font-size: 1.65rem; letter-spacing: -.02em;
    position: relative; padding-left: .9rem;
}
.section-head h2::before {
    content: ""; position: absolute; left: 0; top: .18em; bottom: .18em;
    width: 5px; border-radius: 3px; background: var(--g-brand);
}
.section-head .link { font-weight: 700; }

/* ===== Theme toggle =====

   Which glyph shows is decided in CSS from the root attribute, never by script writing
   into the button. That matters here because Blazor's enhanced navigation swaps the
   header's DOM on every page change: anything JS had written into the button would be
   thrown away on the first link click, while <html data-theme> survives untouched. */
.theme-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; padding: 0;
    border-radius: var(--radius-pill);
    border: 1px solid var(--c-border-strong);
    background: var(--c-surface);
    color: var(--c-text-muted);
    cursor: pointer;
    transition: color .15s, border-color .15s, background-color .15s;
}
.theme-toggle:hover { color: var(--c-brand); border-color: var(--c-brand); }
.theme-toggle:focus-visible { outline: 2px solid var(--c-brand); outline-offset: 2px; }
.theme-toggle svg { width: 18px; height: 18px; display: block; }

/* The button offers the theme you would get by pressing it, so on a light page it shows
   a moon. Default (no attribute, light system): offer dark. */
.theme-toggle .i-dark  { display: block; }
.theme-toggle .i-light { display: none; }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .theme-toggle .i-dark  { display: none; }
    :root:not([data-theme="light"]) .theme-toggle .i-light { display: block; }
}

/* After the media query on purpose: equal specificity, so source order is what lets an
   explicit choice beat the OS in both directions. */
:root[data-theme="dark"]  .theme-toggle .i-dark  { display: none; }
:root[data-theme="dark"]  .theme-toggle .i-light { display: block; }
:root[data-theme="light"] .theme-toggle .i-dark  { display: block; }
:root[data-theme="light"] .theme-toggle .i-light { display: none; }

/* ===== Motion preferences ===== */
@media (prefers-reduced-motion: reduce) {
    /* The hero's two infinite animations are gone entirely, so there is nothing left here
       to switch off — only the hover transitions, which still need it. */
    .card-hover, .product-card .thumb img { transition: none; }
    .card-hover:hover { transform: none; }
}

/* ===== Blazor error UI ===== */
#blazor-error-ui {
    background: var(--c-ink); color: var(--c-on-ink);
    bottom: 0; box-shadow: 0 -1px 2px rgba(0,0,0,0.2);
    display: none; left: 0; padding: 0.6rem 1.25rem 0.7rem 1.25rem; position: fixed;
    width: 100%; z-index: 1000;
}
#blazor-error-ui .dismiss { cursor: pointer; position: absolute; right: 0.75rem; top: 0.5rem; }
.blazor-error-boundary { background: #a3231f; padding: 1rem; color: #fff; border-radius: var(--radius); }
.blazor-error-boundary::after { content: "An error has occurred."; }

/* Price standing vs our own recorded history - see PriceVerdict. Absent until we
   hold enough observations for the claim to be true. */
.product-card .verdict { margin: .3rem 0 0; font-size: .78rem; font-weight: 700; }
.product-card .verdict::before { content: "\25CF"; margin-right: .35rem; font-size: .7em; vertical-align: .1em; }
/*  Four hardcoded hues became three tokens. "Good" used to be blue, which belonged to no
    other element on the site; both positive verdicts are the accent now and the words do
    the distinguishing, which is what they are there for. */
.verdict-best { color: var(--c-brand); }
.verdict-good { color: var(--c-brand); }
.verdict-neutral { color: var(--c-text-muted); }
.verdict-poor { color: var(--c-brass); }
